Attempt to patch a possible message injection hole.

master
Sean B. Palmer 2011-09-05 17:46:17 +01:00
parent 66edd83372
commit 2d3009ccb1
9 changed files with 101 additions and 28 deletions

2
bot.py
View File

@ -55,6 +55,8 @@ class Phenny(irc.Bot):
for filename in filenames:
name = os.path.basename(filename)[:-3]
if name in excluded_modules: continue
# if name in sys.modules:
# del sys.modules[name]
try: module = imp.load_source(name, filename)
except Exception, e:
print >> sys.stderr, "Error loading %s: %s (in bot.py)" % (name, e)

8
irc.py
View File

@ -42,6 +42,9 @@ class Bot(asynchat.async_chat):
import threading
self.sending = threading.RLock()
# def push(self, *args, **kargs):
# asynchat.async_chat.push(self, *args, **kargs)
def __write(self, args, text=None):
# print '%r %r %r' % (self, args, text)
try:
@ -148,7 +151,10 @@ class Bot(asynchat.async_chat):
self.sending.release()
return
self.__write(('PRIVMSG', recipient), text)
def safe(input):
input = input.replace('\n', '')
return input.replace('\r', '')
self.__write(('PRIVMSG', safe(recipient)), safe(text))
self.stack.append((time.time(), text))
self.stack = self.stack[-10:]

View File

@ -83,6 +83,18 @@ def f_title(self, origin, match, args):
uri = 'http://' + uri
uri = uri.replace('#!', '?_escaped_fragment_=')
localhost = [
'http://localhost/', 'http://localhost:80/',
'http://localhost:8080/', 'http://127.0.0.1/',
'http://127.0.0.1:80/', 'http://127.0.0.1:8080/',
'https://localhost/', 'https://localhost:80/',
'https://localhost:8080/', 'https://127.0.0.1/',
'https://127.0.0.1:80/', 'https://127.0.0.1:8080/',
]
for s in localhost:
if uri.startswith(s):
return phenny.reply('Sorry, access forbidden.')
try:
redirects = 0
while True:

View File

@ -81,7 +81,7 @@ def o(phenny, input):
return phenny.reply(msg)
if not o.services.has_key(command):
return phenny.reply('Sorry, no such service. See %s' % o.serviceURI)
return phenny.reply('Service not found in %s' % o.serviceURI)
if hasattr(phenny.config, 'external'):
default = phenny.config.external.get('*')

View File

@ -19,6 +19,8 @@ def f_reload(phenny, input):
return phenny.reply('What?')
if (not name) or (name == '*'):
phenny.variables = None
phenny.commands = None
phenny.setup()
return phenny.reply('done')

View File

@ -18,26 +18,26 @@ class Grab(web.urllib.URLopener):
def http_error_default(self, url, fp, errcode, errmsg, headers):
return web.urllib.addinfourl(fp, [headers, errcode], "http:" + url)
def search(query):
def google_ajax(query):
"""Search using AjaxSearch, and return its JSON."""
uri = 'http://ajax.googleapis.com/ajax/services/search/web'
args = '?v=1.0&safe=off&q=' + web.urllib.quote(query.encode('utf-8'))
args = '?v=1.0&safe=off&q=' + web.urllib.quote(query)
handler = web.urllib._urlopener
web.urllib._urlopener = Grab()
bytes = web.get(uri + args)
web.urllib._urlopener = handler
return web.json(bytes)
def result(query):
results = search(query)
def google_search(query):
results = google_ajax(query)
try: return results['responseData']['results'][0]['unescapedUrl']
except IndexError: return None
except TypeError:
print results
return False
def count(query):
results = search(query)
def google_count(query):
results = google_ajax(query)
if not results.has_key('responseData'): return '0'
if not results['responseData'].has_key('cursor'): return '0'
if not results['responseData']['cursor'].has_key('estimatedResultCount'):
@ -56,7 +56,8 @@ def g(phenny, input):
query = input.group(2)
if not query:
return phenny.reply('.g what?')
uri = result(query)
query = query.encode('utf-8')
uri = google_search(query)
if uri:
phenny.reply(uri)
if not hasattr(phenny.bot, 'last_seen_uri'):
@ -73,7 +74,8 @@ def gc(phenny, input):
query = input.group(2)
if not query:
return phenny.reply('.gc what?')
num = formatnumber(count(query))
query = query.encode('utf-8')
num = formatnumber(google_count(query))
phenny.say(query + ': ' + num)
gc.commands = ['gc']
gc.priority = 'high'
@ -93,7 +95,8 @@ def gcs(phenny, input):
results = []
for i, query in enumerate(queries):
query = query.strip('[]')
n = int((formatnumber(count(query)) or '0').replace(',', ''))
query = query.encode('utf-8')
n = int((formatnumber(google_count(query)) or '0').replace(',', ''))
results.append((n, query))
if i >= 2: __import__('time').sleep(0.25)
if i >= 4: __import__('time').sleep(0.25)
@ -105,6 +108,13 @@ gcs.commands = ['gcs', 'comp']
r_bing = re.compile(r'<h3><a href="([^"]+)"')
def bing_search(query, lang='en-GB'):
query = web.urllib.quote(query)
base = 'http://www.bing.com/search?mkt=%s&q=' % lang
bytes = web.get(base + query)
m = r_bing.search(bytes)
if m: return m.group(1)
def bing(phenny, input):
"""Queries Bing for the specified input."""
query = input.group(2)
@ -115,12 +125,9 @@ def bing(phenny, input):
if not query:
return phenny.reply('.bing what?')
query = web.urllib.quote(query.encode('utf-8'))
base = 'http://www.bing.com/search?mkt=%s&q=' % lang
bytes = web.get(base + query)
m = r_bing.search(bytes)
if m:
uri = m.group(1)
query = query.encode('utf-8')
uri = bing_search(query, lang)
if uri:
phenny.reply(uri)
if not hasattr(phenny.bot, 'last_seen_uri'):
phenny.bot.last_seen_uri = {}
@ -129,24 +136,65 @@ def bing(phenny, input):
bing.commands = ['bing']
bing.example = '.bing swhack'
r_ddg = re.compile(r'nofollow" class="[^"]+" href="(.*?)">')
r_duck = re.compile(r'nofollow" class="[^"]+" href="(.*?)">')
def ddg(phenny, input):
def duck_search(query):
query = query.replace('!', '')
query = web.urllib.quote(query)
uri = 'http://duckduckgo.com/html/?q=%s&kl=uk-en' % query
bytes = web.get(uri)
m = r_duck.search(bytes)
if m: return web.decode(m.group(1))
def duck(phenny, input):
query = input.group(2)
if not query: return phenny.reply('.ddg what?')
query = web.urllib.quote(query.encode('utf-8'))
uri = 'http://duckduckgo.com/html/?q=%s&kl=uk-en' % query
bytes = web.get(uri)
m = r_ddg.search(bytes)
if m:
uri = m.group(1)
query = query.encode('utf-8')
uri = duck_search(query)
if uri:
phenny.reply(uri)
if not hasattr(phenny.bot, 'last_seen_uri'):
phenny.bot.last_seen_uri = {}
phenny.bot.last_seen_uri[input.sender] = uri
else: phenny.reply("No results found for '%s'." % query)
ddg.commands = ['ddg']
duck.commands = ['duck', 'ddg']
def search(phenny, input):
if not input.group(2):
return phenny.reply('.search for what?')
query = input.group(2).encode('utf-8')
gu = google_search(query) or '-'
bu = bing_search(query) or '-'
du = duck_search(query) or '-'
if (gu == bu) and (bu == du):
result = '%s (g, b, d)' % gu
elif (gu == bu):
result = '%s (g, b), %s (d)' % (gu, du)
elif (bu == du):
result = '%s (b, d), %s (g)' % (bu, gu)
elif (gu == du):
result = '%s (g, d), %s (b)' % (gu, bu)
else:
if len(gu) > 250: gu = '(extremely long link)'
if len(bu) > 150: bu = '(extremely long link)'
if len(du) > 150: du = '(extremely long link)'
result = '%s (g), %s (b), %s (d)' % (gu, bu, du)
phenny.reply(result)
search.commands = ['search']
def suggest(phenny, input):
if not input.group(2):
return phenny.reply("No query term.")
query = input.group(2).encode('utf-8')
uri = 'http://websitedev.de/temp-bin/suggest.pl?q='
answer = web.get(uri + web.urllib.quote(query).replace('+', '%2B'))
if answer:
phenny.say(answer)
else: phenny.reply('Sorry, no result.')
suggest.commands = ['suggest']
if __name__ == '__main__':
print __doc__.strip()

View File

@ -122,6 +122,7 @@ def message(phenny, input):
tellee = input.nick
channel = input.sender
if not os: return
if not os.path.exists(phenny.tell_filename):
return

View File

@ -53,7 +53,7 @@ def search(term):
else: term = term.decode('utf-8')
term = term.replace('_', ' ')
try: uri = search.result('site:en.wikipedia.org %s' % term)
try: uri = search.google_search('site:en.wikipedia.org %s' % term)
except IndexError: return term
if uri:
return uri[len('http://en.wikipedia.org/wiki/'):]

4
phenny
View File

@ -30,7 +30,9 @@ def create_default_config(fn):
channels = ['#example', '#test']
owner = 'yournickname'
# password = 'yourserverpassword'
# password is the NickServ password, serverpass is the server password
# password = 'example'
# serverpass = 'serverpass'
# These are people who will be able to use admin.py's functions...
admins = [owner, 'someoneyoutrust']