├── .gitignore
├── asset
├── htmlreport.png
└── linkedint.png
├── LinkedInt.cfg
├── requirements.txt
├── banner.txt
├── .github
└── FUNDING.yml
├── LICENSE.md
├── README.md
└── LinkedInt.py
/.gitignore:
--------------------------------------------------------------------------------
1 | LinkedInt.cfg
2 |
--------------------------------------------------------------------------------
/asset/htmlreport.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vysecurity/LinkedInt/HEAD/asset/htmlreport.png
--------------------------------------------------------------------------------
/asset/linkedint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vysecurity/LinkedInt/HEAD/asset/linkedint.png
--------------------------------------------------------------------------------
/LinkedInt.cfg:
--------------------------------------------------------------------------------
1 | [API_KEYS]
2 | hunter =
3 |
4 | [CREDS]
5 | linkedin_username =
6 | linkedin_password =
7 |
8 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | beautifulsoup4==4.6.0
2 | certifi==2018.1.18
3 | chardet==3.0.4
4 | idna==2.6
5 | requests==2.20.0
6 | thready==0.1.5
7 | urllib3==1.26.5
8 |
--------------------------------------------------------------------------------
/banner.txt:
--------------------------------------------------------------------------------
1 | ██╗ ██╗███╗ ██╗██╗ ██╗███████╗██████╗ ██╗███╗ ██╗████████╗
2 | ██║ ██║████╗ ██║██║ ██╔╝██╔════╝██╔══██╗██║████╗ ██║╚══██╔══╝
3 | ██║ ██║██╔██╗ ██║█████╔╝ █████╗ ██║ ██║██║██╔██╗ ██║ ██║
4 | ██║ ██║██║╚██╗██║██╔═██╗ ██╔══╝ ██║ ██║██║██║╚██╗██║ ██║
5 | ███████╗██║██║ ╚████║██║ ██╗███████╗██████╔╝██║██║ ╚████║ ██║
6 | ╚══════╝╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝╚══════╝╚═════╝ ╚═╝╚═╝ ╚═══╝ ╚═╝
7 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [vysecurity]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018-2021 Vincent Yiu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # Sponsor Open Source Tooling
6 |
7 | * Feel free to sponsor me for maintaining the tool: https://github.com/sponsors/vysecurity
8 |
9 | # Disclaimer
10 |
11 | * The project is to be used for educational and testing purposes only.
12 |
13 | # Authors
14 |
15 | * LinkedInt by Vincent Yiu (@vysecurity): https://www.vincentyiu.com | https://vysecurity.rocks
16 | * Original Scraper by Danny Chrastil (@DisK0nn3cT): https://github.com/DisK0nn3cT/linkedin-gatherer
17 |
18 | Contributors:
19 |
20 | * Leesoh
21 | * harshil-shah004
22 |
23 | # Installation
24 | ```
25 | git clone https://github.com/vysecurity/LinkedInt
26 | cd LinkedInt
27 | pip install -r requirements.txt
28 | ```
29 |
30 | # Change Log
31 |
32 | **[v1.1 01-05-2021]**
33 |
34 | Fixes:
35 | * Temporary fix for location field missing
36 |
37 | **[v1.1 27-03-2021]**
38 |
39 | Fixes:
40 | * Fixed the authentication flow
41 | * Fixed hunter API demo key - removed
42 |
43 | Additions:
44 | * Added better looking missing image value for the profiles with no photo.
45 | * Embedded all images into the HTML file to allow for offline viewing.
46 | * Added credits
47 |
48 | **[v0.1 BETA 12-07-2017]**
49 |
50 | Additions:
51 | * UI Updates
52 | * Constrain to company filters
53 | * Addition of Hunter for e-mail prediction
54 |
55 | # Usage
56 |
57 | 1. Put in LinkedIn credentials in LinkedInt.cfg
58 | 2. Put Hunter.io API key in LinkedInt.cfg
59 | 3. Run LinkedInt.py and follow instructions (example below).
60 |
61 | # Example
62 |
63 | Using General Motors as the target as they have a bug bounty program.
64 |
65 | ```
66 | ██╗ ██╗███╗ ██╗██╗ ██╗███████╗██████╗ ██╗███╗ ██╗████████╗
67 | ██║ ██║████╗ ██║██║ ██╔╝██╔════╝██╔══██╗██║████╗ ██║╚══██╔══╝
68 | ██║ ██║██╔██╗ ██║█████╔╝ █████╗ ██║ ██║██║██╔██╗ ██║ ██║
69 | ██║ ██║██║╚██╗██║██╔═██╗ ██╔══╝ ██║ ██║██║██║╚██╗██║ ██║
70 | ███████╗██║██║ ╚████║██║ ██╗███████╗██████╔╝██║██║ ╚████║ ██║
71 | ╚══════╝╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝╚══════╝╚═════╝ ╚═╝╚═╝ ╚═══╝ ╚═╝
72 |
73 | Providing you with Linkedin Intelligence
74 | Author: Vincent Yiu (@vysec, @vysecurity)
75 | Original version by @DisK0nn3cT
76 | [*] Enter search Keywords (use quotes for more precise results)
77 | "General Motors"
78 |
79 | [*] Enter filename for output (exclude file extension)
80 | generalmotors
81 |
82 | [*] Filter by Company? (Y/N):
83 | Y
84 |
85 | [*] Specify a Company ID (Provide ID or leave blank to automate):
86 |
87 |
88 | [*] Enter e-mail domain suffix (eg. contoso.com):
89 | gm.com
90 |
91 | [*] Select a prefix for e-mail generation (auto,full,firstlast,firstmlast,flast,first.last,fmlast):
92 | auto
93 |
94 | [*] Automatically using Hunter IO to determine best Prefix
95 | [!] {first}.{last}
96 | [+] Found first.last prefix
97 | ```
98 |
99 | Output (HTML):
100 |
101 | 
102 |
--------------------------------------------------------------------------------
/LinkedInt.py:
--------------------------------------------------------------------------------
1 | # LinkedInt
2 | # Scrapes LinkedIn without using LinkedIn API
3 | # Original scraper by @DisK0nn3cT (https://github.com/DisK0nn3cT/linkedin-gatherer)
4 | # Modified by @vysecurity
5 | # - Additions:
6 | # --- UI Updates
7 | # --- Constrain to company filters
8 | # --- Addition of Hunter for e-mail prediction
9 |
10 | #!/usr/bin/python3
11 |
12 | import sys
13 | import re
14 | import time
15 | import requests
16 | import subprocess
17 | import json
18 | import argparse
19 | import http.cookiejar
20 | import configparser
21 | import os
22 | import base64
23 | import urllib
24 | import math
25 | from urllib.request import urlopen
26 | import string
27 | from bs4 import BeautifulSoup
28 | import urllib.parse
29 |
30 | baseDir = os.path.dirname(os.path.realpath(sys.argv[0])) + os.path.sep
31 |
32 | """ Setup Argument Parameters """
33 | parser = argparse.ArgumentParser(description='Discovery LinkedIn')
34 | parser.add_argument('-u', '--keywords', help='Keywords to search')
35 | parser.add_argument('-o', '--output', help='Output file (do not include extensions)')
36 | args = parser.parse_args()
37 | config = configparser.RawConfigParser()
38 | config.read(baseDir + 'LinkedInt.cfg')
39 | api_key = config.get('API_KEYS', 'hunter')
40 | username = config.get('CREDS', 'linkedin_username')
41 | password = config.get('CREDS', 'linkedin_password')
42 |
43 |
44 | def getCookies(cookie_jar, domain):
45 | cookie_dict = cookie_jar.get_dict(domain=domain)
46 | found = ['%s=%s' % (name, value) for (name, value) in cookie_dict.items()]
47 | return '; '.join(found)
48 |
49 | def login():
50 | URL = 'https://www.linkedin.com'
51 | s = requests.Session()
52 | rv = s.get(URL + '/uas/login?trk=guest_homepage-basic_nav-header-signin')
53 | p = BeautifulSoup(rv.content, "html.parser")
54 |
55 |
56 | ac = p.find(attrs={'name' : 'ac'})['value']
57 | parentPageKey = p.find(attrs={'name' : 'parentPageKey'})['value']
58 | pageInstance = "urn:li:page:d_checkpoint_lg_consumerLogin;"
59 | trk = p.find(attrs={'name' : 'trk'})['value']
60 | authUUID = p.find(attrs={'name' : 'authUUID'})['value']
61 | session_redirect = p.find(attrs={'name' : 'session_redirect'})['value']
62 | fp_data = p.find(attrs={'name' : 'fp_data'})['value']
63 | apfc = p.find(attrs={'name' : 'apfc'})['value']
64 | dval = p.find(attrs={'name' : '_d'})['value']
65 | showGoogleOneTapLogin = p.find(attrs={'name' : 'showGoogleOneTapLogin'})['value']
66 |
67 |
68 | csrf = p.find(attrs={'name' : 'loginCsrfParam'})['value']
69 | csrf_token = p.find(attrs={'name':'csrfToken'})['value']
70 | sid_str = p.find(attrs={'name':'sIdString'})['value']
71 |
72 | postdata = {'csrfToken':csrf_token,
73 | 'session_key':username, 'ac':ac,
74 | 'sIdString':sid_str, 'parentPageKey':parentPageKey, 'pageInstance':pageInstance, 'trk':trk, 'authUUID':authUUID, 'session_redirect':session_redirect,
75 | 'loginCsrfParam':csrf, 'fp_data':fp_data, 'apfc':apfc, '_d':dval, 'showGoogleOneTapLogin':showGoogleOneTapLogin, 'controlId': 'd_checkpoint_lg_consumerLogin-login_submit_button',
76 | 'session_password':password, 'loginFlow':'REMEMBER_ME_OPTIN'
77 | }
78 | #print(postdata)
79 | rv = s.post(URL + '/checkpoint/lg/login-submit', data=postdata)
80 | #print(rv.text)
81 | if ("behaviour that can result in restriction" in rv.text):
82 | print("[!] Your account is restricted, fix it before continuing")
83 | sys.exit(0)
84 | try:
85 | #print(s.cookies)
86 | cookie = getCookies(s.cookies, ".www.linkedin.com")
87 |
88 | except:
89 | print("[!] Cannot login")
90 | sys.exit(0)
91 | return cookie
92 |
93 | def get_search():
94 |
95 | body = ""
96 | csv = []
97 | css = """
121 |
122 | """
123 |
124 | header = """
125 |
126 |
127 |
LinkedInt Version 1.1 - Developed by Vincent Yiu (@vysecurity)
128 | The tool is developed for testing and educational purposes only.
129 | GitHub Sponsor Link (to support educational content): https://github.com/sponsors/vysecurity
130 |
131 |
132 | | Photo |
133 | Name |
134 | Possible Email: |
135 | Job |
136 | Location |
137 |
138 | """
139 |
140 | if bCompany:
141 | if bAuto:
142 | companyID = 0
143 | url = "https://www.linkedin.com/voyager/api/typeahead/hits?q=blended&query=%s" % search
144 | headers = {'Csrf-Token':'ajax:0397788525211216810', 'X-RestLi-Protocol-Version':'2.0.0'}
145 | cookies['JSESSIONID'] = 'ajax:0397788525211216810'
146 | r = requests.get(url, cookies=cookies, headers=headers)
147 | content = json.loads(r.text)
148 | firstID = 0
149 | for i in range(0,len(content['elements'])):
150 | try:
151 | companyID = content['elements'][i]['hitInfo']['com.linkedin.voyager.typeahead.TypeaheadCompany']['id']
152 | if firstID == 0:
153 | firstID = companyID
154 | print("[Notice] Found company ID: %s" % companyID)
155 | except:
156 | continue
157 | companyID = firstID
158 | if companyID == 0:
159 | print("[WARNING] No valid company ID found in auto, please restart and find your own")
160 | else:
161 | companyID = bSpecific
162 |
163 | print("")
164 |
165 | print("[*] Using company ID: %s" % companyID)
166 |
167 | if bCompany == False:
168 | url = "https://www.linkedin.com/voyager/api/search/cluster?count=40&guides=List()&keywords=%s&origin=OTHER&q=guided&start=0" % search
169 | else:
170 | url = "https://www.linkedin.com/voyager/api/search/cluster?count=40&guides=List(v->PEOPLE,facetCurrentCompany->%s)&origin=OTHER&q=guided&start=0" % (companyID)
171 |
172 | print(url)
173 |
174 | headers = {'Csrf-Token':'ajax:0397788525211216808', 'X-RestLi-Protocol-Version':'2.0.0'}
175 | cookies['JSESSIONID'] = 'ajax:0397788525211216808'
176 | r = requests.get(url, cookies=cookies, headers=headers)
177 | content = json.loads(r.text)
178 | data_total = content['elements'][0]['total']
179 |
180 | pages = int(math.ceil(data_total / 40.0))
181 |
182 | if pages == 0:
183 | pages = 1
184 |
185 | if data_total % 40 == 0:
186 | pages = pages - 1
187 |
188 | if pages == 0:
189 | print("[!] Try to use quotes in the search name")
190 | sys.exit(0)
191 |
192 | print("[*] %i Results Found" % data_total)
193 | if data_total > 1000:
194 | pages = 25
195 | print("[*] LinkedIn only allows 1000 results. Refine keywords to capture all data")
196 | print("[*] Fetching %i Pages" % pages)
197 | print("")
198 |
199 | for p in range(pages):
200 | if bCompany == False:
201 | url = "https://www.linkedin.com/voyager/api/search/cluster?count=40&guides=List()&keywords=%s&origin=OTHER&q=guided&start=%i" % (search, p*40)
202 | else:
203 | url = "https://www.linkedin.com/voyager/api/search/cluster?count=40&guides=List(v->PEOPLE,facetCurrentCompany->%s)&origin=OTHER&q=guided&start=%i" % (companyID, p*40)
204 | r = requests.get(url, cookies=cookies, headers=headers)
205 | content = r.text.encode('UTF-8')
206 | content = json.loads(content)
207 | print("[*] Fetching page %i with %i results" % ((p),len(content['elements'][0]['elements'])))
208 | for c in content['elements'][0]['elements']:
209 | if 'com.linkedin.voyager.search.SearchProfile' in c['hitInfo'] and c['hitInfo']['com.linkedin.voyager.search.SearchProfile']['headless'] == False:
210 | try:
211 | data_industry = c['hitInfo']['com.linkedin.voyager.search.SearchProfile']['industry']
212 | except:
213 | data_industry = ""
214 | data_firstname = c['hitInfo']['com.linkedin.voyager.search.SearchProfile']['miniProfile']['firstName']
215 | data_lastname = c['hitInfo']['com.linkedin.voyager.search.SearchProfile']['miniProfile']['lastName']
216 | data_slug = "https://www.linkedin.com/in/%s" % c['hitInfo']['com.linkedin.voyager.search.SearchProfile']['miniProfile']['publicIdentifier']
217 | data_occupation = c['hitInfo']['com.linkedin.voyager.search.SearchProfile']['miniProfile']['occupation']
218 | data_location = "" #c['hitInfo']['com.linkedin.voyager.search.SearchProfile']['location']
219 | try:
220 | data_picture = "%s%s" % (c['hitInfo']['com.linkedin.voyager.search.SearchProfile']['miniProfile']['picture']['com.linkedin.common.VectorImage']['rootUrl'],c['hitInfo']['com.linkedin.voyager.search.SearchProfile']['miniProfile']['picture']['com.linkedin.common.VectorImage']['artifacts'][2]['fileIdentifyingUrlPathSegment'])
221 | except:
222 | print("[*] No picture found for %s %s, %s" % (data_firstname, data_lastname, data_occupation))
223 | data_picture = ""
224 |
225 |
226 |
227 | parts = data_lastname.split()
228 |
229 | name = data_firstname + " " + data_lastname
230 | fname = ""
231 | mname = ""
232 | lname = ""
233 |
234 | if len(parts) == 1:
235 | fname = data_firstname
236 | mname = '?'
237 | lname = parts[0]
238 | elif len(parts) == 2:
239 | fname = data_firstname
240 | mname = parts[0]
241 | lname = parts[1]
242 | elif len(parts) >= 3:
243 | fname = data_firstname
244 | lname = parts[0]
245 | else:
246 | fname = data_firstname
247 | lname = '?'
248 |
249 | fname = re.sub('[^A-Za-z]+', '', fname)
250 | mname = re.sub('[^A-Za-z]+', '', mname)
251 | lname = re.sub('[^A-Za-z]+', '', lname)
252 |
253 | if len(fname) == 0 or len(lname) == 0:
254 | continue
255 |
256 |
257 |
258 | if prefix == 'full':
259 | user = '{}{}{}'.format(fname, mname, lname)
260 | if prefix == 'firstlast':
261 | user = '{}{}'.format(fname, lname)
262 | if prefix == 'firstmlast':
263 | if len(mname) == 0:
264 | user = '{}{}{}'.format(fname, mname, lname)
265 | else:
266 | user = '{}{}{}'.format(fname, mname[0], lname)
267 | if prefix == 'flast':
268 | user = '{}{}'.format(fname[0], lname)
269 | if prefix == 'firstl':
270 | user = '{}{}'.format(fname,lname[0])
271 | if prefix == 'first.last':
272 | user = '{}.{}'.format(fname, lname)
273 | if prefix == 'first_last':
274 | user = '{}_{}'.format(fname, lname)
275 | if prefix == 'fmlast':
276 | if len(mname) == 0:
277 | user = '{}{}{}'.format(fname[0], mname, lname)
278 | else:
279 | user = '{}{}{}'.format(fname[0], mname[0], lname)
280 | if prefix == 'lastfirst':
281 | user = '{}{}'.format(lname, fname)
282 | if prefix == 'first':
283 | user = '{}'.format(fname)
284 |
285 |
286 | email = '{}@{}'.format(user, suffix)
287 | ct = ""
288 | if ("http" in data_picture):
289 |
290 | data = requests.get(data_picture)
291 | b64data = base64.b64encode(data.content).decode('ascii')
292 | ct = data.headers['Content-Type']
293 | else:
294 | b64data = "/9j/4AAQSkZJRgABAQEBLAEsAAD/4QCFRXhpZgAASUkqAAgAAAABAA4BAgBjAAAAGgAAAAAAAABNYWxlIGZhY2Ugc2lsaG91ZXR0ZSBvciBpY29uLiBNYW4gYXZhdGFyIHByb2ZpbGUuIFVua25vd24gb3IgYW5vbnltb3VzIHBlcnNvbi4gVmVjdG9yIGlsbHVzdHJhdGlvbi7/4QWLaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/Pgo8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIj4KCTxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CgkJPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczpJcHRjNHhtcENvcmU9Imh0dHA6Ly9pcHRjLm9yZy9zdGQvSXB0YzR4bXBDb3JlLzEuMC94bWxucy8iICAgeG1sbnM6R2V0dHlJbWFnZXNHSUZUPSJodHRwOi8veG1wLmdldHR5aW1hZ2VzLmNvbS9naWZ0LzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGx1cz0iaHR0cDovL25zLnVzZXBsdXMub3JnL2xkZi94bXAvMS4wLyIgIHhtbG5zOmlwdGNFeHQ9Imh0dHA6Ly9pcHRjLm9yZy9zdGQvSXB0YzR4bXBFeHQvMjAwOC0wMi0yOS8iIHhtbG5zOnhtcFJpZ2h0cz0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3JpZ2h0cy8iIHBob3Rvc2hvcDpDcmVkaXQ9IkdldHR5IEltYWdlcy9pU3RvY2twaG90byIgR2V0dHlJbWFnZXNHSUZUOkFzc2V0SUQ9IjEwODc1MzE2NDIiIHhtcFJpZ2h0czpXZWJTdGF0ZW1lbnQ9Imh0dHBzOi8vd3d3LmlzdG9ja3Bob3RvLmNvbS9sZWdhbC9saWNlbnNlLWFncmVlbWVudD91dG1fbWVkaXVtPW9yZ2FuaWMmYW1wO3V0bV9zb3VyY2U9Z29vZ2xlJmFtcDt1dG1fY2FtcGFpZ249aXB0Y3VybCIgPgo8ZGM6Y3JlYXRvcj48cmRmOlNlcT48cmRmOmxpPlZpY3RvciBNZXRlbHNraXk8L3JkZjpsaT48L3JkZjpTZXE+PC9kYzpjcmVhdG9yPjxkYzpkZXNjcmlwdGlvbj48cmRmOkFsdD48cmRmOmxpIHhtbDpsYW5nPSJ4LWRlZmF1bHQiPk1hbGUgZmFjZSBzaWxob3VldHRlIG9yIGljb24uIE1hbiBhdmF0YXIgcHJvZmlsZS4gVW5rbm93biBvciBhbm9ueW1vdXMgcGVyc29uLiBWZWN0b3IgaWxsdXN0cmF0aW9uLjwvcmRmOmxpPjwvcmRmOkFsdD48L2RjOmRlc2NyaXB0aW9uPgo8cGx1czpMaWNlbnNvcj48cmRmOlNlcT48cmRmOmxpIHJkZjpwYXJzZVR5cGU9J1Jlc291cmNlJz48cGx1czpMaWNlbnNvclVSTD5odHRwczovL3d3dy5pc3RvY2twaG90by5jb20vcGhvdG8vbGljZW5zZS1nbTEwODc1MzE2NDItP3V0bV9tZWRpdW09b3JnYW5pYyZhbXA7dXRtX3NvdXJjZT1nb29nbGUmYW1wO3V0bV9jYW1wYWlnbj1pcHRjdXJsPC9wbHVzOkxpY2Vuc29yVVJMPjwvcmRmOmxpPjwvcmRmOlNlcT48L3BsdXM6TGljZW5zb3I+CgkJPC9yZGY6RGVzY3JpcHRpb24+Cgk8L3JkZjpSREY+CjwveDp4bXBtZXRhPgo8P3hwYWNrZXQgZW5kPSJ3Ij8+Cv/tALZQaG90b3Nob3AgMy4wADhCSU0EBAAAAAAAmhwCUAAQVmljdG9yIE1ldGVsc2tpeRwCeABjTWFsZSBmYWNlIHNpbGhvdWV0dGUgb3IgaWNvbi4gTWFuIGF2YXRhciBwcm9maWxlLiBVbmtub3duIG9yIGFub255bW91cyBwZXJzb24uIFZlY3RvciBpbGx1c3RyYXRpb24uHAJuABhHZXR0eSBJbWFnZXMvaVN0b2NrcGhvdG//2wBDAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEm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AQAAAAAAAAAAAAAAQAAAATbbbbbbbbbbbbaAAAAAAAAAAAAAAAAAAACAAAAAbbbbbbbbbbbbbQAAAAAAAAAAAAAAAAAACAAAAADbbbbbbbbbbbbKAAAAAAAAAAAAAAAAAAAQAAAAAbbbbbbbbbbbbbQAAAAAAAAAAAAAAAAAAQAAAAADbbbbbbbbbbbbLAAAAACAAAAAAAAAAAAAAAAAACbbbbbbbbbbbbbIAAAAAQAAAAAAAAAAAAQAAAAATbbbbbbbbbbbbbAAAAAAAAAAAAAAAAAASAAAAACbbbbbbbbbbbbbAAAAAACAAAAAAAAAAAAAAAAAADbbbbbbbbbbbbaAAAAAAAAAAAAAAAAAAAAAAAAATbbbbbbbbbbbbQAAAAACQAAAAAAAAAAAAAAAAACbbbbbbbbbbbbaAAAAAACAAAAAAAAAAAAAAAAAABbbbbbbbbbbbYAAAAAAAQAAAAAAAAAACAAAAAAACbbbbbbbbbbaAAAAAAAAAAAAAAAAAAAQAAAAAAADbbbbbbbbbaAAAAAAAAAAAAAAAAAAAQAAAAAAAAbbbbbbbbbbQAAAAAAACAAAAAAAAAACAAAAAAAACbbbbbbbbbaAAAAAAAAQAAAAAAAAAACAAAAAAAATbbbbbbbbZAAAAAAAAAAAAAAAAAAAAAAAAAAAACLbbbbbbbbAAAAAAAAAAAAAAAAAAAACAAAAAAAAAbbbbbbbbYAAAAAAAAAAAAAAAAAAAAQAAAAAAAADbbbbbbbYAAAAAAAAAAAAAAAAAAAACAAAAAAAAALbbbbbbbQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbbbbbbbaAAAAAAAACAAAAAAAAAAACAAAAAAAAAbbbbbbbbIAAAAAAAAQAAAAAAAAAAACAAAAAAAAbbbbbbbbZSAAAAAAAAAAAAAAAAAAAAAAAAAAATbbbbbbbbbbKAAAAAACAAAAAAAAAAAACAAAAAALbbbbbbbbbbbbAAAAAAQAAAAAAAAAAAACAAACRbbbbbbbbbbbbbbLQAAASAAAAAAAAAAAAASAABbbbbbbbbbbbbbbbbbYAACAAAAAAAAAAAAAAAQLbbbbbbbbbbbbbbbbbbbAAQAAAAAAAAAAAAACRbbbbbbbbbbbbbbbbbbbbbJQAAAAAAAAAAAAAAAbbbbbbbbbbbbbbbbbbbbbbYAAAAA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"
295 | ct = "image/jpeg"
296 | body += "" \
297 | " | " \
298 | "%s | " \
299 | "%s | " \
300 | "%s | " \
301 | "%s | " \
302 | "" % (data_slug, ct ,b64data, data_slug, name, email, data_occupation, data_location)
303 |
304 | csv.append('"%s","%s","%s","%s","%s", "%s"' % (data_firstname, data_lastname, name, email, data_occupation, data_location.replace(",",";")))
305 | foot = "
"
306 | f = open(baseDir + '{}.html'.format(outfile), 'wb')
307 | f.write(css.encode())
308 | f.write(header.encode())
309 | f.write(body.encode())
310 | f.write(foot.encode())
311 | f.close()
312 | f = open(baseDir + '{}.csv'.format(outfile), 'wb')
313 | newcsv='\n'.join(csv)
314 | f.write(newcsv.encode())
315 | for x in csv:
316 | f.write(x.join('\n').encode())
317 | f.close()
318 | else:
319 | print("[!] Headless profile found. Skipping")
320 | print("")
321 | def authenticate():
322 | try:
323 | a = login()
324 | session = a
325 | if len(session) == 0:
326 | sys.exit("[!] Unable to login to LinkedIn.com")
327 | print("[*] Obtained new session")
328 | cookies = dict(li_at=session)
329 | except Exception:
330 | sys.exit("[!] Could not authenticate to linkedin. %s" % e)
331 | return cookies
332 |
333 | if __name__ == '__main__':
334 | print("")
335 | a = open(baseDir + "banner.txt","r")
336 | print(a.read())
337 | a.close()
338 | print("")
339 | print("Version: 1.1 FIXED - March 27, 2021")
340 | print("Author: Vincent Yiu @vysecurity")
341 | print("")
342 | search = args.keywords if args.keywords!=None else input("[*] Enter search Keywords (use quotes for more precise results)\n")
343 | print("")
344 | outfile = args.output if args.output!=None else input("[*] Enter filename for output (exclude file extension)\n")
345 | print("")
346 | while True:
347 | bCompany = input("[*] Filter by Company? (Y/N): \n")
348 | if bCompany.lower() == "y" or bCompany.lower() == "n":
349 | break
350 | else:
351 | print("[!] Incorrect choice")
352 |
353 | if bCompany.lower() == "y":
354 | bCompany = True
355 | else:
356 | bCompany = False
357 |
358 | bAuto = True
359 | bSpecific = 0
360 | prefix = ""
361 | suffix = ""
362 |
363 | print("")
364 |
365 | if bCompany:
366 | while True:
367 | bSpecific = input("[*] Specify a Company ID (Provide ID or leave blank to automate): \n")
368 | if bSpecific != "":
369 | bAuto = False
370 | if bSpecific != 0:
371 | try:
372 | int(bSpecific)
373 | break
374 | except:
375 | print("[!] Incorrect choice, the ID either has to be a number or blank")
376 |
377 | else:
378 | print("[!] Incorrect choice, the ID either has to be a number or blank")
379 | else:
380 | bAuto = True
381 | break
382 |
383 | print("")
384 |
385 |
386 | while True:
387 | suffix = input("[*] Enter e-mail domain suffix (eg. contoso.com): \n")
388 | suffix = suffix.lower()
389 | if "." in suffix:
390 | break
391 | else:
392 | print("[!] Incorrect e-mail? There's no dot")
393 |
394 | print("")
395 |
396 | while True:
397 | prefix = input("[*] Select a prefix for e-mail generation (auto,full,firstlast,firstmlast,flast,firstl,first.last,fmlast,lastfirst,first): \n")
398 | prefix = prefix.lower()
399 | print("")
400 | if prefix == "full" or prefix == "firstlast" or prefix == "firstmlast" or prefix == "flast" or prefix == "firstl" or prefix =="first" or prefix == "first_last"or prefix == "first.last" or prefix == "fmlast" or prefix == "lastfirst":
401 | break
402 | elif prefix == "auto":
403 | print("[*] Automatically using Hunter IO to determine best Prefix")
404 | url = "https://api.hunter.io/v2/domain-search?domain=%s&api_key=%s" % (suffix, api_key)
405 | r = requests.get(url)
406 | content = json.loads(r.text)
407 | if "status" in content:
408 | print("[!] Rate limited by Hunter IO Key")
409 | continue
410 | prefix = content['data']['pattern']
411 | print("[!] %s" % prefix)
412 | if prefix:
413 | prefix = prefix.replace("{","").replace("}", "")
414 | if prefix == "full" or prefix == "firstlast" or prefix == "firstmlast" or prefix == "flast" or prefix == "firstl" or prefix =="first" or prefix == "first.last" or prefix == "fmlast" or prefix == "lastfirst":
415 | print("[+] Found %s prefix" % prefix)
416 | break
417 | else:
418 | print("[!] Automatic prefix search failed, please insert a manual choice")
419 | continue
420 | else:
421 | print("[!] Automatic prefix search failed, please insert a manual choice")
422 | continue
423 | else:
424 | print("[!] Incorrect choice, please select a value from (auto,full,firstlast,firstmlast,flast,firstl,first.last,fmlast)")
425 |
426 | print("")
427 |
428 | search = urllib.parse.quote_plus(search)
429 | cookies = authenticate()
430 |
431 | get_search()
432 |
433 | print("[+] Complete")
434 |
--------------------------------------------------------------------------------