相关阅读

【零基础学渗透】系统层基础与常见命令的学习-自由者联盟
【视频讲解】BASH脚本如何定义变量玩出花样?变量与参数篇-自由者联盟
【视频讲解】黑客常用的远程命令执行实战及演示-自由者联盟
黑客是如何隐藏自己的痕迹?罪犯是如何被追踪到的?如何真正做到完全匿名?-自由者联盟
【零基础学渗透】系统层基础与常见命令的学习-自由者联盟

视频讲解

本期视频我们将给大家分享黑客隐藏恶意命令的小技巧,如何通过一些系统变量、?*进行混淆,从而一定程度上绕过检测,去运行、查看一些特殊路径的文件

效果展示

我们可以通过下图发现,可以通过?*等方式进行统配,最终通过iex打开系统计算器,作为POC

图片[1]-黑客如何隐藏恶意命令?-FancyPig's blog

图文教程

你可以打开终端或者使用powershell

图片[2]-黑客如何隐藏恶意命令?-FancyPig's blog

输入cmd就可以进入我们平常使用的cmd了

使用set命令便可以看到我们的系统环境变量

图片[3]-黑客如何隐藏恶意命令?-FancyPig's blog

我们往下拉,可以看到这里有SystemRoot,它将对应我们的系统根目录,C:\WINDOWS

图片[4]-黑客如何隐藏恶意命令?-FancyPig's blog

通常情况下,我们使用命令行查看,比方说C:\WINDOWS下都有哪些文件,我们会使用DIR命令

dir C:\WINDOWS
图片[5]-黑客如何隐藏恶意命令?-FancyPig's blog

这时,我们思考,能不能用系统变量进行调用呢?

在cmd中,我们要使用下述方式,首先我们需要确认系统变量前后加上%是否可以正常输出

echo %SYSTEMROOT%

然后,我们再使用dir命令,参考下面的命令

dir %SYSTEMROOT%
图片[6]-黑客如何隐藏恶意命令?-FancyPig's blog

这种方式在powershell中就不行了哦!我们exit退出cmd,继续使用powershell

图片[7]-黑客如何隐藏恶意命令?-FancyPig's blog

在powershell中有其他的方式来输出

echo $env:SYSTEMROOT
图片[8]-黑客如何隐藏恶意命令?-FancyPig's blog

这时,你是否会想到,能不能用?来替换,比方说我们先替换一个T

echo $env:SYSTEMROO?
图片[9]-黑客如何隐藏恶意命令?-FancyPig's blog

好像可以哦,那我们再把O替换成?

echo $env:SYSTEMRO??
图片[10]-黑客如何隐藏恶意命令?-FancyPig's blog

继续替换,直到它认不出来……(你全是?当然认不出来了🤪)

图片[11]-黑客如何隐藏恶意命令?-FancyPig's blog

由此我们可以得出结论,我们精简到最后,可以用$env:S?????????来代替系统的C:\WINDOWS,只有echo能输出,我们就可以用它操作,比方说,看看C:\WINDOWS目录下都有哪些文件?你就可以这么操作

图片[12]-黑客如何隐藏恶意命令?-FancyPig's blog

然后,可能就会有热心网友准备整活了,试试能不能弹个计算器?

首先,找下计算器的位置C:\Windows\System32\calc.exe

通过,刚才的方式,我们看下C:\Windows就用这个$env:S?????????代替吧

那我们就得到了$env:S?????????\System32\calc.exe,我们尝试运行

IEX $env:S?????????\SYSTEM32\calc.exe

整活成功,发现计算器是可以弹出的

图片[13]-黑客如何隐藏恶意命令?-FancyPig's blog

但是,有热心网友肯定会觉得,你这样的话后面是不是也太明显了!没错,SYSTEM32我们也可以把它做成?这种样子,这时我们可以使用Get-ChildItem进行调试

Get-ChildItem $env:S?????????\SYSTEM3?
图片[14]-黑客如何隐藏恶意命令?-FancyPig's blog

不妨再替换

图片[15]-黑客如何隐藏恶意命令?-FancyPig's blog

再替换

图片[16]-黑客如何隐藏恶意命令?-FancyPig's blog

直到我们发现有两个结果,这里代表如果我们使用SYS?????可能将不能指定到我们想要的System32路径,因为SysWOW64也是Sys开头,而且后面也是五位

图片[17]-黑客如何隐藏恶意命令?-FancyPig's blog

所以,我们现在就可以把刚才的命令改成

IEX $env:S?????????\SYSt????\calc.exe

发现是可以打开的

图片[18]-黑客如何隐藏恶意命令?-FancyPig's blog

这里值得补充的是?出现的位置,不一定是从后往前,你也可以让其出现在中间,甚至没有规律

IEX $env:S?????????\S??????2\calc.exe
图片[19]-黑客如何隐藏恶意命令?-FancyPig's blog

都是可以的

IEX $env:S?????????\S????M??\calc.exe
图片[20]-黑客如何隐藏恶意命令?-FancyPig's blog

这时,你可能会说了,检测引擎就是检测calc.exe的,你这么做有什么卵用?别急啊,还没完呢!我们可以继续对calc.exe按照上述操作进行替换

 Get-childItem $env:S?????????\S????M??\calc.exe
Get-childItem $env:S?????????\S????M??\cal?.exe
Get-childItem $env:S?????????\S????M??\ca??.exe
图片[21]-黑客如何隐藏恶意命令?-FancyPig's blog

直到我们发现匹配到多个值,我们就选择上一个即可

Get-childItem $env:S?????????\S????M??\ca??.exe
图片[22]-黑客如何隐藏恶意命令?-FancyPig's blog

最终我们打开计算器的命令如下

IEX $env:S?????????\S????M??\ca??.exe
图片[23]-黑客如何隐藏恶意命令?-FancyPig's blog

这样是不是还挺酷的,成功绕过了检测!

自动化代码

main.py

import os
import pathlib
import pprint
import re
import itertools
import glob

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("target")
args = parser.parse_args()

def test_if_env_matches(test,target):
    regex_string = rf'^{test.replace("?",".").replace("*",".*")}$'
    matches = []
    for key in os.environ.keys():
        match = re.search(regex_string,key)
        if match:
            matches.append(match.group())
    return len(matches) == 1 and target in matches

def test_if_glob_matches(test,start_path,target):
    global glob_cache
    matches = [p for p in glob_cache[start_path] if pathlib.Path(p).match(test)]
    return len(matches) == 1 and target in matches

def glob_mutate(subpath):
    for each_possibility in itertools.product("?X", repeat = len(subpath)):
        new_mutation = list(each_possibility)
        for i, c in enumerate(each_possibility):
            if c == "X":
                new_mutation[i] = subpath[i]
        to_test = "".join(new_mutation)
        yield to_test

def star_replace(subpath_mutation):
    return re.sub(r"\?+","*",subpath_mutation)

def path_parts(path_str):
    return tuple(piece.rstrip("\\") for piece in pathlib.Path(path_str).parts)

def main():
    global glob_cache,args

    #target=r"C:\\Windows\\System32\\calc.exe"
    target = args.target
    short_mode = True

    target_norm_str = os.path.normpath(target)
    target_path = pathlib.Path(target_norm_str)
    if not target_path.is_absolute():
        print("[!] error, absolute path required")
    env_score = {}
    target_parts = path_parts(target_norm_str)

    for env_key,value_path in os.environ.items():
        if os.path.exists(value_path) and os.path.isdir(value_path):
            value_path_norm_str = os.path.normpath(value_path)
            value_parts = path_parts(value_path_norm_str)

            if len(value_parts) <= len(target_parts):
                for i,part in enumerate(value_parts):
                    if target_parts[i] == value_parts[i]:
                        if env_key not in env_score:
                            env_score[env_key] = 1
                        else:
                            env_score[env_key] += 1
                    else:
                        env_score[env_key] = 0
                        break
    best_envs = []
    highest_score_env = max(env_score,key=env_score.get)
    highest_score_value = env_score[highest_score_env]
    best_envs = [key for key, value in env_score.items() if value == highest_score_value]

    starting_matches = []
    for env_key in best_envs:
        env_matches = []

        env = os.path.normpath(os.environ[env_key])
        env_parts = path_parts(env)

        left_over_parts = target_parts[len(env_parts):]

        for to_test in glob_mutate(env_key):
            matches = test_if_env_matches(to_test,env_key)
            if matches:
                env_matches.append(to_test)
        starting_matches.append(env_matches)

    env = os.path.normpath(os.environ[best_envs[0]])
    env_parts = path_parts(env)
    left_over_parts = target_parts[len(env_parts):]

    print("caching subdirectories")
    glob_cache = {}
    for i,subpart in enumerate(left_over_parts):
        map_path = os.path.join(env,os.path.sep.join(left_over_parts[:i]))
        glob_value = os.path.join(map_path,"*")
        glob_cache[map_path] = glob.glob(glob_value)


    # Handle subdirectory parts
    print(f"findg globfuscation options for '{target}'...")
    remaining_matches = []
    for i,each_part in enumerate(left_over_parts):
        remaining_part = os.path.sep.join(left_over_parts[:i])
        base_path = os.path.join(env,remaining_part)
        full_path = os.path.join(env,remaining_part,each_part)

        question_mark_mutations = []
        max_length = 0
        for each_question_mark_mutation in glob_mutate(each_part):
            question_mark_mutation_path = os.path.join(
                env,remaining_part,each_question_mark_mutation
            )

            if test_if_glob_matches(question_mark_mutation_path,base_path,full_path):
                question_mark_mutations.append(each_question_mark_mutation)

        star_mutation_matches = []
        max_length = 10000
        for each_mutation in question_mark_mutations:
            star_mutation = star_replace(each_mutation)

            star_mutation_path = os.path.join(env, remaining_part, star_mutation)

            if len(star_mutation) >= max_length:
                continue

            if star_mutation not in star_mutation_matches:
                matches = test_if_glob_matches(star_mutation_path, base_path, full_path)
                if matches:
                    if short_mode:
                        if max_length == 0:
                            max_length = len(star_mutation)
                    max_length = len(star_mutation)
                    star_mutation_matches.append(star_mutation)

        remaining_matches.append(question_mark_mutations + star_mutation_matches)

        all_mode = False

        shortest = 0
        all_options = []
        for env_starts in starting_matches:
            for start in env_starts:
                for every_option in itertools.product(*remaining_matches):
                    new_option = f"$env:{start}{os.path.sep}{os.path.join(*every_option)}"
                    if all_mode:
                        print(new_option)
                    else:
                        if shortest == 0:
                            shortest = len(new_option)
                        if len(new_option) < shortest:
                            print(new_option)
                            shortest = len(new_option)
if __name__ == "__main__":
    main()

我们比方说想生成刚才的C:\\Windows\\System32\\calc.exe

python .\main.py "C:\\Windows\\System32\\calc.exe"
图片[24]-黑客如何隐藏恶意命令?-FancyPig's blog

当然,你也可以调整代码的模式,第143行

all_mode = False

修改为

all_mode = True

在输入上面的命令,可以全部可能性,我们一开始关闭模式相当于只给我们最短的命令

python .\main.py "C:\\Windows\\System32\\calc.exe"
图片[25]-黑客如何隐藏恶意命令?-FancyPig's blog
这是一个动图,你需要点开才能看
© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容