Skip to content

Commit 668ba9c

Browse files
committed
initial commit
moved InSpy from Pentesting-Scripts
0 parents  commit 668ba9c

File tree

3 files changed

+308
-0
lines changed

3 files changed

+308
-0
lines changed

InSpy.py

+194
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
#!/usr/bin/env python2
2+
3+
# InSpy - A LinkedIn employee enumerator
4+
# This script enumerates employees from any organization
5+
# using LinkedIn. Please note that this will not harvest all
6+
# employees within a given organization.
7+
#
8+
# This program is free software: you can redistribute it and/or modify
9+
# it under the terms of the GNU General Public License as published by
10+
# the Free Software Foundation, either version 3 of the License, or
11+
# (at your option) any later version.
12+
#
13+
# This program is distributed in the hope that it will be useful,
14+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
# GNU General Public License for more details.
17+
#
18+
# You should have received a copy of the GNU General Public License
19+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
#
21+
# Author: Jonathan Broche
22+
# Contact: @g0jhonny
23+
# Version: 1.0.1
24+
# Date: 2015-11-22
25+
#
26+
# usage: ./inspy.py -c <company> [-d dept/title] [-e email output format] [-i input file with dept/titles] [-o output file]
27+
# example: ./inspy.py -c abc -e flast@abc.com -o abc_employees.txt
28+
29+
30+
import requests, BeautifulSoup, argparse, signal, time, datetime, os
31+
32+
start_time = time.time()
33+
34+
class colors:
35+
lightblue = "\033[1;36m"
36+
blue = "\033[1;34m"
37+
normal = "\033[0;00m"
38+
red = "\033[1;31m"
39+
yellow = "\033[1;33m"
40+
white = "\033[1;37m"
41+
green = "\033[1;32m"
42+
43+
#----------------------------------------#
44+
# HARVEST USERS #
45+
#----------------------------------------#
46+
47+
def inspy_enum(company, dept, ifile):
48+
try:
49+
dept_dictionary = ['sales', 'marketing', 'human resources', 'finance', 'accounting', 'inventory', 'quality assurance', 'insurance', 'licenses', 'operational', 'customer service', 'staff', 'research & development', 'management', 'administration', 'engineering', 'it', 'is', 'strategy', 'other']
50+
51+
employees = {}
52+
53+
if dept is not None:
54+
dept_dictionary = [dept.lower()]
55+
56+
if ifile is not None:
57+
try:
58+
if os.path.exists(ifile):
59+
with open(ifile, 'r') as f:
60+
dept_dictionary = []
61+
for line in f.readlines():
62+
if line.rstrip():
63+
dept_dictionary.append(line.rstrip())
64+
except IOError as e:
65+
print "{}[!]{} Problem opening the file. {}".format(e)
66+
67+
for dd in dept_dictionary:
68+
print "{}[*]{} Searching for employees working at {} with '{}' in their title".format(colors.lightblue, colors.normal, company, dd)
69+
70+
try:
71+
response = requests.get('https://www.linkedin.com/title/{}-at-{}'.format(dd.replace('-', ' '), company.replace('-', ' ')), timeout=2)
72+
if response.status_code == 200:
73+
soup = BeautifulSoup.BeautifulSoup(response.text)
74+
else:
75+
pass
76+
except requests.exceptions.Timeout:
77+
print "{}[!]{} Timeout enumerating the {} department".format(colors.red, colors.normal, dd)
78+
except requests.exceptions.ConnectionError:
79+
print "{}[!]{} Connection error.".format(colors.red, colors.normal)
80+
except requests.exceptions.HTTPError:
81+
print "{}[!]{} HTTP error.".format(colors.red, colors.normal)
82+
83+
#get employee names
84+
for n, t in zip(soup.findAll('h3', { "class" : "name" }), soup.findAll('p', { "class" : "headline" })):
85+
name = u''.join(n.getText()).encode('utf-8')
86+
title = u''.join(t.getText()).encode('utf-8').replace('&amp;', '&')
87+
88+
if not name in employees:
89+
employees[name] = title
90+
91+
return employees
92+
except Exception as e:
93+
print "{}[!]{} Error harvesting users. {}".format(colors.red, colors.normal, e)
94+
95+
#----------------------------------------#
96+
# EMAILS #
97+
#----------------------------------------#
98+
99+
def format_email(names, eformat):
100+
emails = []
101+
for name in names:
102+
spaces = []
103+
for x,y in enumerate(name):
104+
if ' ' in y:
105+
spaces.append(x)
106+
107+
if eformat[:eformat.find('@')] == 'flast':
108+
emails.append('{}{}{}'.format(name[0], name[(spaces[-1]+1):], eformat[eformat.find('@'):]))
109+
elif eformat[:eformat.find('@')] == 'lfirst':
110+
emails.append('{}{}{}'.format(name[spaces[-1]+1], name[0:spaces[0]], eformat[eformat.find('@'):]))
111+
elif eformat[:eformat.find('@')] == 'first.last':
112+
emails.append('{}.{}{}'.format(name[0:spaces[0]], name[(spaces[-1]+1):], eformat[eformat.find('@'):]))
113+
elif eformat[:eformat.find('@')] == 'last.first':
114+
emails.append('{}.{}{}'.format(name[(spaces[-1]+1):], name[0:spaces[0]], eformat[eformat.find('@'):]))
115+
116+
return [e.lower() for e in emails]
117+
118+
#----------------------------------------#
119+
# OUTPUT #
120+
#----------------------------------------#
121+
122+
def output(employees, email, company, ofile):
123+
counter = 0
124+
ge, be = {}, {}
125+
print '\n'
126+
127+
if email:
128+
for k, e in zip(employees, email):
129+
if company in employees[k].lower():
130+
if ',' in k:
131+
be[e] = '{}, {}'.format(k, employees[k])
132+
else:
133+
ge[e] = '{}, {}'.format(k, employees[k])
134+
print "{}[*]{} {}, {}, {}".format(colors.green, colors.normal, k.replace('&amp;', '&'), employees[k].replace('&amp;', '&'), e)
135+
counter +=1
136+
else:
137+
for k in employees:
138+
if company in employees[k].lower():
139+
ge[k] = employees[k]
140+
print "{}[*]{} {} {}".format(colors.green, colors.normal, k.replace('&amp;', '&'), employees[k].replace('&amp;', '&'))
141+
counter +=1
142+
if be:
143+
print "\n{}[!]{} The following employees have commas in their names. Their emails were not accurate.".format(colors.red, colors.normal)
144+
for k in be:
145+
print "{}[*]{} {}".format(colors.yellow, colors.normal, be[k])
146+
147+
if ofile:
148+
with open(ofile, 'w') as f:
149+
f.write("\n" + "-" * 69 + "\n" + "InSpy Output" + "\n" + "-" * 69 + "\n\n")
150+
151+
if [e for e in ge.keys() if '@' in e]: #if emails in keys
152+
f.write("\n" + "E-mails" + "\n" + "-" * 25 + "\n\n")
153+
for k in ge.keys():
154+
f.write(k+'\n')
155+
156+
f.write("\n" + "All" + "\n" + "-" * 25 + "\n\n")
157+
for k in ge:
158+
f.write('{}, {}\n'.format(ge[k], k))
159+
else:
160+
for k in ge:
161+
f.write('{}, {}\n'.format(k, ge[k]))
162+
163+
print "\n{}[*]{} Done! {}{}{} employees found.".format(colors.lightblue, colors.normal, colors.green, counter, colors.normal)
164+
print "{}[*]{} Completed in {:.1f}s\n".format(colors.lightblue, colors.normal, time.time()-start_time)
165+
166+
#----------------------------------------#
167+
# MAIN #
168+
#----------------------------------------#
169+
170+
def main():
171+
print "\n " + "-" * 74 + "\n " + colors.white + "InSpy v1.0 - LinkedIn Employee Enumerator by Jonathan Broche (@g0jhonny)\n " + colors.normal + "-" * 74 + "\n "
172+
parser = argparse.ArgumentParser(description='InSpy - A LinkedIn employee enumerator by Jonathan Broche (@g0jhonny)')
173+
parser.add_argument('-c', '--company', required=True, help='Company name')
174+
parser.add_argument('-d', '--dept', nargs='?', const='', help='Department or title to query employees against. Inspy searches through a predefined list by default.')
175+
parser.add_argument('-e', '--emailformat', help='Email output format. Acceptable formats: first.last@xyz.com, last.first@xyz.com, flast@xyz.com, lastf@xyz.com')
176+
parser.add_argument('-i', '--inputfilename', nargs='?', const='', help='File with list of departments or titles to query employees against (one item per line)')
177+
parser.add_argument('-o', '--outfilename', nargs='?', const='', help='Output results to text file')
178+
args = parser.parse_args()
179+
180+
employees = inspy_enum(args.company, args.dept, args.inputfilename)
181+
182+
if args.emailformat:
183+
if args.emailformat.find('@') and args.emailformat[:args.emailformat.find('@')] in {'flast', 'lfirst', 'first.last', 'last.first'}:
184+
if employees is not None:
185+
e = format_email(employees.keys(), args.emailformat)
186+
output(employees, e,args.company.lower(), args.outfilename)
187+
else:
188+
print "{}[!]{} Please provide a valid email address format (i.e., flast@xyz.com, lfirst@xyz.com, first.last@xyz.com, last.first@xyz.com)".format(colors.red, colors.normal)
189+
else:
190+
if employees is not None:
191+
output(employees,'',args.company.lower(), args.outfilename)
192+
193+
if __name__ == '__main__':
194+
main()

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2016 Jonathan Broche
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.

README.md

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# InSpy
2+
3+
A python based LinkedIn employee enumerator. This script is great for social engineering assessments where clients ask one
4+
to provide employee emails.
5+
6+
### Help
7+
8+
```
9+
InSpy - A LinkedIn employee enumerator by Jonathan Broche (@g0jhonny)
10+
11+
optional arguments:
12+
-h, --help show this help message and exit
13+
-c COMPANY, --company COMPANY
14+
Company name
15+
-d [DEPT], --dept [DEPT]
16+
Department or title to query employees against. Inspy
17+
searches through a predefined list by default.
18+
-e EMAILFORMAT, --emailformat EMAILFORMAT
19+
Email output format. Acceptable formats:
20+
first.last@xyz.com, last.first@xyz.com, flast@xyz.com,
21+
lastf@xyz.com
22+
-i [INPUTFILENAME], --inputfilename [INPUTFILENAME]
23+
File with list of departments or titles to query
24+
employees against (one item per line)
25+
-o [OUTFILENAME], --outfilename [OUTFILENAME]
26+
Output results to text file
27+
```
28+
### Examples
29+
30+
```
31+
./InSpy.py -c "acme corp"
32+
33+
--------------------------------------------------------------------------
34+
InSpy v1.0 - LinkedIn User Enumerator by Jonathan Broche (@g0jhonny)
35+
--------------------------------------------------------------------------
36+
37+
[*] Searching for employees working at acme corp with 'sales' in their title
38+
[*] Searching for employees working at acme corp with 'hr' in their title
39+
[*] Searching for employees working at acme corp with 'marketing' in their title
40+
[*] Searching for employees working at acme corp with 'finance' in their title
41+
[*] Searching for employees working at acme corp with 'accounting' in their title
42+
[*] Searching for employees working at acme corp with 'director' in their title
43+
[*] Searching for employees working at acme corp with 'administrative' in their title
44+
[*] Searching for employees working at acme corp with 'lawyer' in their title
45+
[*] Searching for employees working at acme corp with 'it' in their title
46+
[*] Searching for employees working at acme corp with 'security' in their title
47+
48+
49+
[*] Proud Arkie Accounts Receivable specialist at Acme Corp.
50+
[*] Brian Russo Finance Manager at Acme corp
51+
[*] Paul Samuelson Director of Customer Support at ACME Corp. Production Resources
52+
[*] Steve Smith Developer at Acme Corp
53+
[*] Sarah Rhodes Director of Sales at Acme Corp
54+
[*] Frances Jones Assistant to the Director at Acme Corp
55+
...snip...
56+
57+
[*] Done! 29 employees found.
58+
[*] Completed in 28.7s
59+
```
60+
61+
Provide InSpy with the email format of the respective corporation and it'll output the emails for you.
62+
63+
```
64+
./InSpy.py -c 'acme corp' -e flast@acme.com
65+
66+
--------------------------------------------------------------------------
67+
InSpy v1.0 - LinkedIn User Enumerator by Jonathan Broche (@g0jhonny)
68+
--------------------------------------------------------------------------
69+
70+
[*] Searching for employees working at acme corp with 'sales' in their title
71+
[*] Searching for employees working at acme corp with 'hr' in their title
72+
[*] Searching for employees working at acme corp with 'marketing' in their title
73+
[*] Searching for employees working at acme corp with 'finance' in their title
74+
[*] Searching for employees working at acme corp with 'accounting' in their title
75+
[*] Searching for employees working at acme corp with 'director' in their title
76+
[*] Searching for employees working at acme corp with 'administrative' in their title
77+
[*] Searching for employees working at acme corp with 'lawyer' in their title
78+
[*] Searching for employees working at acme corp with 'it' in their title
79+
[*] Searching for employees working at acme corp with 'security' in their title
80+
81+
82+
[*] Proud Arkie, Accounts Receivable specialist at Acme Corp., parkie@acme.com
83+
[*] Brian Russo, Finance Manager at Acme corp, brusso@acme.com
84+
[*] Paul Samuelson, Director of Customer Support at ACME Corp. Production Resources, psamuelson@acme.com
85+
[*] Steve Smith, Developer at Acme Corp, ssmith@acme.com
86+
[*] Sarah Rhodes, Director of Sales at Acme Corp, srhodes@acme.com
87+
[*] Frances Jones, Assistant to the Director at Acme Corp, fjones@acme.com
88+
...snip...
89+
90+
[*] Done! 29 employees found.
91+
[*] Completed in 29.0s
92+
93+
```

0 commit comments

Comments
 (0)