mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-10-12 02:22:55 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d72660ef04 | ||
|
|
4833fb3aa6 | ||
|
|
f437a54561 | ||
|
|
f05f84b6e5 | ||
|
|
871ebfdb70 | ||
|
|
d34619232f | ||
|
|
5168daf6ce | ||
|
|
95e476d5c9 | ||
|
|
cc8209d648 | ||
|
|
6ec6e86937 | ||
|
|
018908c2b1 | ||
|
|
9e69d6076d | ||
|
|
ad785ea0a2 | ||
|
|
b51f02c2ca | ||
|
|
ea3de16f24 | ||
|
|
f29c4e1e07 | ||
|
|
e8871b8a99 | ||
|
|
8b88bb82d3 | ||
|
|
30fba849e2 | ||
|
|
617c336813 | ||
|
|
89a5892dd9 | ||
|
|
af8a2afde1 | ||
|
|
ceaf387533 | ||
|
|
e5a1377c36 | ||
|
|
bb61b08c83 | ||
|
|
2d63441cc4 | ||
|
|
80f6460f72 | ||
|
|
f2c2864ab4 | ||
|
|
9eda11d081 | ||
|
|
54e93e53df | ||
|
|
f6e1f11711 | ||
|
|
0a21635e7f | ||
|
|
83aa1ac6a7 | ||
|
|
0aa15a72b0 | ||
|
|
fecd830622 | ||
|
|
32a4f6c32f | ||
|
|
9a47b4025b | ||
|
|
1979e7d75b | ||
|
|
95e6b6c0af | ||
|
|
50b8de00bb | ||
|
|
81289fa7cd | ||
|
|
576d81aa49 | ||
|
|
009a3c8391 | ||
|
|
65b0dbd4c4 | ||
|
|
5f411f73e7 | ||
|
|
dadb33bfdb | ||
|
|
8584c0b021 | ||
|
|
3f1a8e81b4 | ||
|
|
0e14647573 | ||
|
|
bfe8785ed5 | ||
|
|
412301bb18 | ||
|
|
fd4becf389 | ||
|
|
aa2682ec16 | ||
|
|
94ef433a37 | ||
|
|
15f6796b04 | ||
|
|
de63238897 | ||
|
|
1824e5b094 | ||
|
|
a42a7c88bd | ||
|
|
b5063fc25a |
@@ -63,6 +63,7 @@ Translations
|
||||
* [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)
|
||||
* [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-RUS.md)
|
||||
|
||||
@@ -192,6 +192,17 @@
|
||||
/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
|
||||
|
||||
# Reference: https://www.gracefulsecurity.com/path-traversal-cheat-sheet-linux
|
||||
|
||||
/etc/passwd
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
References:
|
||||
* https://en.wikipedia.org/wiki/Debian_version_history
|
||||
-->
|
||||
|
||||
<root>
|
||||
<regexp value="^([\d\.\-]+)[\-\_\ ].*">
|
||||
<info dbms_version="1"/>
|
||||
@@ -36,19 +41,27 @@
|
||||
</regexp>
|
||||
|
||||
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+wheezy">
|
||||
<info dbms_version="1" type="Linux" distrib="Debian" release="7.0" codename="wheezy"/>
|
||||
<info dbms_version="1" type="Linux" distrib="Debian" release="7" codename="wheezy"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+jessie">
|
||||
<info dbms_version="1" type="Linux" distrib="Debian" release="8.0" codename="jessie"/>
|
||||
<info dbms_version="1" type="Linux" distrib="Debian" release="8" codename="jessie"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+stretch">
|
||||
<info dbms_version="1" type="Linux" distrib="Debian" release="9.0" codename="stretch"/>
|
||||
<info dbms_version="1" type="Linux" distrib="Debian" release="9" codename="stretch"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+buster">
|
||||
<info dbms_version="1" type="Linux" distrib="Debian" release="10.0" codename="buster"/>
|
||||
<info dbms_version="1" type="Linux" distrib="Debian" release="10" codename="buster"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+bullseye">
|
||||
<info dbms_version="1" type="Linux" distrib="Debian" release="11" codename="bullseye"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+bookworm">
|
||||
<info dbms_version="1" type="Linux" distrib="Debian" release="12" codename="bookworm"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+(sid|unstable)">
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
# sqlmap
|
||||
|
||||
[](https://travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://badge.fury.io/py/sqlmap) [](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [](https://twitter.com/sqlmap)
|
||||
|
||||
sqlmap은 SQL 인젝션 결함 탐지 및 활용, 데이터베이스 서버 장악 프로세스를 자동화 하는 오픈소스 침투 테스팅 도구입니다. 최고의 침투 테스터, 데이터베이스 핑거프린팅 부터 데이터베이스 데이터 읽기, 대역 외 연결을 통한 기반 파일 시스템 접근 및 명령어 실행에 걸치는 광범위한 스위치들을 위한 강력한 탐지 엔진과 다수의 편리한 기능이 탑재되어 있습니다.
|
||||
|
||||
스크린샷
|
||||
----
|
||||
|
||||

|
||||
|
||||
또는, 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](http://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)을 참고하시길 권장드립니다.
|
||||
|
||||
링크
|
||||
----
|
||||
|
||||
* 홈페이지: http://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://twitter.com/sqlmap)
|
||||
* 시연 영상: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos)
|
||||
* 스크린샷: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
|
||||
+13
-4
@@ -15,11 +15,13 @@ BEEP_WAV_FILENAME = os.path.join(os.path.dirname(__file__), "beep.wav")
|
||||
|
||||
def beep():
|
||||
try:
|
||||
if sys.platform == "nt":
|
||||
if sys.platform.startswith("win"):
|
||||
_win_wav_play(BEEP_WAV_FILENAME)
|
||||
elif sys.platform == "darwin":
|
||||
elif sys.platform.startswith("darwin"):
|
||||
_mac_beep()
|
||||
elif sys.platform.startswith("linux"):
|
||||
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()
|
||||
@@ -34,6 +36,10 @@ def _speaker_beep():
|
||||
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_beep():
|
||||
import Carbon.Snd
|
||||
Carbon.Snd.SysBeep(1)
|
||||
@@ -57,7 +63,10 @@ def _linux_wav_play(filename):
|
||||
class struct_pa_sample_spec(ctypes.Structure):
|
||||
_fields_ = [("format", ctypes.c_int), ("rate", ctypes.c_uint32), ("channels", ctypes.c_uint8)]
|
||||
|
||||
pa = ctypes.cdll.LoadLibrary("libpulse-simple.so.0")
|
||||
try:
|
||||
pa = ctypes.cdll.LoadLibrary("libpulse-simple.so.0")
|
||||
except OSError:
|
||||
return
|
||||
|
||||
wave_file = wave.open(filename, "rb")
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
To use safe2bin.py you need to pass it the original file,
|
||||
and optionally the output file name.
|
||||
|
||||
Example:
|
||||
|
||||
$ python ./safe2bin.py -i output.txt -o output.txt.bin
|
||||
|
||||
This will create an binary decoded file output.txt.bin. For example,
|
||||
if the content of output.txt is: "\ttest\t\x32\x33\x34\nnewline" it will
|
||||
be decoded to: " test 234
|
||||
newline"
|
||||
|
||||
If you skip the output file name, general rule is that the binary
|
||||
file names are suffixed with the string '.bin'. So, that means that
|
||||
the upper example can also be written in the following form:
|
||||
|
||||
$ python ./safe2bin.py -i output.txt
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
|
||||
See the file 'LICENSE' for copying permission
|
||||
"""
|
||||
|
||||
pass
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#/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
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
export SQLMAP_DREI=1
|
||||
#for i in $(find . -iname "*.py" | grep -v __init__); do python3 -c 'import '`echo $i | cut -d '.' -f 2 | cut -d '/' -f 2- | sed 's/\//./g'`''; done
|
||||
for i in $(find . -iname "*.py" | grep -v __init__); do PYTHONWARNINGS=all python3.7 -m compileall $i; done
|
||||
for i in $(find . -iname "*.py" | grep -v __init__); do PYTHONWARNINGS=all python3.7 -m compileall $i | sed 's/Compiling/Checking/g'; done
|
||||
unset SQLMAP_DREI
|
||||
source `dirname "$0"`"/junk.sh"
|
||||
|
||||
|
||||
@@ -422,6 +422,15 @@ def start():
|
||||
if not checkConnection(suppressOutput=conf.forms) or not checkString() or not checkRegexp():
|
||||
continue
|
||||
|
||||
if conf.rParam and kb.originalPage:
|
||||
kb.randomPool = dict([_ for _ in kb.randomPool.items() if isinstance(_[1], list)])
|
||||
|
||||
for match in re.finditer(r"(?si)<select[^>]+\bname\s*=\s*[\"']([^\"']+)(.+?)</select>", kb.originalPage):
|
||||
name, _ = match.groups()
|
||||
options = tuple(re.findall(r"<option[^>]+\bvalue\s*=\s*[\"']([^\"']+)", _))
|
||||
if options:
|
||||
kb.randomPool[name] = options
|
||||
|
||||
checkWaf()
|
||||
|
||||
if conf.nullConnection:
|
||||
|
||||
+12
-8
@@ -5,7 +5,6 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
|
||||
See the file 'LICENSE' for copying permission
|
||||
"""
|
||||
|
||||
import base64
|
||||
import re
|
||||
|
||||
from lib.core.common import Backend
|
||||
@@ -27,6 +26,7 @@ from lib.core.common import unArrayizeValue
|
||||
from lib.core.common import urlencode
|
||||
from lib.core.common import zeroDepthSearch
|
||||
from lib.core.compat import xrange
|
||||
from lib.core.convert import encodeBase64
|
||||
from lib.core.convert import getUnicode
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
@@ -50,7 +50,9 @@ from lib.core.settings import PAYLOAD_DELIMITER
|
||||
from lib.core.settings import REPLACEMENT_MARKER
|
||||
from lib.core.settings import SINGLE_QUOTE_MARKER
|
||||
from lib.core.settings import SLEEP_TIME_MARKER
|
||||
from lib.core.settings import UNICODE_ENCODING
|
||||
from lib.core.unescaper import unescaper
|
||||
from thirdparty import six
|
||||
|
||||
class Agent(object):
|
||||
"""
|
||||
@@ -169,8 +171,8 @@ class Agent(object):
|
||||
|
||||
if re.sub(r" \(.+", "", parameter) in conf.base64Parameter:
|
||||
# TODO: support for POST_HINT
|
||||
newValue = base64.b64encode(newValue)
|
||||
origValue = base64.b64encode(origValue)
|
||||
newValue = encodeBase64(newValue, binary=False, encoding=conf.encoding or UNICODE_ENCODING)
|
||||
origValue = encodeBase64(origValue, binary=False, encoding=conf.encoding or UNICODE_ENCODING)
|
||||
|
||||
if place in (PLACE.URI, PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER):
|
||||
_ = "%s%s" % (origValue, kb.customInjectionMark)
|
||||
@@ -308,7 +310,7 @@ class Agent(object):
|
||||
return re.sub(r";\W*;", ";", expression) if trimEmpty else expression
|
||||
|
||||
def cleanupPayload(self, payload, origValue=None):
|
||||
if payload is None:
|
||||
if not isinstance(payload, six.string_types):
|
||||
return
|
||||
|
||||
replacements = {
|
||||
@@ -333,6 +335,7 @@ class Agent(object):
|
||||
|
||||
if origValue is not None:
|
||||
origValue = getUnicode(origValue)
|
||||
|
||||
if "[ORIGVALUE]" in payload:
|
||||
payload = getUnicode(payload).replace("[ORIGVALUE]", origValue if origValue.isdigit() else unescaper.escape("'%s'" % origValue))
|
||||
if "[ORIGINAL]" in payload:
|
||||
@@ -351,6 +354,7 @@ class Agent(object):
|
||||
inferenceQuery = inference.query
|
||||
|
||||
payload = payload.replace(INFERENCE_MARKER, inferenceQuery)
|
||||
|
||||
elif not kb.testMode:
|
||||
errMsg = "invalid usage of inference payload without "
|
||||
errMsg += "knowledge of underlying DBMS"
|
||||
@@ -393,7 +397,7 @@ class Agent(object):
|
||||
if "hex" in rootQuery:
|
||||
hexField = rootQuery.hex.query % field
|
||||
else:
|
||||
warnMsg = "switch '--hex' is currently not supported on DBMS %s" % Backend.getIdentifiedDbms()
|
||||
warnMsg = "switch '--hex' is currently not supported on DBMS '%s'" % Backend.getIdentifiedDbms()
|
||||
singleTimeWarnMessage(warnMsg)
|
||||
|
||||
return hexField
|
||||
@@ -651,7 +655,7 @@ class Agent(object):
|
||||
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1)
|
||||
_ = unArrayizeValue(zeroDepthSearch(concatenatedQuery, " FROM "))
|
||||
concatenatedQuery = "%s||'%s'%s" % (concatenatedQuery[:_], kb.chars.stop, concatenatedQuery[_:])
|
||||
concatenatedQuery = re.sub(r"('%s'\|\|)(.+)(%s)" % (kb.chars.start, re.escape(castedFields)), r"\g<2>\g<1>\g<3>", concatenatedQuery)
|
||||
concatenatedQuery = re.sub(r"('%s'\|\|)(.+?)(%s)" % (kb.chars.start, re.escape(castedFields)), r"\g<2>\g<1>\g<3>", concatenatedQuery)
|
||||
elif fieldsSelect:
|
||||
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1)
|
||||
concatenatedQuery += "||'%s'" % kb.chars.stop
|
||||
@@ -1007,7 +1011,7 @@ class Agent(object):
|
||||
limitedQuery = "%s WHERE %s " % (limitedQuery, self.nullAndCastField(uniqueField or field))
|
||||
|
||||
limitedQuery += "NOT IN (%s" % (limitStr % num)
|
||||
limitedQuery += "%s %s ORDER BY %s) ORDER BY %s" % (self.nullAndCastField(uniqueField or field), fromFrom, uniqueField or "1", uniqueField or "1")
|
||||
limitedQuery += "%s %s ORDER BY %s) ORDER BY %s" % (self.nullAndCastField(uniqueField or field), fromFrom, uniqueField or '1', uniqueField or '1')
|
||||
else:
|
||||
match = re.search(r" ORDER BY (\w+)\Z", query)
|
||||
field = match.group(1) if match else field
|
||||
@@ -1081,7 +1085,7 @@ class Agent(object):
|
||||
Removes payload delimiters from inside the input string
|
||||
"""
|
||||
|
||||
return value.replace(PAYLOAD_DELIMITER, '') if value else value
|
||||
return value.replace(PAYLOAD_DELIMITER, "") if value else value
|
||||
|
||||
def extractPayload(self, value):
|
||||
"""
|
||||
|
||||
+28
-22
@@ -46,7 +46,6 @@ from xml.sax import SAXParseException
|
||||
|
||||
from extra.beep.beep import beep
|
||||
from extra.cloak.cloak import decloak
|
||||
from extra.safe2bin.safe2bin import safecharencode
|
||||
from lib.core.bigarray import BigArray
|
||||
from lib.core.compat import cmp
|
||||
from lib.core.compat import round
|
||||
@@ -180,6 +179,7 @@ from lib.core.settings import VERSION_STRING
|
||||
from lib.core.settings import ZIP_HEADER
|
||||
from lib.core.settings import WEBSCARAB_SPLITTER
|
||||
from lib.core.threads import getCurrentThreadData
|
||||
from lib.utils.safe2bin import safecharencode
|
||||
from lib.utils.sqlalchemy import _sqlalchemy
|
||||
from thirdparty import six
|
||||
from thirdparty.clientform.clientform import ParseResponse
|
||||
@@ -623,8 +623,8 @@ def paramToDict(place, parameters=None):
|
||||
if parameter in (conf.base64Parameter or []):
|
||||
try:
|
||||
oldValue = value
|
||||
value = decodeBase64(value, binary=False)
|
||||
parameters = re.sub(r"\b%s\b" % re.escape(oldValue), value, parameters)
|
||||
value = decodeBase64(value, binary=False, encoding=conf.encoding or UNICODE_ENCODING)
|
||||
parameters = re.sub(r"\b%s(\b|\Z)" % re.escape(oldValue), value, parameters)
|
||||
except:
|
||||
errMsg = "parameter '%s' does not contain " % parameter
|
||||
errMsg += "valid Base64 encoded value ('%s')" % value
|
||||
@@ -701,7 +701,7 @@ def paramToDict(place, parameters=None):
|
||||
message += "has boundaries. Do you want to inject inside? ('%s') [y/N] " % getUnicode(_)
|
||||
|
||||
if readInput(message, default='N', boolean=True):
|
||||
testableParameters[parameter] = re.sub(r"\b(%s\s*=\s*)%s" % (re.escape(parameter), re.escape(testableParameters[parameter])), (r"\g<1>%s" % re.sub(regex, r"\g<1>%s\g<2>" % BOUNDED_INJECTION_MARKER, testableParameters[parameter])).replace("\\", r"\\"), parameters)
|
||||
testableParameters[parameter] = re.sub(r"\b(%s\s*=\s*)%s" % (re.escape(parameter), re.escape(testableParameters[parameter])), (r"\g<1>%s" % re.sub(regex, r"\g<1>%s\g<2>" % BOUNDED_INJECTION_MARKER, testableParameters[parameter].replace("\\", r"\\"))), parameters)
|
||||
break
|
||||
|
||||
if conf.testParameter:
|
||||
@@ -1285,36 +1285,43 @@ def banner():
|
||||
"""
|
||||
|
||||
if not any(_ in sys.argv for _ in ("--version", "--api")) and not conf.get("disableBanner"):
|
||||
_ = BANNER
|
||||
result = BANNER
|
||||
|
||||
if not IS_TTY or "--disable-coloring" in sys.argv:
|
||||
_ = clearColors(_)
|
||||
result = clearColors(result)
|
||||
elif IS_WIN:
|
||||
coloramainit()
|
||||
|
||||
dataToStdout(_, forceOutput=True)
|
||||
dataToStdout(result, forceOutput=True)
|
||||
|
||||
def parsePasswordHash(password):
|
||||
"""
|
||||
In case of Microsoft SQL Server password hash value is expanded to its components
|
||||
|
||||
>>> pushValue(kb.forcedDbms)
|
||||
>>> kb.forcedDbms = DBMS.MSSQL
|
||||
>>> "salt: 4086ceb6" in parsePasswordHash("0x01004086ceb60c90646a8ab9889fe3ed8e5c150b5460ece8425a")
|
||||
True
|
||||
>>> kb.forcedDbms = popValue()
|
||||
"""
|
||||
|
||||
blank = " " * 8
|
||||
|
||||
if not password or password == " ":
|
||||
password = NULL
|
||||
if isNoneValue(password) or password == " ":
|
||||
retVal = NULL
|
||||
else:
|
||||
retVal = password
|
||||
|
||||
if Backend.isDbms(DBMS.MSSQL) and password != NULL and isHexEncodedString(password):
|
||||
hexPassword = password
|
||||
password = "%s\n" % hexPassword
|
||||
password += "%sheader: %s\n" % (blank, hexPassword[:6])
|
||||
password += "%ssalt: %s\n" % (blank, hexPassword[6:14])
|
||||
password += "%smixedcase: %s\n" % (blank, hexPassword[14:54])
|
||||
if Backend.isDbms(DBMS.MSSQL) and retVal != NULL and isHexEncodedString(password):
|
||||
retVal = "%s\n" % password
|
||||
retVal += "%sheader: %s\n" % (blank, password[:6])
|
||||
retVal += "%ssalt: %s\n" % (blank, password[6:14])
|
||||
retVal += "%smixedcase: %s\n" % (blank, password[14:54])
|
||||
|
||||
if not Backend.isVersionWithin(("2005", "2008")):
|
||||
password += "%suppercase: %s" % (blank, hexPassword[54:])
|
||||
if password[54:]:
|
||||
retVal += "%suppercase: %s" % (blank, password[54:])
|
||||
|
||||
return password
|
||||
return retVal
|
||||
|
||||
def cleanQuery(query):
|
||||
"""
|
||||
@@ -3575,7 +3582,7 @@ def decodeIntToUnicode(value):
|
||||
# Note: https://github.com/sqlmapproject/sqlmap/issues/1531
|
||||
retVal = getUnicode(raw, conf.encoding or UNICODE_ENCODING)
|
||||
elif Backend.isDbms(DBMS.MSSQL):
|
||||
retVal = getUnicode(raw, "UTF-16-BE")
|
||||
retVal = getUnicode(raw, "UTF-16-BE") # References: https://docs.microsoft.com/en-us/sql/relational-databases/collations/collation-and-unicode-support?view=sql-server-2017 and https://stackoverflow.com/a/14488478
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE):
|
||||
retVal = _unichr(value)
|
||||
else:
|
||||
@@ -3662,7 +3669,7 @@ def getLatestRevision():
|
||||
"""
|
||||
|
||||
retVal = None
|
||||
req = _urllib.request.Request(url="https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/lib/core/settings.py")
|
||||
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())
|
||||
@@ -3794,7 +3801,7 @@ def maskSensitiveData(msg):
|
||||
retVal = retVal.replace(value, '*' * len(value))
|
||||
|
||||
# Just in case (for problematic parameters regarding user encoding)
|
||||
for match in re.finditer(r"(?i)[ -]-(u|url|data|cookie|auth-\w+|proxy)( |=)(.*?)(?= -?-[a-z]|\Z)", retVal):
|
||||
for match in re.finditer(r"(?i)[ -]-(u|url|data|cookie|auth-\w+|proxy|host|referer|headers?|H)( |=)(.*?)(?= -?-[a-z]|\Z)", retVal):
|
||||
retVal = retVal.replace(match.group(3), '*' * len(match.group(3)))
|
||||
|
||||
# Fail-safe substitutions
|
||||
@@ -4881,7 +4888,6 @@ def zeroDepthSearch(expression, value):
|
||||
elif expression[index] == ')':
|
||||
depth -= 1
|
||||
elif depth == 0:
|
||||
found = False
|
||||
if value.startswith('[') and value.endswith(']'):
|
||||
if re.search(value, expression[index:index + 1]):
|
||||
retVal.append(index)
|
||||
|
||||
+2
-2
@@ -13,6 +13,7 @@ import math
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
import time
|
||||
import uuid
|
||||
|
||||
class WichmannHill(random.Random):
|
||||
@@ -40,7 +41,6 @@ class WichmannHill(random.Random):
|
||||
try:
|
||||
a = int(binascii.hexlify(os.urandom(16)), 16)
|
||||
except NotImplementedError:
|
||||
import time
|
||||
a = int(time.time() * 256) # use fractional seconds
|
||||
|
||||
if not isinstance(a, int):
|
||||
@@ -132,7 +132,6 @@ class WichmannHill(random.Random):
|
||||
raise ValueError('seeds must be in range(0, 256)')
|
||||
if 0 == x == y == z:
|
||||
# Initialize from current time
|
||||
import time
|
||||
t = int(time.time() * 256)
|
||||
t = int((t & 0xffffff) ^ (t >> 24))
|
||||
t, x = divmod(t, 256)
|
||||
@@ -204,6 +203,7 @@ def round(x, d=0):
|
||||
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):
|
||||
|
||||
+7
-7
@@ -184,7 +184,7 @@ def encodeHex(value, binary=True):
|
||||
|
||||
return retVal
|
||||
|
||||
def decodeBase64(value, binary=True):
|
||||
def decodeBase64(value, binary=True, encoding=None):
|
||||
"""
|
||||
Returns a decoded representation of provided Base64 value
|
||||
|
||||
@@ -197,11 +197,11 @@ def decodeBase64(value, binary=True):
|
||||
retVal = base64.b64decode(value)
|
||||
|
||||
if not binary:
|
||||
retVal = getText(retVal)
|
||||
retVal = getText(retVal, encoding)
|
||||
|
||||
return retVal
|
||||
|
||||
def encodeBase64(value, binary=True):
|
||||
def encodeBase64(value, binary=True, encoding=None):
|
||||
"""
|
||||
Returns a decoded representation of provided Base64 value
|
||||
|
||||
@@ -212,12 +212,12 @@ def encodeBase64(value, binary=True):
|
||||
"""
|
||||
|
||||
if isinstance(value, six.text_type):
|
||||
value = value.encode(UNICODE_ENCODING)
|
||||
value = value.encode(encoding or UNICODE_ENCODING)
|
||||
|
||||
retVal = base64.b64encode(value)
|
||||
|
||||
if not binary:
|
||||
retVal = getText(retVal)
|
||||
retVal = getText(retVal, encoding)
|
||||
|
||||
return retVal
|
||||
|
||||
@@ -305,7 +305,7 @@ def getUnicode(value, encoding=None, noneToNull=False):
|
||||
except UnicodeDecodeError:
|
||||
return six.text_type(str(value), errors="ignore") # encoding ignored for non-basestring instances
|
||||
|
||||
def getText(value):
|
||||
def getText(value, encoding=None):
|
||||
"""
|
||||
Returns textual value of a given value (Note: not necessary Unicode on Python2)
|
||||
|
||||
@@ -318,7 +318,7 @@ def getText(value):
|
||||
retVal = value
|
||||
|
||||
if isinstance(value, six.binary_type):
|
||||
retVal = getUnicode(value)
|
||||
retVal = getUnicode(value, encoding)
|
||||
|
||||
if six.PY2:
|
||||
try:
|
||||
|
||||
@@ -85,7 +85,7 @@ def lockedmethod(f):
|
||||
@functools.wraps(f)
|
||||
def _(*args, **kwargs):
|
||||
if f not in _method_locks:
|
||||
_method_locks[f] = threading.Lock()
|
||||
_method_locks[f] = threading.RLock()
|
||||
|
||||
with _method_locks[f]:
|
||||
result = f(*args, **kwargs)
|
||||
|
||||
@@ -20,6 +20,7 @@ _defaults = {
|
||||
"level": 1,
|
||||
"risk": 1,
|
||||
"dumpFormat": "CSV",
|
||||
"tablePrefix": "sqlmap",
|
||||
"technique": "BEUSTQ",
|
||||
"torType": "SOCKS5",
|
||||
}
|
||||
|
||||
+14
-14
@@ -13,7 +13,6 @@ import shutil
|
||||
import tempfile
|
||||
import threading
|
||||
|
||||
from extra.safe2bin.safe2bin import safechardecode
|
||||
from lib.core.common import Backend
|
||||
from lib.core.common import checkFile
|
||||
from lib.core.common import dataToDumpFile
|
||||
@@ -53,6 +52,7 @@ 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
|
||||
|
||||
@@ -676,28 +676,28 @@ class Dump(object):
|
||||
else:
|
||||
colConsiderStr = " '%s' was" % unsafeSQLIdentificatorNaming(column)
|
||||
|
||||
msg = "column%s found in the " % colConsiderStr
|
||||
msg += "following databases:"
|
||||
self._write(msg)
|
||||
|
||||
_ = {}
|
||||
|
||||
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 _:
|
||||
if tbl in _[db]:
|
||||
_[db][tbl][col] = dataType
|
||||
if db in found:
|
||||
if tbl in found[db]:
|
||||
found[db][tbl][col] = dataType
|
||||
else:
|
||||
_[db][tbl] = {col: dataType}
|
||||
found[db][tbl] = {col: dataType}
|
||||
else:
|
||||
_[db] = {}
|
||||
_[db][tbl] = {col: dataType}
|
||||
found[db] = {}
|
||||
found[db][tbl] = {col: dataType}
|
||||
|
||||
continue
|
||||
|
||||
self.dbTableColumns(_)
|
||||
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)
|
||||
|
||||
+6
-6
@@ -130,12 +130,12 @@ class HASH(object):
|
||||
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[0-9a-f]{32}\Z'
|
||||
SHA1_GENERIC = r'(?i)\A[0-9a-f]{40}\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[0-9a-f]{64}\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[0-9a-f]{128}\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'
|
||||
WORDPRESS = r'\A\$P\$[./0-9a-zA-Z]{31}\Z'
|
||||
@@ -244,8 +244,8 @@ class HASHDB_KEYS(object):
|
||||
OS = "OS"
|
||||
|
||||
class REDIRECTION(object):
|
||||
YES = "Y"
|
||||
NO = "N"
|
||||
YES = 'Y'
|
||||
NO = 'N'
|
||||
|
||||
class PAYLOAD(object):
|
||||
SQLINJECTION = {
|
||||
|
||||
+25
-5
@@ -341,7 +341,8 @@ def _setCrawler():
|
||||
if conf.bulkFile:
|
||||
targets = getFileItems(conf.bulkFile)
|
||||
else:
|
||||
targets = parseSitemap(conf.sitemapUrl)
|
||||
targets = list(parseSitemap(conf.sitemapUrl))
|
||||
|
||||
for i in xrange(len(targets)):
|
||||
try:
|
||||
target = targets[i]
|
||||
@@ -473,10 +474,13 @@ def _findPageForms():
|
||||
if conf.bulkFile:
|
||||
targets = getFileItems(conf.bulkFile)
|
||||
elif conf.sitemapUrl:
|
||||
targets = parseSitemap(conf.sitemapUrl)
|
||||
targets = list(parseSitemap(conf.sitemapUrl))
|
||||
elif conf.googleDork:
|
||||
targets = [_[0] for _ in kb.targets]
|
||||
kb.targets.clear()
|
||||
else:
|
||||
targets = []
|
||||
|
||||
for i in xrange(len(targets)):
|
||||
try:
|
||||
target = targets[i]
|
||||
@@ -1273,8 +1277,8 @@ def _setHTTPAuthentication():
|
||||
from ntlm import HTTPNtlmAuthHandler
|
||||
except ImportError:
|
||||
errMsg = "sqlmap requires Python NTLM third-party library "
|
||||
errMsg += "in order to authenticate via NTLM, "
|
||||
errMsg += "https://github.com/mullender/python-ntlm"
|
||||
errMsg += "in order to authenticate via NTLM. Download from "
|
||||
errMsg += "'https://github.com/mullender/python-ntlm'"
|
||||
raise SqlmapMissingDependence(errMsg)
|
||||
|
||||
authHandler = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(kb.passwordMgr)
|
||||
@@ -1302,6 +1306,9 @@ def _setHTTPExtraHeaders():
|
||||
|
||||
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)
|
||||
@@ -1905,6 +1912,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
||||
kb.forceWhere = None
|
||||
kb.futileUnion = None
|
||||
kb.heavilyDynamic = False
|
||||
kb.headersFile = None
|
||||
kb.headersFp = {}
|
||||
kb.heuristicDbms = None
|
||||
kb.heuristicExtendedDbms = None
|
||||
@@ -1925,12 +1933,13 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
||||
kb.lastParserStatus = None
|
||||
|
||||
kb.locks = AttribDict()
|
||||
for _ in ("cache", "connError", "count", "handlers", "index", "io", "limit", "log", "socket", "redirect", "request", "value"):
|
||||
for _ in ("cache", "connError", "count", "handlers", "hint", "index", "io", "limit", "log", "socket", "redirect", "request", "value"):
|
||||
kb.locks[_] = threading.Lock()
|
||||
|
||||
kb.matchRatio = None
|
||||
kb.maxConnectionsFlag = False
|
||||
kb.mergeCookies = None
|
||||
kb.multipleCtrlC = False
|
||||
kb.negativeLogic = False
|
||||
kb.nullConnection = None
|
||||
kb.oldMsf = None
|
||||
@@ -2442,6 +2451,13 @@ def _basicOptionValidation():
|
||||
errMsg = "invalid regular expression '%s' ('%s')" % (conf.regexp, getSafeExString(ex))
|
||||
raise SqlmapSyntaxException(errMsg)
|
||||
|
||||
if conf.paramExclude:
|
||||
try:
|
||||
re.compile(conf.paramExclude)
|
||||
except Exception as ex:
|
||||
errMsg = "invalid regular expression '%s' ('%s')" % (conf.paramExclude, getSafeExString(ex))
|
||||
raise SqlmapSyntaxException(errMsg)
|
||||
|
||||
if conf.crawlExclude:
|
||||
try:
|
||||
re.compile(conf.crawlExclude)
|
||||
@@ -2485,6 +2501,10 @@ def _basicOptionValidation():
|
||||
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.csrfToken and conf.threads > 1:
|
||||
errMsg = "option '--csrf-url' is incompatible with option '--threads'"
|
||||
raise SqlmapSyntaxException(errMsg)
|
||||
|
||||
@@ -31,6 +31,7 @@ optDict = {
|
||||
"loadCookies": "string",
|
||||
"dropSetCookie": "boolean",
|
||||
"agent": "string",
|
||||
"mobile": "boolean",
|
||||
"randomAgent": "boolean",
|
||||
"host": "string",
|
||||
"referer": "string",
|
||||
@@ -60,6 +61,7 @@ optDict = {
|
||||
"skipUrlEncode": "boolean",
|
||||
"csrfToken": "string",
|
||||
"csrfUrl": "string",
|
||||
"csrfMethod": "string",
|
||||
"forceSSL": "boolean",
|
||||
"chunked": "boolean",
|
||||
"hpp": "boolean",
|
||||
@@ -100,6 +102,7 @@ optDict = {
|
||||
"notString": "string",
|
||||
"regexp": "string",
|
||||
"code": "integer",
|
||||
"smart": "boolean",
|
||||
"textOnly": "boolean",
|
||||
"titles": "boolean",
|
||||
},
|
||||
@@ -197,10 +200,12 @@ optDict = {
|
||||
|
||||
"General": {
|
||||
"trafficFile": "string",
|
||||
"answers": "string",
|
||||
"batch": "boolean",
|
||||
"binaryFields": "string",
|
||||
"charset": "string",
|
||||
"checkInternet": "boolean",
|
||||
"cleanup": "boolean",
|
||||
"crawlDepth": "integer",
|
||||
"crawlExclude": "string",
|
||||
"csvDel": "string",
|
||||
@@ -210,6 +215,7 @@ optDict = {
|
||||
"flushSession": "boolean",
|
||||
"forms": "boolean",
|
||||
"freshQueries": "boolean",
|
||||
"googlePage": "integer",
|
||||
"harFile": "string",
|
||||
"hexConvert": "boolean",
|
||||
"outputDir": "string",
|
||||
@@ -218,28 +224,23 @@ optDict = {
|
||||
"repair": "boolean",
|
||||
"saveConfig": "string",
|
||||
"scope": "string",
|
||||
"skipWaf": "boolean",
|
||||
"testFilter": "string",
|
||||
"testSkip": "string",
|
||||
"updateAll": "boolean",
|
||||
"webRoot": "string",
|
||||
},
|
||||
|
||||
"Miscellaneous": {
|
||||
"alert": "string",
|
||||
"answers": "string",
|
||||
"beep": "boolean",
|
||||
"cleanup": "boolean",
|
||||
"dependencies": "boolean",
|
||||
"disableColoring": "boolean",
|
||||
"googlePage": "integer",
|
||||
"listTampers": "boolean",
|
||||
"mobile": "boolean",
|
||||
"offline": "boolean",
|
||||
"purge": "boolean",
|
||||
"skipWaf": "boolean",
|
||||
"smart": "boolean",
|
||||
"tmpDir": "string",
|
||||
"webRoot": "string",
|
||||
"wizard": "boolean",
|
||||
"updateAll": "boolean",
|
||||
"verbose": "integer",
|
||||
},
|
||||
|
||||
|
||||
@@ -7,13 +7,13 @@ See the file 'LICENSE' for copying permission
|
||||
|
||||
import sqlite3
|
||||
|
||||
from extra.safe2bin.safe2bin import safechardecode
|
||||
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):
|
||||
"""
|
||||
|
||||
@@ -18,7 +18,7 @@ from lib.core.enums import OS
|
||||
from thirdparty.six import unichr as _unichr
|
||||
|
||||
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
||||
VERSION = "1.3.8.0"
|
||||
VERSION = "1.3.10.0"
|
||||
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)
|
||||
@@ -240,7 +240,7 @@ IS_WIN = PLATFORM == "nt"
|
||||
IS_TTY = os.isatty(sys.stdout.fileno())
|
||||
|
||||
# DBMS system databases
|
||||
MSSQL_SYSTEM_DBS = ("Northwind", "master", "model", "msdb", "pubs", "tempdb")
|
||||
MSSQL_SYSTEM_DBS = ("Northwind", "master", "model", "msdb", "pubs", "tempdb", "Resource", "ReportServer", "ReportServerTempDB")
|
||||
MYSQL_SYSTEM_DBS = ("information_schema", "mysql", "performance_schema", "sys")
|
||||
PGSQL_SYSTEM_DBS = ("information_schema", "pg_catalog", "pg_toast", "pgagent")
|
||||
ORACLE_SYSTEM_DBS = ('ANONYMOUS', 'APEX_030200', 'APEX_PUBLIC_USER', 'APPQOSSYS', 'BI', 'CTXSYS', 'DBSNMP', 'DIP', 'EXFSYS', 'FLOWS_%', 'FLOWS_FILES', 'HR', 'IX', 'LBACSYS', 'MDDATA', 'MDSYS', 'MGMT_VIEW', 'OC', 'OE', 'OLAPSYS', 'ORACLE_OCM', 'ORDDATA', 'ORDPLUGINS', 'ORDSYS', 'OUTLN', 'OWBSYS', 'PM', 'SCOTT', 'SH', 'SI_INFORMTN_SCHEMA', 'SPATIAL_CSW_ADMIN_USR', 'SPATIAL_WFS_ADMIN_USR', 'SYS', 'SYSMAN', 'SYSTEM', 'WKPROXY', 'WKSYS', 'WK_TEST', 'WMSYS', 'XDB', 'XS$NULL')
|
||||
@@ -251,7 +251,7 @@ MAXDB_SYSTEM_DBS = ("SYSINFO", "DOMAIN")
|
||||
SYBASE_SYSTEM_DBS = ("master", "model", "sybsystemdb", "sybsystemprocs")
|
||||
DB2_SYSTEM_DBS = ("NULLID", "SQLJ", "SYSCAT", "SYSFUN", "SYSIBM", "SYSIBMADM", "SYSIBMINTERNAL", "SYSIBMTS", "SYSPROC", "SYSPUBLIC", "SYSSTAT", "SYSTOOLS")
|
||||
HSQLDB_SYSTEM_DBS = ("INFORMATION_SCHEMA", "SYSTEM_LOB")
|
||||
H2_SYSTEM_DBS = ("INFORMATION_SCHEMA")
|
||||
H2_SYSTEM_DBS = ("INFORMATION_SCHEMA",)
|
||||
INFORMIX_SYSTEM_DBS = ("sysmaster", "sysutils", "sysuser", "sysadmin")
|
||||
|
||||
MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms")
|
||||
@@ -333,6 +333,9 @@ BLANK = "<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"
|
||||
|
||||
@@ -540,7 +543,7 @@ BRUTE_TABLE_EXISTS_TEMPLATE = "EXISTS(SELECT %d FROM %s)"
|
||||
BRUTE_COLUMN_EXISTS_TEMPLATE = "EXISTS(SELECT %s FROM %s)"
|
||||
|
||||
# Data inside shellcodeexec to be filled with random string
|
||||
SHELLCODEEXEC_RANDOM_STRING_MARKER = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
SHELLCODEEXEC_RANDOM_STRING_MARKER = b"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
|
||||
# Period after last-update to start nagging about the old revision
|
||||
LAST_UPDATE_NAGGING_DAYS = 60
|
||||
@@ -807,9 +810,6 @@ BRUTE_DOC_ROOT_PREFIXES = {
|
||||
OS.WINDOWS: ("/xampp", "/Program Files/xampp", "/wamp", "/Program Files/wampp", "/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%")
|
||||
}
|
||||
|
||||
# Table prefix to use in "takeover" functionalities (i.e. auxiliary tables used by sqlmap at the vulnerable DBMS)
|
||||
TAKEOVER_TABLE_PREFIX = "sqlmap"
|
||||
|
||||
# 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")
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ 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:
|
||||
@@ -192,6 +193,8 @@ def send_all(p, data):
|
||||
if not data:
|
||||
return
|
||||
|
||||
data = getBytes(data)
|
||||
|
||||
while len(data):
|
||||
sent = p.send(data)
|
||||
if not isinstance(sent, int):
|
||||
|
||||
+9
-8
@@ -125,8 +125,8 @@ def _setRequestParams():
|
||||
return retVal
|
||||
|
||||
if kb.processUserMarks is None and kb.customInjectionMark in conf.data:
|
||||
message = "custom injection marker ('%s') found in option " % kb.customInjectionMark
|
||||
message += "'--data'. Do you want to process it? [Y/n/q] "
|
||||
message = "custom injection marker ('%s') found in POST " % kb.customInjectionMark
|
||||
message += "body. Do you want to process it? [Y/n/q] "
|
||||
choice = readInput(message, default='Y').upper()
|
||||
|
||||
if choice == 'Q':
|
||||
@@ -151,12 +151,13 @@ def _setRequestParams():
|
||||
conf.data = re.sub(r'("(?P<name>[^"]+)"\s*:\s*".+?)"(?<!\\")', functools.partial(process, repl=r'\g<1>%s"' % kb.customInjectionMark), conf.data)
|
||||
conf.data = re.sub(r'("(?P<name>[^"]+)"\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<name>[^"]+)"\s*:\s*)((true|false|null))\b', functools.partial(process, repl=r'\g<1>\g<3>%s' % kb.customInjectionMark), conf.data)
|
||||
match = re.search(r'(?P<name>[^"]+)"\s*:\s*\[([^\]]+)\]', conf.data)
|
||||
if match and not (conf.testParameter and match.group("name") not in conf.testParameter):
|
||||
_ = match.group(2)
|
||||
_ = 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), _))
|
||||
for match in re.finditer(r'(?P<name>[^"]+)"\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), _))
|
||||
|
||||
kb.postHint = POST_HINT.JSON
|
||||
|
||||
|
||||
+12
-8
@@ -97,11 +97,11 @@ def exceptionHandledFunction(threadFunction, silent=False):
|
||||
except Exception as ex:
|
||||
from lib.core.common import getSafeExString
|
||||
|
||||
if not silent and kb.get("threadContinue"):
|
||||
if not silent and kb.get("threadContinue") and not isinstance(ex, SqlmapUserQuitException):
|
||||
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, (SqlmapUserQuitException, SqlmapConnectionException)):
|
||||
if conf.get("verbose") > 1 and not isinstance(ex, SqlmapConnectionException):
|
||||
traceback.print_exc()
|
||||
|
||||
def setDaemon(thread):
|
||||
@@ -114,6 +114,7 @@ def setDaemon(thread):
|
||||
def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardException=True, threadChoice=False, startThreadMsg=True):
|
||||
threads = []
|
||||
|
||||
kb.multipleCtrlC = False
|
||||
kb.threadContinue = True
|
||||
kb.threadException = False
|
||||
kb.technique = ThreadData.technique
|
||||
@@ -185,6 +186,7 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
|
||||
pass
|
||||
|
||||
except KeyboardInterrupt:
|
||||
kb.multipleCtrlC = True
|
||||
raise SqlmapThreadException("user aborted (Ctrl+C was pressed multiple times)")
|
||||
|
||||
if forwardException:
|
||||
@@ -199,13 +201,15 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
|
||||
traceback.print_exc()
|
||||
|
||||
except:
|
||||
from lib.core.common import unhandledExceptionMessage
|
||||
|
||||
print()
|
||||
kb.threadException = True
|
||||
errMsg = unhandledExceptionMessage()
|
||||
logger.error("thread %s: %s" % (threading.currentThread().getName(), errMsg))
|
||||
traceback.print_exc()
|
||||
|
||||
if not kb.multipleCtrlC:
|
||||
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.threadContinue = True
|
||||
|
||||
@@ -105,6 +105,7 @@ def update():
|
||||
|
||||
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)
|
||||
|
||||
@@ -42,7 +42,7 @@ class Wordlist(six.Iterator):
|
||||
def adjust(self):
|
||||
self.closeFP()
|
||||
if self.index > len(self.filenames):
|
||||
raise StopIteration
|
||||
return # Note: https://stackoverflow.com/a/30217723 (PEP 479)
|
||||
elif self.index == len(self.filenames):
|
||||
self.iter = iter(self.custom)
|
||||
else:
|
||||
|
||||
+58
-34
@@ -44,6 +44,26 @@ finally:
|
||||
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
|
||||
@@ -152,6 +172,9 @@ def cmdLineParser(argv=None):
|
||||
request.add_argument("--user-agent", dest="agent",
|
||||
help="HTTP User-Agent header value")
|
||||
|
||||
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")
|
||||
|
||||
@@ -242,6 +265,9 @@ def cmdLineParser(argv=None):
|
||||
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("--force-ssl", dest="forceSSL", action="store_true",
|
||||
help="Force usage of SSL/HTTPS")
|
||||
|
||||
@@ -344,6 +370,9 @@ def cmdLineParser(argv=None):
|
||||
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")
|
||||
|
||||
@@ -585,6 +614,9 @@ def cmdLineParser(argv=None):
|
||||
general.add_argument("-t", dest="trafficFile",
|
||||
help="Log all HTTP traffic into a textual file")
|
||||
|
||||
general.add_argument("--answers", dest="answers",
|
||||
help="Set predefined answers (e.g. \"quit=N,follow=N\")")
|
||||
|
||||
general.add_argument("--batch", dest="batch", action="store_true",
|
||||
help="Never ask for user input, use the default behavior")
|
||||
|
||||
@@ -594,6 +626,9 @@ def cmdLineParser(argv=None):
|
||||
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")
|
||||
|
||||
@@ -624,6 +659,9 @@ def cmdLineParser(argv=None):
|
||||
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")
|
||||
|
||||
@@ -648,17 +686,23 @@ def cmdLineParser(argv=None):
|
||||
general.add_argument("--scope", dest="scope",
|
||||
help="Regexp to filter targets from provided proxy log")
|
||||
|
||||
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("--update", dest="updateAll", action="store_true",
|
||||
help="Update sqlmap")
|
||||
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")
|
||||
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\")")
|
||||
@@ -666,50 +710,32 @@ def cmdLineParser(argv=None):
|
||||
miscellaneous.add_argument("--alert", dest="alert",
|
||||
help="Run host OS command(s) when SQL injection is found")
|
||||
|
||||
miscellaneous.add_argument("--answers", dest="answers",
|
||||
help="Set predefined answers (e.g. \"quit=N,follow=N\")")
|
||||
|
||||
miscellaneous.add_argument("--beep", dest="beep", action="store_true",
|
||||
help="Beep on question and/or when SQL injection is found")
|
||||
|
||||
miscellaneous.add_argument("--cleanup", dest="cleanup", action="store_true",
|
||||
help="Clean up the DBMS from sqlmap specific UDF and tables")
|
||||
|
||||
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("--gpage", dest="googlePage", type=int,
|
||||
help="Use Google dork results from specified page number")
|
||||
|
||||
miscellaneous.add_argument("--list-tampers", dest="listTampers", action="store_true",
|
||||
help="Display list of available tamper scripts")
|
||||
|
||||
miscellaneous.add_argument("--mobile", dest="mobile", action="store_true",
|
||||
help="Imitate smartphone through HTTP User-Agent header")
|
||||
|
||||
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("--skip-waf", dest="skipWaf", action="store_true",
|
||||
help="Skip heuristic detection of WAF/IPS protection")
|
||||
|
||||
miscellaneous.add_argument("--smart", dest="smart", action="store_true",
|
||||
help="Conduct thorough tests only if positive heuristic(s)")
|
||||
|
||||
miscellaneous.add_argument("--sqlmap-shell", dest="sqlmapShell", 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("--web-root", dest="webRoot",
|
||||
help="Web server document root directory (e.g. \"/var/www\")")
|
||||
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")
|
||||
@@ -838,18 +864,10 @@ def cmdLineParser(argv=None):
|
||||
parser.usage = ""
|
||||
cmdLineOptions.sqlmapShell = True
|
||||
|
||||
_ = ["x", "q", "exit", "quit", "clear"]
|
||||
commands = set(("x", "q", "exit", "quit", "clear"))
|
||||
commands.update(get_all_options(parser))
|
||||
|
||||
for option in get_actions(parser):
|
||||
_.extend(option._long_opts)
|
||||
_.extend(option._short_opts)
|
||||
|
||||
for group in get_groups(parser):
|
||||
for option in get_actions(group):
|
||||
_.extend(option._long_opts)
|
||||
_.extend(option._short_opts)
|
||||
|
||||
autoCompletion(AUTOCOMPLETE_TYPE.SQLMAP, commands=_)
|
||||
autoCompletion(AUTOCOMPLETE_TYPE.SQLMAP, commands=commands)
|
||||
|
||||
while True:
|
||||
command = None
|
||||
@@ -884,8 +902,11 @@ def cmdLineParser(argv=None):
|
||||
raise SqlmapSyntaxException("something went wrong during command line parsing ('%s')" % getSafeExString(ex))
|
||||
|
||||
for i in xrange(len(argv)):
|
||||
longOptions = set(re.findall(r"\-\-([^= ]+?)=", parser.format_help()))
|
||||
if argv[i] == "-hh":
|
||||
argv[i] = "-h"
|
||||
elif i == 1 and argv[i].startswith("http"):
|
||||
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, well, illegal (%s)\n" % argv[i])
|
||||
raise SystemExit
|
||||
@@ -931,6 +952,9 @@ def cmdLineParser(argv=None):
|
||||
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-\w\Z", 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:
|
||||
|
||||
+16
-10
@@ -22,7 +22,6 @@ except ImportError:
|
||||
class WebSocketException(Exception):
|
||||
pass
|
||||
|
||||
from extra.safe2bin.safe2bin import safecharencode
|
||||
from lib.core.agent import agent
|
||||
from lib.core.common import asciifyUrl
|
||||
from lib.core.common import calculateDeltaSeconds
|
||||
@@ -42,6 +41,7 @@ from lib.core.common import getRequestHeader
|
||||
from lib.core.common import getSafeExString
|
||||
from lib.core.common import isMultiThreadMode
|
||||
from lib.core.common import logHTTPTraffic
|
||||
from lib.core.common import openFile
|
||||
from lib.core.common import popValue
|
||||
from lib.core.common import pushValue
|
||||
from lib.core.common import randomizeParameterValue
|
||||
@@ -60,6 +60,7 @@ from lib.core.common import wasLastResponseDelayed
|
||||
from lib.core.compat import patchHeaders
|
||||
from lib.core.compat import xrange
|
||||
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
|
||||
@@ -123,6 +124,7 @@ 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
|
||||
@@ -426,6 +428,14 @@ class Connect(object):
|
||||
if auxHeaders:
|
||||
headers = forgeHeaders(auxHeaders, headers)
|
||||
|
||||
if kb.headersFile:
|
||||
content = openFile(kb.headersFile, "rb").read()
|
||||
for line in content.split("\n"):
|
||||
line = getText(line.strip())
|
||||
if ':' in line:
|
||||
header, value = line.split(':', 1)
|
||||
headers[header] = value
|
||||
|
||||
for key, value in list(headers.items()):
|
||||
del headers[key]
|
||||
if isinstance(value, six.string_types):
|
||||
@@ -749,21 +759,17 @@ class Connect(object):
|
||||
|
||||
if kb.connErrorCounter >= MAX_CONSECUTIVE_CONNECTION_ERRORS and kb.connErrorChoice is None:
|
||||
message = "there seems to be a continuous problem with connection to the target. "
|
||||
message += "Are you sure that you want to continue "
|
||||
message += "with further target testing? [y/N] "
|
||||
message += "Are you sure that you want to continue? [y/N] "
|
||||
|
||||
kb.connErrorChoice = readInput(message, default='N', boolean=True)
|
||||
|
||||
if kb.connErrorChoice is not None:
|
||||
if kb.connErrorChoice:
|
||||
raise SqlmapConnectionException(warnMsg)
|
||||
else:
|
||||
raise SqlmapUserQuitException
|
||||
if kb.connErrorChoice is False:
|
||||
raise SqlmapUserQuitException
|
||||
|
||||
if "forcibly closed" in tbMsg:
|
||||
logger.critical(warnMsg)
|
||||
return None, None, None
|
||||
elif ignoreTimeout and any(_ in tbMsg for _ in ("timed out", "IncompleteRead")):
|
||||
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"
|
||||
@@ -1033,7 +1039,7 @@ class Connect(object):
|
||||
return retVal
|
||||
|
||||
token = AttribDict()
|
||||
page, headers, code = Connect.getPage(url=conf.csrfUrl or conf.url, data=conf.data if conf.csrfUrl == conf.url else None, method=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, headers, code = Connect.getPage(url=conf.csrfUrl or conf.url, data=conf.data if conf.csrfUrl == conf.url 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)
|
||||
|
||||
@@ -7,7 +7,6 @@ See the file 'LICENSE' for copying permission
|
||||
|
||||
import time
|
||||
|
||||
from extra.safe2bin.safe2bin import safecharencode
|
||||
from lib.core.agent import agent
|
||||
from lib.core.common import Backend
|
||||
from lib.core.common import calculateDeltaSeconds
|
||||
@@ -25,8 +24,8 @@ 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 TAKEOVER_TABLE_PREFIX
|
||||
from lib.core.settings import UNICODE_ENCODING
|
||||
from lib.utils.safe2bin import safecharencode
|
||||
from lib.utils.timeout import timeout
|
||||
|
||||
def direct(query, content=True):
|
||||
@@ -54,7 +53,7 @@ def direct(query, content=True):
|
||||
|
||||
if not select and "EXEC " not in query.upper():
|
||||
timeout(func=conf.dbmsConnector.execute, args=(query,), duration=conf.timeout, default=None)
|
||||
elif not (output and ("%soutput" % TAKEOVER_TABLE_PREFIX) not in query and ("%sfile" % TAKEOVER_TABLE_PREFIX) not in query):
|
||||
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)
|
||||
|
||||
@@ -9,7 +9,6 @@ from __future__ import print_function
|
||||
|
||||
import sys
|
||||
|
||||
from extra.safe2bin.safe2bin import safechardecode
|
||||
from lib.core.common import Backend
|
||||
from lib.core.common import dataToStdout
|
||||
from lib.core.common import getSQLSnippet
|
||||
@@ -28,6 +27,7 @@ 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):
|
||||
|
||||
@@ -227,18 +227,15 @@ class Metasploit(object):
|
||||
|
||||
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.warn("beware that the VNC injection might not work")
|
||||
|
||||
break
|
||||
|
||||
elif Backend.isDbms(DBMS.MSSQL) and Backend.isVersionWithin(("2005", "2008")):
|
||||
@@ -634,7 +631,7 @@ class Metasploit(object):
|
||||
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, randomStr(len(SHELLCODEEXEC_RANDOM_STRING_MARKER)))
|
||||
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)
|
||||
|
||||
@@ -8,10 +8,8 @@ See the file 'LICENSE' for copying permission
|
||||
from __future__ import division
|
||||
|
||||
import re
|
||||
import threading
|
||||
import time
|
||||
|
||||
from extra.safe2bin.safe2bin import safecharencode
|
||||
from lib.core.agent import agent
|
||||
from lib.core.common import Backend
|
||||
from lib.core.common import calculateDeltaSeconds
|
||||
@@ -59,6 +57,7 @@ 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
|
||||
|
||||
def bisection(payload, expression, length=None, charsetType=None, firstChar=None, lastChar=None, dump=False):
|
||||
@@ -190,10 +189,8 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||
else:
|
||||
dataToStdout("\r[%s] [INFO] retrieved: " % time.strftime("%X"))
|
||||
|
||||
hintlock = threading.Lock()
|
||||
|
||||
def tryHint(idx):
|
||||
with hintlock:
|
||||
with kb.locks.hint:
|
||||
hintValue = kb.hintValue
|
||||
|
||||
if payload is not None and len(hintValue or "") > 0 and len(hintValue) >= idx:
|
||||
@@ -212,7 +209,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||
if result:
|
||||
return hintValue[idx - 1]
|
||||
|
||||
with hintlock:
|
||||
with kb.locks.hint:
|
||||
kb.hintValue = ""
|
||||
|
||||
return None
|
||||
|
||||
@@ -8,7 +8,6 @@ See the file 'LICENSE' for copying permission
|
||||
import re
|
||||
import time
|
||||
|
||||
from extra.safe2bin.safe2bin import safecharencode
|
||||
from lib.core.agent import agent
|
||||
from lib.core.common import Backend
|
||||
from lib.core.common import calculateDeltaSeconds
|
||||
@@ -33,6 +32,7 @@ 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):
|
||||
"""
|
||||
|
||||
@@ -10,7 +10,6 @@ from __future__ import print_function
|
||||
import re
|
||||
import time
|
||||
|
||||
from extra.safe2bin.safe2bin import safecharencode
|
||||
from lib.core.agent import agent
|
||||
from lib.core.bigarray import BigArray
|
||||
from lib.core.common import Backend
|
||||
@@ -60,6 +59,7 @@ 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):
|
||||
@@ -76,7 +76,7 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
|
||||
|
||||
threadData.resumed = retVal is not None and not partialValue
|
||||
|
||||
if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL, DBMS.ORACLE)) and kb.errorChunkLength is None and not chunkTest and not kb.testMode:
|
||||
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)
|
||||
|
||||
@@ -117,7 +117,7 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
|
||||
if field:
|
||||
nulledCastedField = agent.nullAndCastField(field)
|
||||
|
||||
if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL, DBMS.ORACLE)) and not any(_ in field for _ in ("COUNT", "CASE")) and kb.errorChunkLength and not chunkTest:
|
||||
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)
|
||||
@@ -177,7 +177,7 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
|
||||
else:
|
||||
output = output.rstrip()
|
||||
|
||||
if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL, DBMS.ORACLE)):
|
||||
if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL, DBMS.SYBASE, DBMS.ORACLE)):
|
||||
if offset == 1:
|
||||
retVal = output
|
||||
else:
|
||||
@@ -367,7 +367,7 @@ def errorUse(expression, dump=False):
|
||||
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):
|
||||
if readInput(message, default='N', boolean=True):
|
||||
expression = expression[:expression.index(" ORDER BY ")]
|
||||
|
||||
numThreads = min(conf.threads, (stopLimit - startLimit))
|
||||
|
||||
@@ -163,7 +163,7 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where=
|
||||
|
||||
if retVal:
|
||||
infoMsg = "target URL appears to be UNION injectable with %d columns" % retVal
|
||||
singleTimeLogMessage(infoMsg, logging.INFO, re.sub(r"\d+", "N", infoMsg))
|
||||
singleTimeLogMessage(infoMsg, logging.INFO, re.sub(r"\d+", 'N', infoMsg))
|
||||
|
||||
return retVal
|
||||
|
||||
@@ -290,7 +290,7 @@ def _unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix)
|
||||
if not conf.uChar and count > 1 and kb.uChar == NULL:
|
||||
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):
|
||||
if not readInput(message, default='Y', boolean=True):
|
||||
warnMsg += "usage of option '--union-char' "
|
||||
warnMsg += "(e.g. '--union-char=1') "
|
||||
else:
|
||||
|
||||
@@ -10,7 +10,6 @@ import re
|
||||
import time
|
||||
import xml.etree.ElementTree
|
||||
|
||||
from extra.safe2bin.safe2bin import safecharencode
|
||||
from lib.core.agent import agent
|
||||
from lib.core.bigarray import BigArray
|
||||
from lib.core.common import arrayizeValue
|
||||
@@ -62,6 +61,7 @@ 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
|
||||
|
||||
|
||||
+67
-56
@@ -60,6 +60,7 @@ def _addPageTextWords():
|
||||
|
||||
return wordsList
|
||||
|
||||
@stackedmethod
|
||||
def tableExists(tableFile, regex=None):
|
||||
if kb.tableExistsChoice 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])
|
||||
@@ -74,15 +75,17 @@ def tableExists(tableFile, regex=None):
|
||||
|
||||
result = inject.checkBooleanExpression("%s" % safeStringFormat(BRUTE_TABLE_EXISTS_TEMPLATE, (randomInt(1), randomStr())))
|
||||
|
||||
if conf.db and Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
|
||||
conf.db = conf.db.upper()
|
||||
|
||||
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 (DBMS.ORACLE, DBMS.DB2):
|
||||
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"
|
||||
@@ -92,80 +95,88 @@ def tableExists(tableFile, regex=None):
|
||||
message = "what's the custom common tables file location?\n"
|
||||
tableFile = readInput(message) or tableFile
|
||||
|
||||
infoMsg = "checking table existence using items from '%s'" % 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)
|
||||
|
||||
threadData = getCurrentThreadData()
|
||||
threadData.shared.count = 0
|
||||
threadData.shared.limit = len(tables)
|
||||
threadData.shared.files = []
|
||||
threadData.shared.unique = set()
|
||||
for conf.db in (conf.db.split(',') if conf.db else [conf.db]):
|
||||
if conf.db:
|
||||
infoMsg = "checking database '%s'" % conf.db
|
||||
logger.info(infoMsg)
|
||||
|
||||
def tableExistsThread():
|
||||
threadData = getCurrentThreadData()
|
||||
threadData.shared.count = 0
|
||||
threadData.shared.limit = len(tables)
|
||||
threadData.shared.files = []
|
||||
threadData.shared.unique = set()
|
||||
|
||||
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
|
||||
def tableExistsThread():
|
||||
threadData = getCurrentThreadData()
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
result = inject.checkBooleanExpression("%s" % safeStringFormat(BRUTE_TABLE_EXISTS_TEMPLATE, (randomInt(1), fullTableName)))
|
||||
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
|
||||
|
||||
kb.locks.io.acquire()
|
||||
result = inject.checkBooleanExpression("%s" % safeStringFormat(BRUTE_TABLE_EXISTS_TEMPLATE, (randomInt(1), fullTableName)))
|
||||
|
||||
if result and table.lower() not in threadData.shared.unique:
|
||||
threadData.shared.files.append(table)
|
||||
threadData.shared.unique.add(table.lower())
|
||||
kb.locks.io.acquire()
|
||||
|
||||
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 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):
|
||||
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)
|
||||
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)
|
||||
|
||||
kb.locks.io.release()
|
||||
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)
|
||||
|
||||
try:
|
||||
runThreads(conf.threads, tableExistsThread, threadChoice=True)
|
||||
except KeyboardInterrupt:
|
||||
warnMsg = "user aborted during table existence "
|
||||
warnMsg += "check. sqlmap will display partial output"
|
||||
logger.warn(warnMsg)
|
||||
kb.locks.io.release()
|
||||
|
||||
clearConsoleLine(True)
|
||||
dataToStdout("\n")
|
||||
try:
|
||||
runThreads(conf.threads, tableExistsThread, threadChoice=True)
|
||||
except KeyboardInterrupt:
|
||||
warnMsg = "user aborted during table existence "
|
||||
warnMsg += "check. sqlmap will display partial output"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
if not threadData.shared.files:
|
||||
warnMsg = "no table(s) found"
|
||||
logger.warn(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)
|
||||
clearConsoleLine(True)
|
||||
dataToStdout("\n")
|
||||
|
||||
for _ in ((conf.db, item) for item in threadData.shared.files):
|
||||
if _ not in kb.brute.tables:
|
||||
kb.brute.tables.append(_)
|
||||
if not threadData.shared.files:
|
||||
warnMsg = "no table(s) found"
|
||||
if conf.db:
|
||||
warnMsg += "for database '%s'" % conf.db
|
||||
logger.warn(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
|
||||
|
||||
@@ -92,8 +92,7 @@ def crawl(target):
|
||||
soup = BeautifulSoup(content)
|
||||
tags = soup('a')
|
||||
|
||||
if not tags:
|
||||
tags = re.finditer(r'(?i)<a[^>]+href=["\'](?P<href>[^>"\']+)', content)
|
||||
tags += re.finditer(r'(?i)<a[^>]+href=["\'](?P<href>[^>"\']+)', content)
|
||||
|
||||
for tag in tags:
|
||||
href = tag.get("href") if hasattr(tag, "get") else tag.group("href")
|
||||
|
||||
+35
-18
@@ -33,6 +33,7 @@ else:
|
||||
import base64
|
||||
import binascii
|
||||
import gc
|
||||
import hashlib
|
||||
import os
|
||||
import re
|
||||
import tempfile
|
||||
@@ -155,7 +156,24 @@ def postgres_passwd(password, username, uppercase=False):
|
||||
|
||||
return retVal.upper() if uppercase else retVal.lower()
|
||||
|
||||
def mssql_passwd(password, salt, uppercase=False):
|
||||
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
|
||||
@@ -172,7 +190,7 @@ def mssql_passwd(password, salt, uppercase=False):
|
||||
|
||||
return "0x%s" % (retVal.upper() if uppercase else retVal.lower())
|
||||
|
||||
def mssql_old_passwd(password, salt, uppercase=True): # prior to version '2005'
|
||||
def mssql_old_passwd(password, salt, uppercase=True): # version '2000' and before
|
||||
"""
|
||||
Reference(s):
|
||||
www.exploit-db.com/download_pdf/15537/
|
||||
@@ -190,22 +208,6 @@ def mssql_old_passwd(password, salt, uppercase=True): # prior to version '2005'
|
||||
|
||||
return "0x%s" % (retVal.upper() if uppercase else retVal.lower())
|
||||
|
||||
def mssql_new_passwd(password, salt, uppercase=False):
|
||||
"""
|
||||
Reference(s):
|
||||
http://hashcat.net/forum/thread-1474.html
|
||||
|
||||
>>> 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 oracle_passwd(password, salt, uppercase=True):
|
||||
"""
|
||||
Reference(s):
|
||||
@@ -246,6 +248,18 @@ def oracle_old_passwd(password, username, uppercase=True): # prior to version '
|
||||
|
||||
return retVal.upper() if uppercase else retVal.lower()
|
||||
|
||||
def md4_generic_passwd(password, uppercase=False):
|
||||
"""
|
||||
>>> md4_generic_passwd(password='testpass', uppercase=False)
|
||||
'5b4d300688f19c8fd65b8d6ccf98e0ae'
|
||||
"""
|
||||
|
||||
password = getBytes(password)
|
||||
|
||||
retVal = hashlib.new("md4", password).hexdigest()
|
||||
|
||||
return retVal.upper() if uppercase else retVal.lower()
|
||||
|
||||
def md5_generic_passwd(password, uppercase=False):
|
||||
"""
|
||||
>>> md5_generic_passwd(password='testpass', uppercase=False)
|
||||
@@ -708,6 +722,7 @@ def attackDumpedTable():
|
||||
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)
|
||||
@@ -942,6 +957,8 @@ def dictionaryAttack(attack_dict):
|
||||
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:]}]
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ class ReqHandler(_BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
self.send_header(HTTP_HEADER.CONNECTION, "close")
|
||||
|
||||
if content is not None:
|
||||
for match in re.finditer(b"<\!(\w+)\!>", content):
|
||||
for match in re.finditer(b"<!(\\w+)!>", content):
|
||||
name = match.group(1)
|
||||
_ = getattr(self, "_%s" % name.lower(), None)
|
||||
if _:
|
||||
|
||||
@@ -7,7 +7,6 @@ See the file 'LICENSE' for copying permission
|
||||
|
||||
import re
|
||||
|
||||
from extra.safe2bin.safe2bin import safechardecode
|
||||
from lib.core.agent import agent
|
||||
from lib.core.bigarray import BigArray
|
||||
from lib.core.common import Backend
|
||||
@@ -33,6 +32,7 @@ from lib.core.settings import MAX_INT
|
||||
from lib.core.settings import NULL
|
||||
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):
|
||||
|
||||
+2
-1
@@ -15,6 +15,7 @@ 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
|
||||
|
||||
@@ -84,4 +85,4 @@ def purge(directory):
|
||||
try:
|
||||
shutil.rmtree(directory)
|
||||
except OSError as ex:
|
||||
logger.error("problem occurred while removing directory '%s' ('%s')" % (directory, getSafeExString(ex)))
|
||||
logger.error("problem occurred while removing directory '%s' ('%s')" % (getUnicode(directory), getSafeExString(ex)))
|
||||
|
||||
@@ -1,23 +1,15 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
safe2bin.py - Simple safe(hex) to binary format converter
|
||||
|
||||
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
|
||||
See the file 'LICENSE' for copying permission
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import binascii
|
||||
import re
|
||||
import string
|
||||
import os
|
||||
import sys
|
||||
|
||||
from optparse import OptionError
|
||||
from optparse import OptionParser
|
||||
|
||||
if sys.version_info >= (3, 0):
|
||||
xrange = range
|
||||
text_type = str
|
||||
@@ -49,10 +41,10 @@ def safecharencode(value):
|
||||
"""
|
||||
Returns safe representation of a given basestring value
|
||||
|
||||
>>> safecharencode(u'test123')
|
||||
u'test123'
|
||||
>>> safecharencode(u'test\x01\x02\xff')
|
||||
u'test\\01\\02\\03\\ff'
|
||||
>>> safecharencode(u'test123') == u'test123'
|
||||
True
|
||||
>>> safecharencode(u'test\x01\x02\xaf') == u'test\\\\x01\\\\x02\\xaf'
|
||||
True
|
||||
"""
|
||||
|
||||
retVal = value
|
||||
@@ -107,37 +99,3 @@ def safechardecode(value, binary=False):
|
||||
retVal[i] = safechardecode(value[i])
|
||||
|
||||
return retVal
|
||||
|
||||
def main():
|
||||
usage = '%s -i <input file> [-o <output file>]' % sys.argv[0]
|
||||
parser = OptionParser(usage=usage, version='0.1')
|
||||
|
||||
try:
|
||||
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 not a regular file' % args.inputFile)
|
||||
sys.exit(1)
|
||||
|
||||
f = open(args.inputFile, 'r')
|
||||
data = f.read()
|
||||
f.close()
|
||||
|
||||
if not args.outputFile:
|
||||
args.outputFile = args.inputFile + '.bin'
|
||||
|
||||
f = open(args.outputFile, 'wb')
|
||||
f.write(safechardecode(data))
|
||||
f.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -76,7 +76,8 @@ class SQLAlchemy(GenericConnector):
|
||||
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')")
|
||||
raise
|
||||
else:
|
||||
pass
|
||||
except SqlmapFilePathException:
|
||||
raise
|
||||
except Exception as ex:
|
||||
|
||||
@@ -10,6 +10,7 @@ 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
|
||||
@@ -74,13 +75,14 @@ class Fingerprint(GenericFingerprint):
|
||||
("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")),
|
||||
# TODO: add test for Firebird 2.5
|
||||
("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)))
|
||||
check = checks[randomRange(0, len(checks) - 1)].replace("%d", getUnicode(randomRange(1, 100))).replace("%s", getUnicode(randomStr()))
|
||||
result = inject.checkBooleanExpression(check)
|
||||
|
||||
if result:
|
||||
|
||||
@@ -96,7 +96,7 @@ class Fingerprint(GenericFingerprint):
|
||||
infoMsg = "actively fingerprinting %s" % DBMS.INFORMIX
|
||||
logger.info(infoMsg)
|
||||
|
||||
for version in ("12.1", "11.7", "11.5"):
|
||||
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:
|
||||
|
||||
@@ -94,7 +94,8 @@ class Fingerprint(GenericFingerprint):
|
||||
("2008", "SYSDATETIME()=SYSDATETIME()"),
|
||||
("2012", "CONCAT(NULL,NULL)=CONCAT(NULL,NULL)"),
|
||||
("2014", "CHARINDEX('12.0.2000',@@version)>0"),
|
||||
("2016", "ISJSON(NULL) IS NULL")
|
||||
("2016", "ISJSON(NULL) IS NULL"),
|
||||
("2017", "TRIM(NULL) IS NULL")
|
||||
):
|
||||
result = inject.checkBooleanExpression(check)
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ class Fingerprint(GenericFingerprint):
|
||||
(50600, 50646), # MySQL 5.6
|
||||
(50700, 50726), # MySQL 5.7
|
||||
(60000, 60014), # MySQL 6.0
|
||||
(80000, 80015), # MySQL 8.0
|
||||
(80000, 80017), # MySQL 8.0
|
||||
)
|
||||
|
||||
index = -1
|
||||
|
||||
@@ -21,6 +21,7 @@ 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
|
||||
|
||||
@@ -30,7 +31,7 @@ class Enumeration(GenericEnumeration):
|
||||
|
||||
rootQuery = queries[DBMS.ORACLE].roles
|
||||
|
||||
if conf.user == "CU":
|
||||
if conf.user == CURRENT_USER:
|
||||
infoMsg += " for current user"
|
||||
conf.user = self.getCurrentUser()
|
||||
|
||||
@@ -55,7 +56,7 @@ class Enumeration(GenericEnumeration):
|
||||
values = inject.getValue(query, blind=False, time=False)
|
||||
|
||||
if not values and not query2:
|
||||
infoMsg = "trying with table USER_ROLE_PRIVS"
|
||||
infoMsg = "trying with table 'USER_ROLE_PRIVS'"
|
||||
logger.info(infoMsg)
|
||||
|
||||
return self.getRoles(query2=True)
|
||||
@@ -116,7 +117,7 @@ class Enumeration(GenericEnumeration):
|
||||
|
||||
if not isNumPosStrValue(count):
|
||||
if count != 0 and not query2:
|
||||
infoMsg = "trying with table USER_SYS_PRIVS"
|
||||
infoMsg = "trying with table 'USER_SYS_PRIVS'"
|
||||
logger.info(infoMsg)
|
||||
|
||||
return self.getPrivileges(query2=True)
|
||||
|
||||
@@ -105,7 +105,7 @@ class Fingerprint(GenericFingerprint):
|
||||
logger.info(infoMsg)
|
||||
|
||||
# Reference: https://en.wikipedia.org/wiki/Oracle_Database
|
||||
for version in ("18c", "12c", "11g", "10g", "9i", "8i"):
|
||||
for version in ("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))
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ 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 isListLike
|
||||
from lib.core.common import isStackingAvailable
|
||||
from lib.core.common import randomStr
|
||||
@@ -104,7 +105,7 @@ class Takeover(GenericTakeover):
|
||||
output = inject.getValue(query, resumeValue=False)
|
||||
|
||||
if isListLike(output):
|
||||
output = os.linesep.join(output)
|
||||
output = os.linesep.join(flattenValue(output))
|
||||
|
||||
self._cleanupCmd = "DROP TABLE %s" % self.cmdTblName
|
||||
inject.goStacked(self._cleanupCmd)
|
||||
|
||||
@@ -33,7 +33,6 @@ 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 TAKEOVER_TABLE_PREFIX
|
||||
from lib.core.settings import UNICODE_ENCODING
|
||||
from lib.request import inject
|
||||
|
||||
@@ -43,7 +42,7 @@ class Filesystem(object):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.fileTblName = "%sfile" % TAKEOVER_TABLE_PREFIX
|
||||
self.fileTblName = "%sfile" % conf.tablePrefix
|
||||
self.tblField = "data"
|
||||
|
||||
def _checkFileLength(self, localFile, remoteFile, fileRead=False):
|
||||
|
||||
@@ -25,7 +25,6 @@ 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.core.settings import TAKEOVER_TABLE_PREFIX
|
||||
from lib.takeover.abstraction import Abstraction
|
||||
from lib.takeover.icmpsh import ICMPsh
|
||||
from lib.takeover.metasploit import Metasploit
|
||||
@@ -37,7 +36,7 @@ class Takeover(Abstraction, Metasploit, ICMPsh, Registry):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.cmdTblName = ("%soutput" % TAKEOVER_TABLE_PREFIX)
|
||||
self.cmdTblName = ("%soutput" % conf.tablePrefix)
|
||||
self.tblField = "data"
|
||||
|
||||
Abstraction.__init__(self)
|
||||
|
||||
@@ -39,6 +39,7 @@ from lib.core.enums import EXPECTED
|
||||
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.threads import getCurrentThreadData
|
||||
from lib.request import inject
|
||||
from lib.utils.hash import attackCachedUsersPasswords
|
||||
@@ -153,7 +154,7 @@ class Users(object):
|
||||
|
||||
rootQuery = queries[Backend.getIdentifiedDbms()].passwords
|
||||
|
||||
if conf.user == "CU":
|
||||
if conf.user == CURRENT_USER:
|
||||
infoMsg += " for current user"
|
||||
conf.user = self.getCurrentUser()
|
||||
|
||||
@@ -362,7 +363,7 @@ class Users(object):
|
||||
|
||||
rootQuery = queries[Backend.getIdentifiedDbms()].privileges
|
||||
|
||||
if conf.user == "CU":
|
||||
if conf.user == CURRENT_USER:
|
||||
infoMsg += " for current user"
|
||||
conf.user = self.getCurrentUser()
|
||||
|
||||
@@ -410,7 +411,7 @@ class Users(object):
|
||||
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"
|
||||
infoMsg = "trying with table 'USER_SYS_PRIVS'"
|
||||
logger.info(infoMsg)
|
||||
|
||||
return self.getPrivileges(query2=True)
|
||||
@@ -446,7 +447,7 @@ class Users(object):
|
||||
# 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":
|
||||
if privilege.upper() == 'Y':
|
||||
privileges.add(MYSQL_PRIVS[count])
|
||||
|
||||
# In Firebird we get one letter for each privilege
|
||||
@@ -465,7 +466,7 @@ class Users(object):
|
||||
i = 1
|
||||
|
||||
for priv in privs:
|
||||
if priv.upper() in ("Y", "G"):
|
||||
if priv.upper() in ('Y', 'G'):
|
||||
for position, db2Priv in DB2_PRIVS.items():
|
||||
if position == i:
|
||||
privilege += ", " + db2Priv
|
||||
@@ -525,7 +526,7 @@ class Users(object):
|
||||
|
||||
if not isNumPosStrValue(count):
|
||||
if not retrievedUsers and Backend.isDbms(DBMS.ORACLE) and not query2:
|
||||
infoMsg = "trying with table USER_SYS_PRIVS"
|
||||
infoMsg = "trying with table 'USER_SYS_PRIVS'"
|
||||
logger.info(infoMsg)
|
||||
|
||||
return self.getPrivileges(query2=True)
|
||||
|
||||
+39
-32
@@ -67,6 +67,10 @@ dropSetCookie = False
|
||||
# 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
|
||||
@@ -176,16 +180,19 @@ safeReqFile =
|
||||
# Default: 0
|
||||
safeFreq = 0
|
||||
|
||||
# Skip URL encoding of payload data
|
||||
# Skip URL encoding of payload data.
|
||||
# Valid: True or False
|
||||
skipUrlEncode = False
|
||||
|
||||
# Parameter used to hold anti-CSRF token
|
||||
# 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 =
|
||||
|
||||
# Force usage of SSL/HTTPS
|
||||
# Valid: True or False
|
||||
forceSSL = False
|
||||
@@ -343,6 +350,10 @@ regexp =
|
||||
# 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
|
||||
@@ -683,6 +694,9 @@ sessionFile =
|
||||
# Log all HTTP traffic into a textual file.
|
||||
trafficFile =
|
||||
|
||||
# Set predefined answers (e.g. "quit=N,follow=N").
|
||||
answers =
|
||||
|
||||
# Never ask for user input, use the default behaviour.
|
||||
# Valid: True or False
|
||||
batch = False
|
||||
@@ -693,6 +707,10 @@ 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
|
||||
@@ -729,6 +747,11 @@ forms = False
|
||||
# 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
|
||||
@@ -752,15 +775,22 @@ repair = False
|
||||
# Example: (google|yahoo)
|
||||
scope =
|
||||
|
||||
# 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 =
|
||||
|
||||
# Update sqlmap.
|
||||
# Valid: True or False
|
||||
updateAll = False
|
||||
# Web server document root directory (e.g. "/var/www").
|
||||
webRoot =
|
||||
|
||||
|
||||
[Miscellaneous]
|
||||
@@ -768,9 +798,6 @@ updateAll = False
|
||||
# Run host OS command(s) when SQL injection is found.
|
||||
alert =
|
||||
|
||||
# Set predefined answers (e.g. "quit=N,follow=N").
|
||||
answers =
|
||||
|
||||
# Beep on question and/or when SQL injection is found.
|
||||
# Valid: True or False
|
||||
beep = False
|
||||
@@ -779,10 +806,6 @@ beep = False
|
||||
# Valid: True or False
|
||||
checkPayload = False
|
||||
|
||||
# Clean up the DBMS from sqlmap specific UDF and tables.
|
||||
# Valid: True or False
|
||||
cleanup = False
|
||||
|
||||
# Check for missing (optional) sqlmap dependencies.
|
||||
# Valid: True or False
|
||||
dependencies = False
|
||||
@@ -791,41 +814,25 @@ dependencies = False
|
||||
# Valid: True or False
|
||||
disableColoring = False
|
||||
|
||||
# Use Google dork results from specified page number.
|
||||
# Valid: integer
|
||||
# Default: 1
|
||||
googlePage = 1
|
||||
|
||||
# Display list of available tamper scripts
|
||||
# Valid: True or False
|
||||
listTampers = False
|
||||
|
||||
# Imitate smartphone through HTTP User-Agent header.
|
||||
# Valid: True or False
|
||||
mobile = False
|
||||
|
||||
# Work in offline mode (only use session data)
|
||||
# Valid: True or False
|
||||
offline = False
|
||||
|
||||
# Skip heuristic detection of WAF/IPS protection.
|
||||
# Valid: True or False
|
||||
skipWaf = False
|
||||
|
||||
# Conduct thorough tests only if positive heuristic(s).
|
||||
# Valid: True or False
|
||||
smart = False
|
||||
|
||||
# Local directory for storing temporary files.
|
||||
tmpDir =
|
||||
|
||||
# Web server document root directory (e.g. "/var/www").
|
||||
webRoot =
|
||||
|
||||
# Simple wizard interface for beginner users.
|
||||
# Valid: True or False
|
||||
wizard = False
|
||||
|
||||
# Update sqlmap.
|
||||
# Valid: True or False
|
||||
updateAll = False
|
||||
|
||||
# Verbosity level.
|
||||
# Valid: integer between 0 and 6
|
||||
# 0: Show only error and critical messages
|
||||
|
||||
@@ -263,6 +263,11 @@ def main():
|
||||
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 ("No such file", "_'")):
|
||||
errMsg = "corrupted installation detected ('%s'). " % excMsg.strip().split('\n')[-1]
|
||||
errMsg += "You should retrieve the latest development version from official GitHub "
|
||||
|
||||
+14
-5
@@ -16,20 +16,29 @@ def dependencies():
|
||||
pass
|
||||
|
||||
def randomIP():
|
||||
numbers = []
|
||||
octets = []
|
||||
|
||||
while not numbers or numbers[0] in (10, 172, 192):
|
||||
numbers = random.sample(xrange(1, 255), 4)
|
||||
while not octets or octets[0] in (10, 172, 192):
|
||||
octets = random.sample(xrange(1, 255), 4)
|
||||
|
||||
return '.'.join(str(_) for _ in numbers)
|
||||
return '.'.join(str(_) for _ in octets)
|
||||
|
||||
def tamper(payload, **kwargs):
|
||||
"""
|
||||
Append a fake HTTP header 'X-Forwarded-For'
|
||||
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
|
||||
|
||||
+1
-1
@@ -894,7 +894,7 @@ class Tag(PageElement):
|
||||
|
||||
def recursiveChildGenerator(self):
|
||||
if not len(self.contents):
|
||||
raise StopIteration
|
||||
return # Note: https://stackoverflow.com/a/30217723 (PEP 479)
|
||||
stopNode = self._lastRecursiveChild().next
|
||||
current = self.contents[0]
|
||||
while current is not stopNode:
|
||||
|
||||
Vendored
+3
-1
@@ -227,6 +227,9 @@ def unescape(data, entities, encoding=DEFAULT_ENCODING):
|
||||
if data is None or "&" not in data:
|
||||
return data
|
||||
|
||||
if isinstance(data, six.string_types):
|
||||
encoding = None
|
||||
|
||||
def replace_entities(match, entities=entities, encoding=encoding):
|
||||
ent = match.group()
|
||||
if ent[1] == "#":
|
||||
@@ -279,7 +282,6 @@ def get_entitydefs():
|
||||
entitydefs["&%s;" % name] = _unichr(codepoint)
|
||||
return entitydefs
|
||||
|
||||
|
||||
def issequence(x):
|
||||
try:
|
||||
x[0]
|
||||
|
||||
Vendored
+2
@@ -184,6 +184,8 @@ class AnsiToWin32(object):
|
||||
if not (err.errno == 0 and retry > 0):
|
||||
raise
|
||||
self._write(text, retry-1)
|
||||
except UnicodeError:
|
||||
self.wrapped.write('?')
|
||||
|
||||
def convert_ansi(self, paramstring, command):
|
||||
if self.convert:
|
||||
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (c) 2019 Miroslav Stampar (@stamparm), MIT
|
||||
# See the file 'LICENSE' for copying permission
|
||||
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user