SQLmap註入啟發式檢測算法
1、經過setTargetEnv()就進入了checkWaf()的環節
def
checkWaf():
"""
Reference: http://seclists.org/nmap-dev/2011/q2/att-1005/http-waf-detect.nse
"""
if
any
((conf.string, conf.notString, conf.regexp, conf.dummy, conf.offline, conf.skipWaf)):
return
None
_
=
hashDBRetrieve(HASHDB_KEYS.CHECK_WAF_RESULT,
True
)
if
_
is
not
None
:
if
_:
warnMsg
=
"previous heuristics detected that the target "
warnMsg
+
=
"is protected by some kind of WAF/IPS/IDS"
logger.critical(warnMsg)
return
_
infoMsg
=
"checking if the target is protected by "
infoMsg
+
=
"some kind of WAF/IPS/IDS"
logger.info(infoMsg)
retVal
=
False
payload
=
"%d %s"
%
(randomInt(), IDS_WAF_CHECK_PAYLOAD)
value
=
""
if
not
conf.parameters.get(PLACE.GET)
else
conf.parameters[PLACE.GET]
+
DEFAULT_GET_POST_DELIMITER
value
+
=
agent.addPayloadDelimiters(
"%s=%s"
%
(randomStr(), payload))
pushValue(conf.timeout)
conf.timeout
=
IDS_WAF_CHECK_TIMEOUT
try
:
retVal
=
Request.queryPage(place
=
PLACE.GET, value
=
value, getRatioValue
=
True
, noteResponseTime
=
False
, silent
=
True
)[
1
] < IDS_WAF_CHECK_RATIO
except
SqlmapConnectionException:
retVal
=
True
finally
:
kb.matchRatio
=
None
conf.timeout
=
popValue()
if
retVal:
warnMsg
=
"heuristics detected that the target "
warnMsg
+
=
"is protected by some kind of WAF/IPS/IDS"
logger.critical(warnMsg)
if
not
conf.identifyWaf:
message
=
"do you want sqlmap to try to detect backend "
message
+
=
"WAF/IPS/IDS? [y/N] "
if
readInput(message, default
=
‘N‘
, boolean
=
True
):
conf.identifyWaf
=
True
if
conf.timeout
=
=
defaults.timeout:
logger.warning(
"dropping timeout to %d seconds (i.e. ‘--timeout=%d‘)"
%
(IDS_WAF_CHECK_TIMEOUT, IDS_WAF_CHECK_TIMEOUT))
conf.timeout
=
IDS_WAF_CHECK_TIMEOUT
hashDBWrite(HASHDB_KEYS.CHECK_WAF_RESULT, retVal,
True
)
return
retVal
2、啟發式註入檢測
def
heuristicCheckSqlInjection(place, parameter):
if
kb.nullConnection:
debugMsg
=
"heuristic check skipped because NULL connection used"
logger.debug(debugMsg)
return
None
origValue
=
conf.paramDict[place][parameter]
paramType
=
conf.method
if
conf.method
not
in
(
None
, HTTPMETHOD.GET, HTTPMETHOD.POST)
else
place
prefix
=
""
suffix
=
""
randStr
=
""
if
conf.prefix
or
conf.suffix:
if
conf.prefix:
prefix
=
conf.prefix
if
conf.suffix:
suffix
=
conf.suffix
while
randStr.count(
‘\‘‘
) !
=
1
or
randStr.count(
‘\"‘
) !
=
1
:
randStr
=
randomStr(length
=
10
, alphabet
=
HEURISTIC_CHECK_ALPHABET)
kb.heuristicMode
=
True
payload
=
"%s%s%s"
%
(prefix, randStr, suffix)
payload
=
agent.payload(place, parameter, newValue
=
payload)
page, _, _
=
Request.queryPage(payload, place, content
=
True
, raise404
=
False
)
kb.heuristicPage
=
page
kb.heuristicMode
=
False
parseFilePaths(page)
result
=
wasLastResponseDBMSError()
infoMsg
=
"heuristic (basic) test shows that %s parameter "
%
paramType
infoMsg
+
=
"‘%s‘ might "
%
parameter
def
_(page):
return
any
(_
in
(page
or
"")
for
_
in
FORMAT_EXCEPTION_STRINGS)
casting
=
_(page)
and
not
_(kb.originalPage)
if
not
casting
and
not
result
and
kb.dynamicParameter
and
origValue.isdigit():
randInt
=
int
(randomInt())
payload
=
"%s%s%s"
%
(prefix,
"%d-%d"
%
(
int
(origValue)
+
randInt, randInt), suffix)
payload
=
agent.payload(place, parameter, newValue
=
payload, where
=
PAYLOAD.WHERE.REPLACE)
result
=
Request.queryPage(payload, place, raise404
=
False
)
if
not
result:
randStr
=
randomStr()
payload
=
"%s%s%s"
%
(prefix,
"%s.%d%s"
%
(origValue, random.randint(
1
,
9
), randStr), suffix)
payload
=
agent.payload(place, parameter, newValue
=
payload, where
=
PAYLOAD.WHERE.REPLACE)
casting
=
Request.queryPage(payload, place, raise404
=
False
)
kb.heuristicTest
=
HEURISTIC_TEST.CASTED
if
casting
else
HEURISTIC_TEST.NEGATIVE
if
not
result
else
HEURISTIC_TEST.POSITIVE
if
casting:
errMsg
=
"possible %s casting "
%
(
"integer"
if
origValue.isdigit()
else
"type"
)
errMsg
+
=
"detected (e.g. \"$%s=intval($_REQUEST[‘%s‘])\") "
%
(parameter, parameter)
errMsg
+
=
"at the back-end web application"
logger.error(errMsg)
if
kb.ignoreCasted
is
None
:
message
=
"do you want to skip those kind of cases (and save scanning time)? %s "
%
(
"[Y/n]"
if
conf.multipleTargets
else
"[y/N]"
)
kb.ignoreCasted
=
readInput(message, default
=
‘Y‘
if
conf.multipleTargets
else
‘N‘
, boolean
=
True
)
elif
result:
infoMsg
+
=
"be injectable"
if
Backend.getErrorParsedDBMSes():
infoMsg
+
=
" (possible DBMS: ‘%s‘)"
%
Format
.getErrorParsedDBMSes()
logger.info(infoMsg)
else
:
infoMsg
+
=
"not be injectable"
logger.warn(infoMsg)
kb.heuristicMode
=
True
randStr1, randStr2
=
randomStr(NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH), randomStr(NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH)
value
=
"%s%s%s"
%
(randStr1, DUMMY_NON_SQLI_CHECK_APPENDIX, randStr2)
payload
=
"%s%s%s"
%
(prefix,
"‘%s"
%
value, suffix)
payload
=
agent.payload(place, parameter, newValue
=
payload)
page, _, _
=
Request.queryPage(payload, place, content
=
True
, raise404
=
False
)
paramType
=
conf.method
if
conf.method
not
in
(
None
, HTTPMETHOD.GET, HTTPMETHOD.POST)
else
place
if
value.lower()
in
(page
or
"").lower():
infoMsg
=
"heuristic (XSS) test shows that %s parameter "
%
paramType
infoMsg
+
=
"‘%s‘ might be vulnerable to cross-site scripting attacks"
%
parameter
logger.info(infoMsg)
for
match
in
re.finditer(FI_ERROR_REGEX, page
or
""):
if
randStr1.lower()
in
match.group(
0
).lower():
infoMsg
=
"heuristic (FI) test shows that %s parameter "
%
paramType
infoMsg
+
=
"‘%s‘ might be vulnerable to file inclusion attacks"
%
parameter
logger.info(infoMsg)
break
kb.heuristicMode
=
False
return
kb.heuristicTest
首先是對sql註入的檢測
1 |
payload = "%s%s%s" % (prefix, randStr, suffix)
|
randStr就是隨機生成的可導致sql語句因閉合問題而報錯的字符,這個payload不是用來註入的,而是將其產生的頁面作為啟發式註入標準頁面(kb.heuristicPage),與不註入產生的正常頁面(kb.originalPage)作為一個基準性對比。
接下來是一個關鍵變量casting
1 |
casting = _(page) and not _(kb.originalPage)
|
_()函數如下
1 2 |
def _(page):
return any (_ in (page or "") for _ in FORMAT_EXCEPTION_STRINGS)
|
FORMAT_EXCEPTION_STRINGS 是一些在Web服務中常見的sql語句關於變量類型出錯的報錯
(‘Type mismatch‘, ‘Error converting‘, ‘Conversion failed‘, ‘String or binary data would be truncated‘, ‘Failed to convert‘, ‘unable to interpret text value‘, ‘Input string was not in a correct format‘, ‘System.FormatException‘, ‘java.lang.NumberFormatException‘, ‘ValueError: invalid literal‘, ‘DataTypeMismatchException‘, ‘CF_SQL_INTEGER‘, ‘ for CFSQLTYPE ‘, ‘cfqueryparam cfsqltype‘, ‘InvalidParamTypeException‘, ‘Invalid parameter type‘, ‘is not of type numeric‘, ‘<cfif Not IsNumeric(‘, ‘invalid input syntax for integer‘, ‘invalid input syntax for type‘, ‘invalid number‘, ‘character to number conversion error‘, ‘unable to interpret text value‘, ‘String was not recognized as a valid‘, ‘Convert.ToInt‘, ‘cannot be converted to a ‘, ‘InvalidDataException‘)
casting為false就代表這種註入樣例因為變量類型不統一而無法使用,所以用戶可以選擇跳過這些樣例
第二個關鍵變量 result
1 |
result = wasLastResponseDBMSError()
|
函數如下
1 2 3 4 5 6 |
def wasLastResponseDBMSError():
"""
Returns True if the last web request resulted in a (recognized) DBMS error page
"""
threadData = getCurrentThreadData()
return threadData.lastErrorPage and threadData.lastErrorPage[ 0 ] = = threadData.lastRequestUID
|
如果啟發式註入標準頁面是可識別的,則返回ture,否則返回false
這也作為sqlmap啟發性測試結果的標誌,為true就代表可能存在註入,為false就可能不存在註入
接下來就是對於非sql註入漏洞的檢測,sqlmap會隨機生成可引發其他類型漏洞報錯的字符,然後進行註入測試,在sqlmap源碼中可以看出除了sql註入,還測試了xss與文件包含漏洞
1、內部類,java編譯器生成的內部類的字節碼文件的名字和通常的不同,內部類對應的字節碼文件名字的格式是“外嵌類名&內部類類名”,如果將內部類添加修飾詞static,則可以這樣調用, RedCowForm.RedCow redCow=new RedCowForm.RedCow(122,232,333);
public class NeiBuLai {
public static void main(String[] args) {
// TODO Auto-generated method stub
RedCowForm form=new RedCowForm("德納司");
form.showMessage();
RedCowForm.RedCow redCow=new RedCowForm.RedCow(122,232,333);
}
}
class RedCowForm{
static String formName;
RedCow cow;
RedCowForm(){
}
RedCowForm(String s){
cow=new RedCow(12,23,34);
formName=s;
}
public void showMessage(){
cow.speak();
}
static class RedCow{
String cowName="bed wos";
int height,weight,price;
// int t=0;int w=0;int p=0;
RedCow(int h, int w,int p){
height=h;
weight=w;
price=p;
}
void speak(){
System.out.println("mingzi"+cowName+"shenggao"+height+"tizhong"+weight+"shenghuozai"+formName);
}
}
}
2、匿名類匿名類繼承父類的方法一個可以重寫父類的方法,匿名類必須是內部類。用匿名類創建對象時直接使用父類的構造方法。
public class NiMingLei {
public static void main(String[] args) {
// TODO Auto-generated method stub
ShowBoard board=new ShowBoard();
board.showMessge(new OutPutEnglish());//這是一個OutPutAlpaabe的子類對象
board.showMessge(new OutPutAlphabe(){ public void output(){
for(char c=‘@‘;c<‘*‘;c++)
System.out.printf("%3c",c);
}
}
);//這裏是OutPutAlphabe的一個匿名類也是他的一個子類對象
}
}
abstract class OutPutAlphabet{
public abstract void output();
}
class OutPutEnglish extends OutPutAlphabet{
public void output(){
for(char c=‘a‘;c<‘z‘;c++){
System.out.printf("%3c",c);
}
}
}
class ShowBoard{
void showMessge(OutPutAlphabet show){
show.output();
}
}
3、接口匿名類
public class JieKouNiMIng {
public static void main(String[] args) {
// TODO Auto-generated method stub
HelloMachine machine=new HelloMachine();
machine.turnON(new SpeakHello(){
public void spaek(){
System.out.println("Hello ,you are wellcome");
}
@Override
public void speak() {
// TODO Auto-generated method stub
}
});
machine.turnON(new SpeakHello(){
public void spaek(){
System.out.println("Hello ");
}
@Override
public void speak() {
// TODO Auto-generated method stub
}
});
}
}
interface SpeakHello{
void speak();
}
class HelloMachine{
public void turnON(SpeakHello hello){
hello.speak();
}
}
4、異常類的處理以及自定義異常類使用
SQLmap註入啟發式檢測算法