├── MaltegoTransform.py ├── README.md ├── crtsh.mtz └── crtsh.py /MaltegoTransform.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ####################################################### 3 | # Maltego Python Local Transform Helper # 4 | # Version 0.3 # 5 | # # 6 | # Local transform specification can be found at: # 7 | # http://ctas.paterva.com/view/Specification # 8 | # # 9 | # For more help and other local transforms # 10 | # try the forum or mail me: # 11 | # # 12 | # http://www.paterva.com/forum # 13 | # # 14 | # Andrew MacPherson [ andrew <> Paterva.com ] # 15 | # # 16 | # UPDATED: 2016/08/29 - PR ["&",">","<"] # 17 | # UPDATED: 2015/10/29 - PR # 18 | # UPDATED: 2016/08/19 - AM (fixed # and = split) # 19 | ####################################################### 20 | 21 | import sys 22 | 23 | 24 | BOOKMARK_COLOR_NONE="-1" 25 | BOOKMARK_COLOR_BLUE="0" 26 | BOOKMARK_COLOR_GREEN="1" 27 | BOOKMARK_COLOR_YELLOW="2" 28 | BOOKMARK_COLOR_ORANGE="3" 29 | BOOKMARK_COLOR_RED="4" 30 | 31 | LINK_STYLE_NORMAL="0" 32 | LINK_STYLE_DASHED="1" 33 | LINK_STYLE_DOTTED="2" 34 | LINK_STYLE_DASHDOT="3" 35 | 36 | UIM_FATAL='FatalError' 37 | UIM_PARTIAL='PartialError' 38 | UIM_INFORM='Inform' 39 | UIM_DEBUG='Debug' 40 | 41 | 42 | class MaltegoEntity(object): 43 | value = "" 44 | weight = 100 45 | displayInformation = None 46 | additionalFields = [] 47 | iconURL = "" 48 | entityType = "Phrase" 49 | 50 | def __init__(self,eT=None,v=None): 51 | if (eT is not None): 52 | self.entityType = eT 53 | if (v is not None): 54 | self.value = sanitise(v) 55 | self.additionalFields = [] 56 | self.displayInformation = None 57 | 58 | def setType(self,eT=None): 59 | if (eT is not None): 60 | self.entityType = eT 61 | 62 | def setValue(self,eV=None): 63 | if (eV is not None): 64 | self.value = sanitise(eV) 65 | 66 | def setWeight(self,w=None): 67 | if (w is not None): 68 | self.weight = w 69 | 70 | def setDisplayInformation(self,di=None): 71 | if (di is not None): 72 | self.displayInformation = di 73 | 74 | def addAdditionalFields(self,fieldName=None,displayName=None,matchingRule=False,value=None): 75 | self.additionalFields.append([sanitise(fieldName),sanitise(displayName),matchingRule,sanitise(value)]) 76 | 77 | def setIconURL(self,iU=None): 78 | if (iU is not None): 79 | self.iconURL = iU 80 | 81 | def setLinkColor(self,color): 82 | self.addAdditionalFields('link#maltego.link.color','LinkColor','',color) 83 | 84 | def setLinkStyle(self,style): 85 | self.addAdditionalFields('link#maltego.link.style','LinkStyle','',style) 86 | 87 | def setLinkThickness(self,thick): 88 | self.addAdditionalFields('link#maltego.link.thickness','Thickness','',str(thick)) 89 | 90 | def setLinkLabel(self,label): 91 | self.addAdditionalFields('link#maltego.link.label','Label','',label) 92 | 93 | def setBookmark(self,bookmark): 94 | self.addAdditionalFields('bookmark#','Bookmark','',bookmark) 95 | 96 | def setNote(self,note): 97 | self.addAdditionalFields('notes#','Notes','',note) 98 | 99 | def returnEntity(self): 100 | print "" 101 | print "" + str(self.value) + "" 102 | print "" + str(self.weight) + "" 103 | if (self.displayInformation is not None): 104 | print "" 105 | if (len(self.additionalFields) > 0): 106 | print "" 107 | for i in range(len(self.additionalFields)): 108 | if (str(self.additionalFields[i][2]) <> "strict"): 109 | print "" + str(self.additionalFields[i][3]) + "" 110 | else: 111 | print "" + str(self.additionalFields[i][3]) + "" 112 | print "" 113 | if (len(self.iconURL) > 0): 114 | print "" + self.iconURL + "" 115 | print "" 116 | 117 | class MaltegoTransform(object): 118 | entities = [] 119 | exceptions = [] 120 | UIMessages = [] 121 | values = {} 122 | 123 | def __init__(self): 124 | values = {} 125 | value = None 126 | 127 | def parseArguments(self,argv): 128 | if (argv[1] is not None): 129 | self.value = argv[1] 130 | 131 | if (len(argv) > 2): 132 | if (argv[2] is not None): 133 | vars = argv[2].split('#') 134 | for x in range(0,len(vars)): 135 | vars_values = vars[x].split('=',1) 136 | if (len(vars_values) == 2): 137 | self.values[vars_values[0]] = vars_values[1] 138 | 139 | def getValue(self): 140 | if (self.value is not None): 141 | return self.value 142 | 143 | def getVar(self,varName): 144 | if (varName in self.values.keys()): 145 | if (self.values[varName] is not None): 146 | return self.values[varName] 147 | 148 | def addEntity(self,enType,enValue): 149 | me = MaltegoEntity(enType,enValue) 150 | self.addEntityToMessage(me) 151 | return self.entities[len(self.entities)-1] 152 | 153 | def addEntityToMessage(self,maltegoEntity): 154 | self.entities.append(maltegoEntity) 155 | 156 | def addUIMessage(self,message,messageType="Inform"): 157 | self.UIMessages.append([messageType,message]) 158 | 159 | def addException(self,exceptionString): 160 | self.exceptions.append(exceptionString) 161 | 162 | def throwExceptions(self): 163 | print "" 164 | print "" 165 | print "" 166 | 167 | for i in range(len(self.exceptions)): 168 | print "" + self.exceptions[i] + "" 169 | print "" 170 | print "" 171 | print "" 172 | exit() 173 | 174 | def returnOutput(self): 175 | print "" 176 | print "" 177 | 178 | print "" 179 | for i in range(len(self.entities)): 180 | self.entities[i].returnEntity() 181 | print "" 182 | 183 | print "" 184 | for i in range(len(self.UIMessages)): 185 | print "" + self.UIMessages[i][1] + "" 186 | print "" 187 | 188 | print "" 189 | print "" 190 | 191 | def writeSTDERR(self,msg): 192 | sys.stderr.write(str(msg)) 193 | 194 | def heartbeat(self): 195 | self.writeSTDERR("+") 196 | 197 | def progress(self,percent): 198 | self.writeSTDERR("%" + str(percent)) 199 | 200 | def debug(self,msg): 201 | self.writeSTDERR("D:" + str(msg)) 202 | 203 | 204 | 205 | def sanitise(value): 206 | replace_these = ["&",">","<"] 207 | replace_with = ["&",">","<"] 208 | tempvalue = value 209 | for i in range(0,len(replace_these)): 210 | tempvalue = tempvalue.replace(replace_these[i],replace_with[i]) 211 | return tempvalue -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # crt.sh Maltego Transforms 2 | Maltego Local Transforms for crt.sh 3 | 4 | ## Requirements 5 | - You need to have `requests` and `BeautifulSoup` installed. Which can be done through `pip install requests` and `pip install beautifulsoup` 6 | 7 | ## Installation 8 | - Grab the .mtz file I have hosted on my github, here. 9 | - Import this .mtz file into Maltego, by going to the top-left icon, then Import, then Import Configuration. 10 | - Grab the Python code from my Github for the transforms. You'll grab crtsh.py and MaltegoTransform.py from this repo. 11 | - Put crtsh.py and MaltegoTransform.py into a folder called crtsh 12 | - Move the crtsh folder to `/opt/Maltego` *You'll most likely need to create this folder first* 13 | 14 | ## Using this Transform 15 | Once you import the transform, you'll add a new Website entity to the graph, and enter the domain as the entity name (i.e. nullsecure.org). The transform will search for any other hosts that have certificates under your domain name (i.e. test.nullsecure.org, stuff.nullsecure.org, etc.) 16 | 17 | ## Sample Results 18 | 19 | ![https://i.imgur.com/0Ga8gsS.png](https://i.imgur.com/0Ga8gsS.png) 20 | 21 | That should be all you need to get going, if you run into any issues or have bug reports/issues, please shoot them to me at brian@nullsecure.org, or on twitter @brian_warehime, or file an issue in Github. 22 | 23 | Thanks! 24 | -------------------------------------------------------------------------------- /crtsh.mtz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianwarehime/crt.sh-Maltego-Transforms/163fa1f9ff3aaa6193a71953fb35695f2a5afe86/crtsh.mtz -------------------------------------------------------------------------------- /crtsh.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from bs4 import BeautifulSoup 3 | import re 4 | from MaltegoTransform import * 5 | 6 | me = MaltegoTransform() 7 | me.parseArguments(sys.argv) 8 | 9 | company_name = sys.argv[1] 10 | 11 | r = requests.get('https://crt.sh/?q=%25.' + company_name) 12 | 13 | doc = r.content 14 | 15 | soup = BeautifulSoup(doc, 'html.parser') 16 | 17 | rows = [] 18 | 19 | for link in soup.findAll('td', attrs={'style': None}): 20 | if link.find('a'): 21 | continue 22 | else: 23 | rows.append(link.text) 24 | 25 | regex = re.compile('Identity\sLIKE.*') 26 | end_rows = [x for x in rows if not regex.match(x)] 27 | 28 | new_rows = [] 29 | 30 | for row in end_rows: 31 | if row not in new_rows: 32 | new_rows.append(row) 33 | 34 | for row in new_rows: 35 | ent = me.addEntity("maltego.DNSName",row) 36 | 37 | me.returnOutput() --------------------------------------------------------------------------------