|
165 | 165 | from lib.core.settings import URLENCODE_CHAR_LIMIT |
166 | 166 | from lib.core.settings import URLENCODE_FAILSAFE_CHARS |
167 | 167 | from lib.core.settings import USER_AGENT_ALIASES |
| 168 | +from lib.core.settings import VERSION |
168 | 169 | from lib.core.settings import VERSION_STRING |
169 | 170 | from lib.core.settings import WEBSCARAB_SPLITTER |
170 | 171 | from lib.core.threads import getCurrentThreadData |
@@ -1165,6 +1166,9 @@ def getHeader(headers, key): |
1165 | 1166 | def checkFile(filename, raiseOnError=True): |
1166 | 1167 | """ |
1167 | 1168 | Checks for file existence and readability |
| 1169 | +
|
| 1170 | + >>> checkFile(__file__) |
| 1171 | + True |
1168 | 1172 | """ |
1169 | 1173 |
|
1170 | 1174 | valid = True |
@@ -1647,6 +1651,9 @@ def parseUnionPage(page): |
1647 | 1651 | def parseFilePaths(page): |
1648 | 1652 | """ |
1649 | 1653 | Detects (possible) absolute system paths inside the provided page content |
| 1654 | +
|
| 1655 | + >>> _ = "/var/www/html/index.php"; parseFilePaths("<html>Error occurred at line 207 of: %s<br>Please contact your administrator</html>" % _); _ in kb.absFilePaths |
| 1656 | + True |
1650 | 1657 | """ |
1651 | 1658 |
|
1652 | 1659 | if page: |
@@ -2039,6 +2046,9 @@ def parseXmlFile(xmlFile, handler): |
2039 | 2046 | def getSQLSnippet(dbms, sfile, **variables): |
2040 | 2047 | """ |
2041 | 2048 | Returns content of SQL snippet located inside 'procs/' directory |
| 2049 | +
|
| 2050 | + >>> 'RECONFIGURE' in getSQLSnippet(DBMS.MSSQL, "activate_sp_oacreate") |
| 2051 | + True |
2042 | 2052 | """ |
2043 | 2053 |
|
2044 | 2054 | if sfile.endswith('.sql') and os.path.exists(sfile): |
@@ -2078,9 +2088,12 @@ def getSQLSnippet(dbms, sfile, **variables): |
2078 | 2088 |
|
2079 | 2089 | return retVal |
2080 | 2090 |
|
2081 | | -def readCachedFileContent(filename, mode='rb'): |
| 2091 | +def readCachedFileContent(filename, mode="rb"): |
2082 | 2092 | """ |
2083 | 2093 | Cached reading of file content (avoiding multiple same file reading) |
| 2094 | +
|
| 2095 | + >>> "readCachedFileContent" in readCachedFileContent(__file__) |
| 2096 | + True |
2084 | 2097 | """ |
2085 | 2098 |
|
2086 | 2099 | if filename not in kb.cache.content: |
@@ -2137,13 +2150,19 @@ def average(values): |
2137 | 2150 | def calculateDeltaSeconds(start): |
2138 | 2151 | """ |
2139 | 2152 | Returns elapsed time from start till now |
| 2153 | +
|
| 2154 | + >>> calculateDeltaSeconds(0) > 1151721660 |
| 2155 | + True |
2140 | 2156 | """ |
2141 | 2157 |
|
2142 | 2158 | return time.time() - start |
2143 | 2159 |
|
2144 | 2160 | def initCommonOutputs(): |
2145 | 2161 | """ |
2146 | 2162 | Initializes dictionary containing common output values used by "good samaritan" feature |
| 2163 | +
|
| 2164 | + >>> initCommonOutputs(); "information_schema" in kb.commonOutputs["Databases"] |
| 2165 | + True |
2147 | 2166 | """ |
2148 | 2167 |
|
2149 | 2168 | kb.commonOutputs = {} |
@@ -3351,6 +3370,9 @@ def unhandledExceptionMessage(): |
3351 | 3370 | def getLatestRevision(): |
3352 | 3371 | """ |
3353 | 3372 | Retrieves latest revision from the offical repository |
| 3373 | +
|
| 3374 | + >>> getLatestRevision() == VERSION |
| 3375 | + True |
3354 | 3376 | """ |
3355 | 3377 |
|
3356 | 3378 | retVal = None |
@@ -4149,6 +4171,9 @@ def checkSystemEncoding(): |
4149 | 4171 | def evaluateCode(code, variables=None): |
4150 | 4172 | """ |
4151 | 4173 | Executes given python code given in a string form |
| 4174 | +
|
| 4175 | + >>> _ = {}; evaluateCode("a = 1; b = 2; c = a", _); _["c"] |
| 4176 | + 1 |
4152 | 4177 | """ |
4153 | 4178 |
|
4154 | 4179 | try: |
@@ -4202,6 +4227,9 @@ def incrementCounter(technique): |
4202 | 4227 | def getCounter(technique): |
4203 | 4228 | """ |
4204 | 4229 | Returns query counter for a given technique |
| 4230 | +
|
| 4231 | + >>> resetCounter(PAYLOAD.TECHNIQUE.STACKED); incrementCounter(PAYLOAD.TECHNIQUE.STACKED); getCounter(PAYLOAD.TECHNIQUE.STACKED) |
| 4232 | + 1 |
4205 | 4233 | """ |
4206 | 4234 |
|
4207 | 4235 | return kb.counters.get(technique, 0) |
@@ -4441,6 +4469,9 @@ def zeroDepthSearch(expression, value): |
4441 | 4469 | """ |
4442 | 4470 | Searches occurrences of value inside expression at 0-depth level |
4443 | 4471 | regarding the parentheses |
| 4472 | +
|
| 4473 | + >>> _ = "SELECT (SELECT id FROM users WHERE 2>1) AS result FROM DUAL"; _[zeroDepthSearch(_, "FROM")[0]:] |
| 4474 | + 'FROM DUAL' |
4444 | 4475 | """ |
4445 | 4476 |
|
4446 | 4477 | retVal = [] |
@@ -4476,7 +4507,7 @@ def pollProcess(process, suppress_errors=False): |
4476 | 4507 | Checks for process status (prints . if still running) |
4477 | 4508 | """ |
4478 | 4509 |
|
4479 | | - while True: |
| 4510 | + while process: |
4480 | 4511 | dataToStdout(".") |
4481 | 4512 | time.sleep(1) |
4482 | 4513 |
|
@@ -4701,12 +4732,33 @@ def getSafeExString(ex, encoding=None): |
4701 | 4732 | return getUnicode(retVal or "", encoding=encoding).strip() |
4702 | 4733 |
|
4703 | 4734 | def safeVariableNaming(value): |
| 4735 | + """ |
| 4736 | + Returns escaped safe-representation of a given variable name that can be used in Python evaluated code |
| 4737 | +
|
| 4738 | + >>> safeVariableNaming("foo bar") |
| 4739 | + 'foo__SAFE__20bar' |
| 4740 | + """ |
| 4741 | + |
4704 | 4742 | return re.sub(r"[^\w]", lambda match: "%s%02x" % (SAFE_VARIABLE_MARKER, ord(match.group(0))), value) |
4705 | 4743 |
|
4706 | 4744 | def unsafeVariableNaming(value): |
| 4745 | + """ |
| 4746 | + Returns unescaped safe-representation of a given variable name |
| 4747 | +
|
| 4748 | + >>> unsafeVariableNaming("foo__SAFE__20bar") |
| 4749 | + 'foo bar' |
| 4750 | + """ |
| 4751 | + |
4707 | 4752 | return re.sub(r"%s([0-9a-f]{2})" % SAFE_VARIABLE_MARKER, lambda match: match.group(1).decode("hex"), value) |
4708 | 4753 |
|
4709 | 4754 | def firstNotNone(*args): |
| 4755 | + """ |
| 4756 | + Returns first not-None value from a given list of arguments |
| 4757 | +
|
| 4758 | + >>> firstNotNone(None, None, 1, 2, 3) |
| 4759 | + 1 |
| 4760 | + """ |
| 4761 | + |
4710 | 4762 | retVal = None |
4711 | 4763 |
|
4712 | 4764 | for _ in args: |
|
0 commit comments