Say0l的安全开发-弱口令扫描工具-My-crack【红队工具】

写在前面

终于终于,安全开发也练习一年半了,有时间完善一下项目,写写中间踩过的坑。

安全开发的系列全部都会上传至github,欢迎使用和star

工具链接地址

https://github.com/SAY0l/my-crack

预览

Say0l的安全开发-弱口令扫描工具-My-crack【红队工具】_第1张图片

My-Crack 工具介绍

更适合中国宝宝的弱口令扫描器

Help

NAME:
   My-Crack - Weak password crack

USAGE:
   main.exe [global options] command [command options] [arguments...]

VERSION:
   1.1

AUTHOR:
   sayol 

COMMANDS:
   scan     let's crack weak password
   help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --debug, -d                    debug mode
   --timeout value, -t value      timeout (default: 3)
   --scan_num value, -n value     thread num (default: 5000)
   --ip_list value, -i value      ip_list (default: "./input/ip_list.txt")
   --user_dict value, -u value    user_dict (default: "./input/user.dic")
   --pass_dict value, -p value    pass_dict (default: "./input/pass.dic")
   --output_file value, -o value  scan result file (default: "./output/my_crack.txt")
   --help, -h                     show help
   --version, -v                  print the version

Use

当前核心支持ftp/mongodb/mysql/mssql/postgre/redis/ssh的弱口令扫描

提供了编译后的版本。

后续版本开放代码

Other

思路借鉴于赵海峰老师的《白帽子安全开发实战》

顺带回答赵海峰老师的小问题:

1. 扫到一个弱口令后,如何取消相同IP\port和用户名请求,避免扫描效率低下
2. 对于FTP匿名访问,如何只记录一个密码,而不是把所有用户名都记录下来
3. 对于Redis这种没有用户名的服务,如何只记录一次密码,而不是记录所有的所有用户及正常的密码的组合
4. 对于不支持设置超时的扫描插件,如何统一设置超时时间
  1. 利用hash来完成的。在redis,ftp这种可以仅记录密码的就以(ip-port-protocol)进行hash,其他带用户名的以(ip-port-username)进行hash,查hash来作为规避条件,一旦结果集的hash已经存在和当前扫描产生的hash值相同,就continue。

  2. 基于上述原理,就可以实现redis、ftp 只记录一个密码,不会把所有用户名都记录下来,因为是用ip-port-protocol 进行hash。

  3. 设计了一个WaitTimeout函数。

c:= make(chan struct{})
	go func(){
		defer close(c)
		wg.Wait()
	}()
	select{
	case <-c:
		return false //c仅仅作为一个flag,没有实际作用
	case <-time.After(timeout):
		return true
	}

使用一个管道作为flagtime.After(timeout)也返回一个管道。一旦c关闭,就会触发select第一个case,返回false,表示正常关闭,wg.Wait正常完成。一旦超时时间到达,会触发select第二个case,就会返回true,表示已经超时。

Ver 1.1 优化点

  1. 连接核心中,更替了一些不能用的版本、第三方库,使用了维护性高,连接稳定的版本库。

例如mongodb的连接核心:

“go.mongodb.org/mongo-driver/mongo”

“go.mongodb.org/mongo-driver/mongo/options”

抛弃了之前的个人维护库。

  1. 修复了一些问题
ipListFile, err := os.Open(fileName)
	if err != nil {
		logger.Log.Fatalf("Open ip list file err, %v", err)
	}

	defer ipListFile.Close()

减少大量代码冗余。上述代码为例,发生错误会直接终止,defer不会入栈,无需再做defer前的判断。
  1. 错误处理修复

之前版本大量复用err,会出现err覆盖问题,有必要的err取消覆盖写法。

Ver 1.2 待优化点

代码上线

并发算法需要优化

更多服务的支持 smb,elastic …

踩坑

初始化结构体什么时候用指针,什么时候传呢?

在Go语言中,当我们初始化一个结构体时,通常会使用取地址运算符&来创建一个指向该结构体的指针,然后将该指针赋值给一个变量。

这样做的主要原因有以下几点:

1.结构体是值类型:在Go语言中,结构体是值类型,也就是说当我们将一个结构体赋值给另一个结构体时,会进行值的拷贝。如果结构体较大,这将导致内存开销较大。而使用指针可以避免这种情况,因为指针只是保存了结构体的内存地址,赋值时只是复制了一个指针,而不是整个结构体。

2.修改结构体的字段:如果我们希望在函数中修改结构体的字段值,直接传递结构体的值是不会改变原结构体的。但如果传递结构体的指针,就可以通过指针来修改结构体的字段。

3.减少内存拷贝:在函数调用时,如果传递结构体的指针,避免了对整个结构体进行内存拷贝,提高了性能。特别是当结构体较大时,这种优化效果更为明显。

函数出口编写

无论是AI,还是我自己编写的,都是多出口写法,也就是函数弹出err时,检测err是否为nil,一旦出现错误,就弹出函数

从程序设计的角度来说,多出口是很繁琐,也很不严谨的,但是如果设置flag变量来检测,不仅占用内存也很麻烦

学习大佬编写时,提供了一个非常棒的思路,当你的true条件比较重要时,同时需要处理的err不算多,不需要保证每一次的错误精准处理时

使用单个err变量,判断err==nil时的下一步动作,一旦出现错误,直接走整个函数的总出口返回。如果没有错误,继续执行语句,新的err会覆盖旧的err,一旦出错仍然走总出口返回

这样,整个函数就只有一个总出口,重点就会放在err==nil的正确情况下,不需要去繁琐的处理err

但是这样也会产生一个问题,由于err是覆盖机制,一旦有两个语句同时发生错误,你并不能判断第一个语句是否真的发生了错误,它可能是被覆盖了,也可能是没有错误。所以上述写法在需要处理的err较少的情况下比较好用。

defer与return

在常规情况下,defer应该是写在return的前面,保证函数在进行返回之前做出defer中的操作。
但是这并不能保证defer一定能够达到你的逻辑,因为写的不好的函数中,函数会有多个出口,例如

if err!=nil{
    return false
}
defer fmt.Println("i am defer")

这样的错误处理是很常规的,此时如果err没有问题,defer仍然能够正常入栈,可以达到正常的逻辑,但是一旦err发现错误,defer 就不能正常入栈了。

所以defer一定要写在所有可能return的前面

你可能感兴趣的:(安全,web安全,网络安全,安全开发,红队)