· 9 years ago · Jan 31, 2017, 06:56 PM
1'''
238a11b99402ab435eb0bc53419bf278e582cb3c3361da5be1b8f69d3bf422470
3
4Welcome back to the resistance. We have another tool for you today.
5
6While we're all busy collecting hosts we thought it might be useful to increase
7the level of automation required for us to keep in touch. Following these keys
8is a pain, no?
9
10This script is called watchtower.py and it will enable us all to keep an eye on
11any pastes that we find interesting.
12
13Don't worry, we'll get back to walrus.db after enough information has been
14collected, but for now we encourage you to try out your new tool. Save this
15paste as watchtower.py and execute the following command:
16
17>>> python watchtower.py help
18
19This will output some basic usage details as follows:
20
21
22python watchtower.py CMD ARGS...
23
24Commands:
25 run -- Begin monitoring
26 help -- Show this
27 list -- List watched phrases
28 add "PHRASE" -- Add a new phrase to be watched
29 remove "PHRASE" -- Remove an existing phrase from being watched
30
31
32For instance, to begin waiting for the next step, use the following commands:
33
34>>> python watchtower.py add 8b09358a233181b4191bc9051323accc99a6d40bc9dcf2d9ac38ee688a26b21d
35>>> python watchtower.py run
36
37
38But feel free to use your new tool for other purposes as well. For instance,
39I'll personally be listening for this short key: 2ae819d1ba5ba04a
40
41You can contact me by including that in your paste (note that Untitled pastes
42are ignored so be sure to give your paste a title). If you'd like a response be
43sure to leave me a key that you're listening on.
44
45In the meantime, keep on collecting, there is work to do.
46'''
47
48try:
49 from bs4 import BeautifulSoup as Soup
50except:
51 print('bs4 (BeautifulSoup) module required:\npip install bs4')
52 exit()
53
54try:
55 from requests import get
56except:
57 print('requests module required:\npip install requests')
58 exit()
59
60from sys import argv
61from time import sleep
62from os import path, makedirs
63
64COMMANDS = {}
65DIRECTORY = './pastes'
66USER_AGENT = 'There must be some kind of way out of here'
67
68def main():
69 args = argv
70 script, args = args[0], args[1:]
71 if not len(args):
72 help()
73 cmd, args = args[0], args[1:]
74 cmd = cmd.replace('-', '').lower()
75 if cmd not in COMMANDS:
76 print('\nUnknown command: ' + cmd)
77 help()
78 COMMANDS[cmd](*args)
79
80def database():
81 '''
82 Return the sqlite db object.
83 '''
84 from sqlite3 import connect
85 db = connect('watchtower.db')
86 cursor = db.cursor()
87 cursor.execute('create table if not exists Phrases (phrase text)')
88 cursor.execute('''
89 create unique index if not exists idx_phrase on Phrases (phrase)
90 ''')
91 return db
92
93def command(name):
94 '''
95 Decorator for defining commands.
96 '''
97 def wrapper(fn):
98 COMMANDS[name] = fn
99 return fn
100 return wrapper
101
102@command('run')
103def run():
104 '''
105 Let's get this party started!
106 '''
107 if not path.exists(DIRECTORY):
108 makedirs(DIRECTORY)
109 last_key = None
110 try:
111 while True:
112 try:
113 last_key = update(last_key)
114 except KeyboardInterrupt as e:
115 raise e
116 except:
117 # Something weird happened... Wait a bit longer.
118 sleep(4)
119 sleep(1)
120 except KeyboardInterrupt:
121 pass
122
123def update(last_key):
124 '''
125 The main update function. Grabs pastes and looks for phrases.
126 '''
127 phrases = list_phrases(silent=True)
128 if len(phrases) == 0:
129 return last_key
130 next_key = None
131 headers = {'User-Agent': USER_AGENT}
132 pastes = recent_pastes()
133 for paste in pastes:
134 key = paste['key']
135 if next_key is None:
136 next_key = key
137 if last_key == key:
138 break
139 if paste['title'] == 'Untitled':
140 # Ignore Untitled pastes
141 continue
142 req = get('http://pastebin.com/raw/' + key, headers=headers)
143 text = req.text
144 # Phrase could be in title too, just combine these
145 title_text = paste['title'] + text
146 if any(phrase in title_text for phrase in phrases):
147 paste['text'] = text
148 keep(paste)
149 if next_key is None:
150 next_key = last_key
151 return next_key
152
153def keep(paste):
154 '''
155 Keep a paste.
156 '''
157 print(paste['key'])
158 filename = '{}_{}'.format(paste['key'], paste['title'])
159 fp = open(path.join(DIRECTORY, filename), 'wb')
160 fp.write(paste['text'].encode('utf8'))
161 fp.close()
162
163def recent_pastes():
164 '''
165 Grab list of recent pastes.
166 '''
167 headers = {'User-Agent': USER_AGENT}
168 req = get('http://pastebin.com', headers=headers)
169 soup = Soup(req.text, 'html.parser')
170 table = soup.find('div', {'id': 'menu_2'})
171 rows = table.findAll('li')
172 out = []
173 for row in rows:
174 a = row.find('a')
175 title = a.string
176 key = a['href'][1:]
177 out.append({'title': title, 'key': key})
178 return out
179
180@command('help')
181def help():
182 print('''
183python watchtower.py CMD ARGS...
184
185Commands:
186 run -- Begin monitoring
187 help -- Show this
188 list -- List watched phrases
189 add "PHRASE" -- Add a new phrase to be watched
190 remove "PHRASE" -- Remove an existing phrase from being watched
191''')
192 exit()
193
194@command('list')
195def list_phrases(silent=False):
196 db = database()
197 cursor = db.cursor()
198 cursor.execute('select phrase from Phrases')
199 out = []
200 for row in cursor:
201 if not silent:
202 print(row[0])
203 out.append(row[0])
204 return out
205
206@command('add')
207def add_phrase(*phrases):
208 db = database()
209 cursor = db.cursor()
210 for phrase in phrases:
211 cursor.execute('''
212 insert or ignore into Phrases (phrase) values (?)
213 ''', (phrase,))
214 db.commit()
215 list_phrases()
216
217@command('remove')
218def remove_phrase(*phrases):
219 db = database()
220 cursor = db.cursor()
221 for phrase in phrases:
222 cursor.execute('delete from Phrases where phrase = ?', (phrase,))
223 db.commit()
224 list_phrases()
225
226if __name__ == '__main__':
227 main()