一、前言
因为最近在进行漏洞方面的学习,之前租的服务器到期了,也不想在虚拟机上整,就直接在本机上通过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!