AWVS14.7sql injection part source code analysis

AWVS-SQL injection partial source code analysis

**PS:**In the article, I will indent some sentence patterns, the text is fixed by default, and the input indentation corresponds to the code indentation, so please pay attention to my paragraph indentation.

classErrorBasedSQLInjection.inc

classSQLErrorMessages()

this.plainArray

Store common sql injection error messages, such as

'Microsoft OLE DB Provider for ODBC Drivers',
'Error Executing Database Query',
'Microsoft OLE DB Provider for SQL Server',
'ODBC Microsoft Access Driver',

this.regexArray

Store the regular matching information of common sql injection, such as

/(Incorrect\ssyntax\snear\s'[^']*')/,
/(Syntax error: Missing operand after '[^']*' operator)/,
/Syntax error near\s.*?\sin the full-text search condition\s/,
/column "\w{5}" does not exist/,
/near\s[^:]+?:\ssyntax\serror/,
/(pg_query\(\)[:]*\squery\sfailed:\serror:\s)/,
/('[^']*'\sis\snull\sor\snot\san\sobject)/,
/(ORA-\d{4,5}:\s)/,

**PS:** Here is an explanation of the difference between this.plainArray and this.regexArray, both of which match strings, but this.plainArray directly matches the contents of the array with the strings, requiring a complete match Variables meet the matching requirements, and this.regexArray emphasizes a regular matching rule. As long as there is content in the string that meets the matching rules, it is considered to meet the matching requirements.

this.FalsePositivesPlainArray

Store the obvious characteristics of sql injection error reporting, such as

"Connection Timeout",
"(0x80131904)",
"org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object"

this.FalsePositivesRegexArray

Temporarily empty, judging from the array name, it is used to store the expression characteristics when SQL injection errors are reported.

classSQLErrorMessages.prototype.isFalsePositive = function (text)

Function

A function used to judge whether there are obvious features of sql error message.

content

Match the obtained data with the data in this.FalsePositivesPlainArray in turn, and return true if it exists.

Match the obtained data with the data in this.FalsePositivesRegexArray in turn, and return true if it exists.

Return false if none.

classSQLErrorMessages.prototype.searchOnText = function (text)

Function

By means of string matching, it is judged which kind of sql injection characteristics the string belongs to.

content

Declare a variable first _in, the default value is body

Match the obtained data, if "HTTP/1." or "HTTP/0." is recognized, the obtained information is recognized as a response packet, and the value is assigned _inas response .

Match the obtained data with the data in this.plainArray in turn. If there is, return highlightFromTextSearch(this.plainArray[i], text, _in) . The function of this function is to match the value of this.plainArray[i] in text Return to _in .

Match the obtained data with the data in this.regexArray in turn, if there is return highlightFromRegexMatch(m, _in) , this function returns the regular matching result in m to **_in**, where m=this.regexArray[ i].exec(text)

Return false if none.

InjectionResult(data, adItem)

Function

Assign values ​​to the class properties this.data and this.adItem

content

this.data = data;
this.adItem = adItem;

classErrorBasedSQLInjection(targetUrl, errorMessages, scheme, inputIndex, variationIndex, reflectionPoint)

Function

Assign values ​​to class attributes, especially save the input content (change value) this.variations , and initialize some class attributes.

content

First assign values ​​to some class variables

this.scheme = scheme;
this.targetUrl = targetUrl;
this.errorMessages = errorMessages;
this.inputIndex = inputIndex;
this.reflectionPoint = reflectionPoint;
this.foundVulnOnVariation = false;
this.lastJob = null;
this.lastJobConfirm = null;
this.disableSensorBased = false;

If scheme is not empty, initialize this.currentVariation and this.origValue = this.getOrigValue();

If scheme is not empty and inputIndex is not empty, create array this.variations and assign inputIndex to this.variations .

If scheme is not empty but inputIndex is empty, create an array this.variations and assign this.scheme.selectVariationsForInput(inputIndex) to this.variations .

classErrorBasedSQLInjection.prototype.isSQLInjection = function (sensorData, start, end)

Function

Determine the database type based on the fingerprint feature, and store the result of the attempted injection.

content

Initialize items first , items = sensorData.getItems(“SQL_Query”) , sensorData.getItems here can be understood as a function to capture and analyze http request packets.

If items is empty null .

The value item is taken out sequentially from items .

​ If item is not empty, initialize dbType = "mysql" addData = item.additional

​ If the length of addData is greater than or equal to 2, db = addData[1]

​ If matched in db database=, db = db.substr(9) dbType = db.toLowerCase()

Take the value entry from item.dataList in turn

​ If the variable start string is matched in the entry

​ If dbType == 'mysql' and ax.util.testForInjection(entry, ax.util.InjectionType.MySQL, start, end) is not equal to empty (the return value of the attempted injection function is not empty), return InjectionResult(entry, item )

​ If dbType == 'mssql' or dbType == 'mssql_or_access' and ax.util.testForInjection(entry, ax.util.InjectionType.MySQL, start, end) is not equal to empty, return InjectionResult(entry, item)

​ If dbType == 'pg' and ax.util.testForInjection(entry, ax.util.InjectionType.MySQL, start, end) is not equal to empty, return InjectionResult(entry, item)

​ If dbType == 'sqlite' and ax.util.testForInjection(entry, ax.util.InjectionType.MySQL, start, end) is not equal to empty, return InjectionResult(entry, item)

​ If dbType == 'oracle' and ax.util.testForInjection(entry, ax.util.InjectionType.MySQL, start, end) is not equal to empty, return InjectionResult(entry, item)

​ If dbType == 'sybase' and ax.util.testForInjection(entry, ax.util.InjectionType.MySQL, start, end) is not equal to empty, return InjectionResult(entry, item)

​ If dbType does not meet the above conditions, and ax.util.testForInjection(entry, ax.util.InjectionType.MySQL, start, end) is not equal to empty, return InjectionResult(entry, item)

Otherwise return false

classErrorBasedSQLInjection.prototype.getOrigValue = function ()

Function

Matches whether the input data (this.inputIndex) has already been entered.

content

Initialize the variable value , the initial value is empty.

Take values ​​sequentially from this.variations (this array is the input content stored in classErrorBasedSQLInjection), match the input data (this.inputIndex) with the previously stored data (this.variations), and the matching result is varValue, if it contains relation (variations contains the input data this.inputIndex). If value is empty and varValue is not empty, assign value to varValue , exit the loop, and return value .

classErrorBasedSQLInjection.prototype.request = function (value)

Function

Appends a value value to the current variation and sends an HTTP request.

content

If there is a file upload ( this.scheme.hasFileInput ) and the input data has a key flag ( this.scheme.getInputFlags(this.inputIndex) ) and the uploaded data is a file ( INPUT_FLAG_IS_FILE ), then set the upload file name (setInputFileName) to value , set the upload file type (setInputContentType) to image/png , and set the upload file value (setInputValue) to value . Otherwise, set the upload file value to value .

Initialize lastJob ( this.lastJob = new THTTPJob() ), assign this.lastJob.url to this.targetUrl

If the value in targetHasAcuSensor ( this.scheme.targetHasAcuSensor ) is not empty, call this.lastJob.addAspectHeaders()

Call populateRequest , passing lastjob ( this.scheme.populateRequest(this.lastJob) )

PS: The function of calling populateRequest is to fill in the perfect request header.

If the string Referer does not exist in the request header , call the function addHeader to add the request header Referer

Then send a package to lastJob ( this.lastJob.execute() ).

Initialize variable tmp = false

If the request result does not report an error ( wasError )) and the response packet can be received, send a packet to reflectionPoint , copy the response packet data to the lastJob response packet, and assign tmp to the value of wasError .

Finally return !this.lastJob.wasError && !tmp

classFileInclusion.prototype.requestProof = function (value, dontEncode)

Function

Extract the proof, and judge whether the extraction proof ( Proof ) exists.

content

If there is a file upload ( this.scheme.hasFileInput ) and the input data has a key flag ( this.scheme.getInputFlags(this.inputIndex) ) and the uploaded data is a file ( INPUT_FLAG_IS_FILE ), then set the upload file name (setInputFileName) to value , set the upload file type ( setInputContentType ) to image/png .

​ If dontEncode == TRUE , call setEncodedInputValue , set the encoded input value ( this.inputIndex ) to value ( this.scheme.setEncodedInputValue(this.inputIndex, value) ), otherwise set the input value ( this.inputIndex ) to value .

otherwise

​ If dontEncode == TRUE , call setEncodedInputValue , set the encoded input value ( this.inputIndex ) to value ( this.scheme.setEncodedInputValue(this.inputIndex, value) ), otherwise set the input value ( this.inputIndex ) to value .

Initialize this.lastJobProof = new THTTPJob()

Initialize this.lastJobProof.url = this.targetUrl

If the value in targetHasAcuSensor ( this.scheme.targetHasAcuSensor ) is not empty, call this.lastJob.addAspectHeaders()

Call populateRequest , passing lastjob ( this.scheme.populateRequest(this.lastJob) )

If the string Referer does not exist in the request header , call the function addHeader to add the request header Referer

Then send a package to lastJob ( this.lastJob.execute() ).

return !this.lastJobProof.wasError

classFileInclusion.prototype.extractProofOfExploit = function (testValue)

Function

Attempt to extract proof of exploit

content

Initialize proof = false

Initialize proof_title = false

Initialize proof_contents = false

init- regex = false

If testValue starts with **http://**, then

testValue = "http://bxss.me/t/fit.txt?";
regex = /(63c19a6da79816b21429e5bb262daed863c19a6da79816b21429e5bb262daed8)/;
proof_title = "URL - http://bxss.me/t/fit.txt";

otherwise

testValue = "../../../../../../../../proc/version";
regex = /(Linux\sversion\s\d.*?\s\(.*?\)\s\(gcc\sversion\s\d.*?\(.*?\)\s*\)\s\#.*?[A-Z]{3}\s\d{4})/;
proof_title = "File - /proc/version";

if regex is not empty

​ If the testValue extraction proves that the result is flase , return false .

​ Assign the variable match to this.lastJobProof.response.toString().match(regex) , here is the matching result returned after matching regex (regular matching rules) to the information in the request package in testValue .

​ If match is not empty and the length of match (array) is greater than 1, assign proof_contents to match[1] .

​ If proof_contents is not empty, return [proof_title, proof_contents].

return proof.

classFileInclusion.prototype.alert = function (testValue, matchedText, sourceFile, sourceLine, additionalInfo, acuSensor)

Function

Generate report items for scanners.

content

Initialize this.foundVulnOnVariation = true

Initialize- flags=[]

If acuSensor == TRUE , write the values ​​verified and acusensor to flags .

If this.reflectionPoint is not empty, write the value stored into flags .

Initialize proof_title = false

Initialize proof_contents = false

Initialize the constant proof = this.extractProofOfExploit(testValue)

If proof exists and proof (array) length is 2, then proof_title = proof[0] , proof_contents = proof[1] .

If both proof_title and proof_contents are not empty, write the value verified into flags .

Initialize newVuln

var newVuln = {
    typeId: "File_inclusion.xml",
    path: this.scheme.path,
    tags: flags,
    highlights: [matchedText],
    details: {
        input_type: this.scheme.getInputTypeStr(this.inputIndex),
        input_name: this.scheme.getInputName(this.inputIndex),
        proof_title: proof_title ? proof_title : false,
        proof_contents: proof_contents ? proof_contents : false,
        test_value: testValue,
        matched_text: matchedText ? matchedText : false,
        reflection_point: this.reflectionPoint ? this.reflectionPoint.url.url : false
    },
    http: this.lastJob.getNativeObject(),
    ssl: scriptArg.target.url.protocol == 'https',
    parameter: this.scheme.getInputName(this.inputIndex),
    attackVector: testValue
};

If sourceFile is not empty or additionalInfo is not empty, add value to newVuln

newVuln.sensor = {
    file: sourceFile,
    line: sourceLine,
    additional: additionalInfo
};

Add newVuln to scanState ( scanState.addVuln(newVuln) )

classFileInclusion.prototype.testInjection = function (value, dontEncode)

Function

Try to perform sql injection, and generate a report item if the attempt fails.

content

Initialize sensorPayload = value.includes(this.injectionValidator.startMark)

Returns false if **!this.request(value, dontEncode) is true** .

Initialize job = this.lastJob

Create data = this.disableSensorBased , if empty then call getSensorData(this.lastJob) .

If data and sensorPayload are not empty, initialize the variable injRes = this.isFileInclusion(value, data)

​ If injRes and injRes.adItem are not empty, assign a value to the variable additional, additional = "File: " + injRes.data + "\r\n" + injRes.adItem.additional[0] , generate a report item this.alert (value, "", injRes.adItem.fileName, injRes.adItem.fileNo, additional, 1) and return false .

Otherwise, initialize this.disableSensorBased = true .

​ If this.reflectionPoint is empty, assign a value to the variable matchedText , matchedText = this.injectionPatterns.searchOnText(job.response.toString()) , where the information returned by the response packet of the job is matched with the information in injectionPatterns , and the matched The result is assigned to matchedText .

​ If matchedText is not empty, generate a report item this.alert(value, matchedText) and return false .

returns true .

classFileInclusion.prototype.testInjectionSelfInclude = function (value)

Function

Try to perform sql injection, and generate a report item if the attempt fails.

content

Returns false if sending http request failed ( !this.request(value, 0) ) .

Initialize job = this.lastJob .

Assign a value to matchmatch = job.response.toString().match(/(<%@[^%]+?%>)/) , , where the regular matching method is matched <%@[^%]+?%>with the response packet of the job , and if there is a string in job.response that meets the matching rules, it is assigned to match .

If match and match[1] are not empty, generate a report item this.alert(value, match[1]) and return false .

returns true .

classFileInclusion.prototype.startTesting = function ()

Function

The main function, which tests all input changes.

content

Initialize inputType = this.scheme.getInputTypeStr(this.inputIndex)

Initialize inputName = this.scheme.getInputName(this.inputIndex)

Take the values ​​​​in order from this.variations

​ If this.foundVulnOnVariation == false then exit the loop.

​ Assign variable this.currentVariation = i .

​ If targetHasAcuSensor or reflectionPoint is not empty

​ If reflectionPoint is empty, then this.injectionValidator.startMark = rnd.randStrDigits(6) , this.injectionValidator.endMark = rnd.randStrDigits(6)

​ If the result of the attempt to inject is false , continue the loop.

!this.testInjection(`1${this.injectionValidator.startMark}/../../xxx\\..\\..\\${this.injectionValidator.endMark}`)

​ 否则,this.injectionValidator.startMark = rnd.randStrDigits(6)this.injectionValidator.endMark = rnd.randStrDigits(6)

​ If the result of the attempt to inject is false , continue the loop.

!this.testInjection(`1${this.injectionValidator.startMark}/../../xxx\\..\\..\\${this.injectionValidator.endMark}`)

​ If this.injectionPatterns is not empty, assign origValue = this.getOrigValue() and initialize extension = "jpg" .

​ If origValue is not empty and origValue contains words 符点".", take the string after the last dot (.) and assign it to extension .

​ Initialize schemeExtension = ""

​ Initialize schemePath = scheme.path

​ If schemePath is not empty and schemePath contains words , take the string after符点"." the last dot (.) and assign it to schemeExtension ; take the string after the last backslash (/) and assign it to schemeFileName .

​ If the result of the attempt to inject is false , continue the loop.

!this.testInjection("http://some-inexistent-website.acu/some_inexistent_file_with_long_name%3F." + extension, 1)

​ If the result of the attempt to inject is false , continue the loop.

!this.testInjection("1some_inexistent_file_with_long_name%00." + extension, 1)

​ If the result of the attempt to inject is false , continue the loop.

!this.testInjection("Http://" + AcuMonitor_AMServer + "/t/fit.txt", 1)

​ If the result of the attempt to inject is false , continue the loop.

!this.testInjection("http://" + AcuMonitor_AMServer + "/t/fit.txt%3F." + extension, 1)

​ If the result of the attempt to inject is false , continue the loop.

!this.testInjection(AcuMonitor_AMServer, 0)

​ If schemeExtension == 'jsp' and origValue contains the string backslash (/) .

​ If the result of the attempt to inject is false , continue the loop.

!this.testInjectionSelfInclude(schemePath)

​ If the result of the attempt to inject is false , continue the loop.

!this.testInjectionSelfInclude(schemePath.replace(/^\/[^\/]+/, ""))

​ If the result of the attempt to inject is false , continue the loop.

!this.testInjectionSelfInclude(schemePath.replace(/^\/[^\/]+/, "").replace(/^\/[^\/]+/, ""))

​ If the result of the attempt to inject is false , continue the loop.

!this.testInjectionSelfInclude(schemePath.replace(/^\/[^\/]+/, "").replace(/^\/[^\/]+/, "").replace(/^\/[^\/]+/, ""))

​ If schemeExtension == 'jsp' .

​ If the result of the attempt to inject is false , continue the loop.

!this.testInjectionSelfInclude(schemeFileName)

​ If the result of the attempt to inject is false , continue the loop.

!this.testInjectionSelfInclude("./" + schemeFileName)

​ If the result of the attempt to inject is false , continue the loop.

!this.testInjectionSelfInclude("/" + schemeFileName)

SQL_Injection_In_Basic_Auth.script

Function

First determine whether the visited website meets the requirements of SQL injection, handle the URL, and call the testInjection function up to four times to determine whether there is SQL injection.

try username

try password

Username in single quotes, password in double quotes

Username in double quotes, password in single quotes

Include

#include constants.inc;
#include classErrorBasedSQLInjection.inc;

custom function

function alert(path, value, job, matchedText, sourceFile, sourceLine, additionalInfo, acuSensor)

AWVS is a function used to report vulnerabilities. When a vulnerability is judged, this function is called to report the vulnerability, and the corresponding vulnerability information is echoed. This only needs to know the general effect, and careful analysis will involve a lot of calling functions, so I won’t go into details.

function request(dir, withAop, path, value)

Initialize variables

lastJob = new THTTPJob();
lastJob.url = dir.url;
lastJob.uri = path;
lastJob.autoAuthenticate = false;

Add the header name Authorization to the lastJob request header , and the value is value . ( lastJob. request. addHeader(“Authorization”, value, true) )

If withAop == True , call the function lastJob.addAspectHeaders() to add the request header

send package lastJob.execute()

returns **!lastJob.wasError**

function testInjection(dir, withAop, path, value, tester)

Assign a value to the variable sensorPayload

sensorPayload = value.includes("MUFDVVNUQVJUJ1wiKi9cclxuIFx0QUNVRU5EOmFhYWE=") || value.includes("YWFhYToxQUNVU1RBUlQnXCIqL1xyXG4gXHRBQ1VFTkQ=")
MUFDVVNUQVJUJ1wiKi9cclxuIFx0QUNVRU5EOmFhYWE=
BASE64解密结果
1ACUSTART'\"*/\r\n \tACUEND:aaaa

YWFhYToxQUNVU1RBUlQnXCIqL1xyXG4gXHRBQ1VFTkQ=
BASE64解密结果
aaaa:1ACUSTART'\"*/\r\n \tACUEND

Returns false if the request result is false (request(dir, withAop, path, value)) .

init job = lastJob

data = getSensorData(job)

If the data is not empty and the result of the sensorPayload judgment is not empty, assign the variable **injRes = tester.isSQLInjection(data, ACUINJSTART, ACUINJEND)** to determine whether there is SQL injection.

​ If injRes and injRes.adItem are not empty, assign the variable additional = "SQL query: " + injRes.data + "\r\n" + injRes.adItem.additional[0] and call the alert function ( alert(path, value, job, "", injRes.adItem.fileName, injRes.adItem.fileNo, additional, 1) ) and returns false .

Otherwise initialize the variable matchedText = errorMessages.searchOnText(job.response.body)

​ If matchedText is not empty, call the alert function ( alert(path, value, job, matchedText) ) and return false .

returns true .

main function

init dir = getCurrentDirectory()

If the status code after the request is 401 and the variable value of the variable name WWW-Authenticate in the request header contains Basic , then initialize the variable

var lastJob = null;
var errorMessages = new classSQLErrorMessages();
var dirName = dir.fullPath;

​ If the end of the URL is not a backslash (/) , add a backslash (/) to the end of the URL ( if (dirName.charAt(dirName.length - 1) != '/') dirName = dirName + '/' )

​ Assign variable **tester = new classErrorBasedSQLInjection(scanURL, errorMessages, null, 0)** The function is to assign values ​​​​to class attributes ( this.variations ).

​ If dir.hasAcuSensor is not empty

​ If testInjection(dir, true, dirName, "Basic MUFDVVNUQVJUJ1wiKi9cclxuIFx0QUNVRU5EOmFhYWE=", tester) returns true [Try Username], call the function testInjection ( testInjection(dir, true, dirName, "Basic YWFhYToxQUNVU1RBUlQn XCIqL1xyXG4gXHRBQ1VFTkQ=", tester) ) 【Try password】.

​ otherwise

​ If testInjection(dir, false, dirName, "Basic Jzoi") returns true [single quote user, double quote password], then call the function testInjection ( testInjection(dir, false, dirName, 'Basic Ijon') ) [double quote user, single quote password].

SQL_Injection_In_URI.script

Function

First determine whether the visited website meets the requirements of SQL injection, handle the URL, and call the testInjection function up to six times to determine whether there is SQL injection.

Include

#include constants.inc;
#include classErrorBasedSQLInjection.inc;
#include dir_listing_helpers.inc;

custom function

function alert(path, value, job, matchedText, sourceFile, sourceLine, additionalInfo, acuSensor)

AWVS is a function used to report vulnerabilities. When a vulnerability is judged, this function is called to report the vulnerability, and the corresponding vulnerability information is echoed.

function request(dir, withAop, path)

Initialize variables

lastJob = new THTTPJob();
lastJob.url = dir.url;
lastJob.uri = path;

If withAop == True , call the function lastJob.addAspectHeaders() to add the request header

Add request header

lastJob.request.addHeader('User-Agent', '1\'"2000', true);
lastJob.request.addHeader('referer', '1\'"3000', true);
lastJob.request.addHeader('client-ip', '1\'"4000', true);
lastJob.request.addHeader('x-forwarded-for', '1\'"5000', true);
lastJob.request.addHeader('accept-language', '1\'"6000', true);
lastJob.request.addHeader('via', '1\'"7000', true);

send package lastJob.execute()

returns **!lastJob.wasError**

function testInjection(dir, withAop, path, value, tester)

Assign variable sensorPayload = value.includes(ACUINJSTART)

Returns false if the request result is false ( request(dir, withAop, path, value) ) .

init job = lastJob

data = getSensorData(job)

If the data is not empty and the result of the sensorPayload judgment is not empty, assign the variable **injRes = tester.isSQLInjection(data, ACUINJSTART, ACUINJEND)** to determine whether there is SQL injection.

​ If both injRes and injResinjRes are not empty, assign the variable additional = "SQL query: " + injRes.data + "\r\n" + injRes.adItem.additional[0] and call the alert function ( alert(path, value , job, "", injRes.adItem.fileName, injRes.adItem.fileNo, additional, 1) ) and returns false .

Otherwise initialize the variable matchedText = errorMessages.searchOnText(job.response.body)

​ If matchedText is not empty, call the alert function ( alert(path, value, job, matchedText) ) and return false .

returns true .

main function

init dir = getCurrentDirectory()

If the status code is 200 after the request , initialize the variable matches = new classDirListingMatches()

​ If **matches.searchOnText(dir.response.body)** is empty, initialize the variable

var lastJob = null;
var errorMessages = new classSQLErrorMessages();
var dirName = dir.fullPath;

​ If the end of the URL is not a backslash (/) , add a backslash (/) to the end of the URL ( if (dirName.charAt(dirName.length - 1) != '/') dirName = dirName + '/' )

​ Assign variable **tester = new classErrorBasedSQLInjection(scanURL, errorMessages, null, 0)** The function is to assign values ​​​​to class attributes ( this.variations ).

​ If dir.hasAcuSensor is not empty

​ 如果testInjection(dir, true, dirName, dirName + `1 A C U I N J S T A R T ′ " {ACUINJSTART}'" A C U I N J S T A R T "{ACUINJEND}`, tester, dirName)returnsfalse, then returnstrue. [Simple construction]

​ If testInjection(dir, true, dirName, dirName + `index/1 KaTeX parse error: Can't use function '\'' in math mode at position 14: {ACUINJSTART}\̲'̲" {ACUINJEND}`, tester , dirName) returns false , then returns true . [index construction]

​ If testInjection(dir, true, dirName, dirName + `?id=1 KaTeX parse error: Can't use function '\'' in math mode at position 14: {ACUINJSTART}\̲'̲" {ACUINJEND}`, tester, dirName) returns false , then returns true . [Construction with parameters]

​ If matchedText is empty

​ If the return value of testInjection(dir, false, dirName, dirName + "1'\“1000") is false , return true . [Simple construction]

​ If the return value of testInjection(dir, false, dirName, dirName + "index/1'\“1000") is false , return true . [index construction]

​ If the return value of testInjection(dir, false, dirName, dirName + "?id=1'\“1000") is false , return true . [Build with parameters]

Guess you like

Origin blog.csdn.net/weixin_46706771/article/details/124208693