使用SwiftUI编写一个客户端——完成一键启动Docker与vulhub漏洞环境!

一、前言

        因为最近在进行漏洞方面的学习,之前租的服务器到期了,也不想在虚拟机上整,就直接在本机上通过docker-compose启动漏洞环境,但是每次都需要先进入vulhub的目录,然后进入具体的目录,通过命令行输入docker-compose up -d才能将环境启动起来,又要打开文件夹又要打开终端,很烦,于是想通过SwiftUI写一个macos客户端,实现目录的加载以及一键启动、一键停止,这样的话就只用打开一个客户端就行了,顺便学习一下SwfitUI,现在ipad、ios应用都可以用这个写,以后如果想做其他应用就可以轻松一些。开整!

二、封装函数

        为了后续SwiftUI能够更快的实现功能,于是乎我先把函数功能写好,结果类型定义好了之后再写客户端。

1、读取目录并转化为字典格式存储

public func FindAllDir(path:String)-> Dictionary<String, Array<String>>{
    var list=Array<String>()
    var dict=Dictionary<String, Array<String>>()
    
    let pointer = UnsafeMutablePointer<ObjCBool>.allocate(capacity: 1)
    do{
        let files=try FileManager.default.contentsOfDirectory(atPath: path)
        //遍历第一遍找到文件夹
        for f in files{
            if FileManager.default.fileExists(atPath: path+f, isDirectory: pointer) {
                if !pointer.pointee.boolValue {
                }
                else{
                    list.append(f)
                }
            }
        }
        //遍历第二遍找到文件夹内部漏洞项目
        for l in list{
            let object=try FileManager.default.contentsOfDirectory(atPath: path+l)
            var array=Array<String>()
            for o in object{
                if FileManager.default.fileExists(atPath: path+l+"/"+o, isDirectory: pointer) {
                    if !pointer.pointee.boolValue {
                    }
                    else{
                        if l==String(".git"){
                        }else{
                            array.append(o)
                        }
                    }
                }
            }
            dict[l]=array
        }
    }catch{}
    return dict
}

       

如图所示目录的结构是这样的,一级目录是应用的名字,二级目录是漏洞名,我只需要进入二级目录然后,在二级目录下执行命令就可以成功启动环境。

函数编写的思路就是第一步找到所有一级目录,然后进入目录找到二级目录。

不知道Swift中有没有更简单的能实现这个功能的函数....

实现之后的字典是这样的:<String,Array<String>>的形式

2、执行命令行语句

public func runShellAndOutput(_ command: String) -> (Int32, String?){
    let task = Process()
    task.launchPath = "/bin/zsh"
    task.arguments = ["-cl", command]
    let pipe = Pipe()
    task.standardOutput = pipe
    task.standardError = pipe
    task.launch()
    let data = pipe.fileHandleForReading.readDataToEndOfFile()
    let output = String(data: data, encoding: .utf8)
    task.waitUntilExit()
    return (task.terminationStatus, output)
}

这里是在网上找了一些,然后写了个能用的,吐槽一下大部分关于Swift的文章竟然是收费的!!!!

大概意思就是要开个线程,然后设置输入的命令,通过管道来获取输出的内容。

3、进入目录启动项目

func Object_start(filepath:String)-> String{
    var st=String()
    let (_, output1) = runShellAndOutput("cd \(filepath) ;docker-compose up -d")
    if let output=output1{
        //print(output1)
        st=output
    }
    return st
}

4、停止项目

func Object_stop(filepath:String)-> String{
    var st=String()
    let (_, output1) = runShellAndOutput("cd \(filepath) ;docker-compose stop")
    if let output=output1{
        //print(output1)
        st=output
    }
    return st
}

5、查看项目logs

func Object_info(filepath:String)->String{
    var st=String()
    let (_, output1) = runShellAndOutput("cd \(filepath) ;docker-compose logs")
    if let output=output1{
        //print(output1)
        st=output
    }
    return st
}

6、启动docker

func StartDocker(){
    let (_, _) = runShellAndOutput("open -a Docker")
}

7、查看docker状态

func CheckDockerStats()->String{
    var st=String()
    let (_, output1) = runShellAndOutput("docker info")
    if let output=output1{
        //print(output1)
        st=output
    }
    return st
}

这里要启动的原因是,在linux上是把docker作为了一个service服务,可以启动或者关闭,但是在mac中他把docker当成了工具,就不能把它作为服务启动,这里的解决方案就是直接打开Docker-Desktop,因为这个打开之后dokcer就自动开启了。

三、客户端UI

//
//  ContentView.swift
//  dddtest
//
//  Created by Van on 2023/10/5.
//

import SwiftUI
import Foundation

struct ContentView: View {
    @State var dict_keys=Array<String>(FindAllDir(path: PATH).keys).sorted(by: { $0.lowercased() > $1.lowercased() })
    @State var dict=FindAllDir(path: PATH)
    @State var result=String("welcome")
    
    var body: some View {
        VStack(alignment: .center){
            Spacer()
            HStack(alignment: .bottom){
                Button("Docker start"){
                    StartDocker()
                    result="Starting...."
                }.buttonStyle(.automatic).font(.largeTitle)
                Button("status"){
                    result=CheckDockerStats()
                }.buttonStyle(.automatic).font(.headline)
                
            }
            
            List(){
                ForEach(dict_keys,id:\.self){name in
                    DisclosureGroup(name){
                        ForEach(Array<String>(dict[name]!),id:\.self){
                            obj in LabeledContent(obj) {
                                Button(action: {
                                    let Filepath=String(PATH+name+"/"+obj)
                                    //print(Object_start(filepath: Filepath))
                                    result=Object_start(filepath: Filepath)
                                    }, label: {
                                    Image(systemName: "restart.circle.fill")
                                })
                              
                                Button(action: {
                                    let Filepath=String(PATH+name+"/"+obj)
                                    result=Object_stop(filepath: Filepath)
                                    
                                }, label: {
                                    Image(systemName: "stop.circle.fill")
                                })
                                Button(action: {
                                    let Filepath=String(PATH+name+"/"+obj)
                                    result=Object_info(filepath: Filepath)
                                }, label: {
                                    Image(systemName: "info.circle.fill")
                                })
                            }.buttonStyle(.plain).font(.title2)
                        }
                        
                        
                    }.font(.title2)
                }
            }
            
            }
            ContentUnavailableView {
                Text(result).font(.headline)
            }
        }
    }
    

#Preview {
    ContentView()
    
}

这里就尝试了很多种组件,最终选择了上面这种形式,后面可能还会加个搜索功能?

每个漏洞项目旁边都有三个按钮,start、stop、info,显而易见的功能对吧。

组件主要就是List和DisclosureGroup,然后就是Button和Text。整个UI种我感觉最难的一点在与用List和DisclosureGroup把我的目录显示出来,因为此前将目录转化为了Dictionary<String, Array<String>>的形式,然后我还不怎么会用那个Foreach语句,感觉swfit的对象类型要求好严格,我就只能一步步写,然后把对象格式又转换成相匹配的格式,其实它大可以搞个自动转换,毕竟我写也是强制转换。

四、测试功能

1、打开客户端

2、运行docker、查看docker状态

3、启动漏洞项目

这里就启动一个mysql项目吧,之前测试过。

4、漏洞复现

        漏洞文档中是直接通过输入shell命令来测试,我自己写了python脚本,直接一步到位获取password!这里是启动之后运行的,可以看到漏洞已经复现了,在此基础上我直接查到了root的密码,只不过是MD5加密过的,揭秘之后就是123456。测试完成之后点一下就可以关闭环境了,图放在上面。   

over!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值