Yakit单兵作战武器文档速查

文章发布时间:

最后更新时间:

写在前面

记录Yakit这个工具的使用学习以及Yakit语法脚本exp的编写,黑盒开搞!

Yak中的常见库使用教程

  • 字符串工具库 str

    渗透测试可能需要使用的函数

    1. 判断一个字符串密码强弱

      1
      2
      3
      4
      println(str.IsStrongPassword("abcdefghijk"))       // false
      println(str.IsStrongPassword("abc#52G")) // false
      println(str.IsStrongPassword("abcdefgh.G1ijk")) // true
      println(str.IsStrongPassword("abcdefghij.$t2Tk")) // true
    2. 把域名或者IP+端口拼成一个网络地址

      1
      2
      3
      println(str.HostPort("192.168.1.1", 80))
      println(str.HostPort("192.168.1.1", "80"))
      println(str.HostPort("example.com", 80))
    3. 让IPV4退化成一个C段地址

      1
      printTwoResult(str.IPv4ToCClassNetwork("example.com"))
    4. 判断一个字符串是不是IPV4

      1
      println(str.IsIPv4("127.0.0.1"))
    5. 判断一个字符串是不是IPV6

      1
      println(str.IsIPv6("127.0.0.1"))
    6. 把字符串(URL/Addr)中的主机和端口解析出来

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      printHostPortErr(str.ParseStringToHostPort("example.com:80"))
      printHostPortErr(str.ParseStringToHostPort("127.0.0.1:80"))
      printHostPortErr(str.ParseStringToHostPort("https://example.com"))
      printHostPortErr(str.ParseStringToHostPort("http://example.com"))
      printHostPortErr(str.ParseStringToHostPort("http://example.com:8082"))
      printHostPortErr(str.ParseStringToHostPort("example.com"))
      printHostPortErr(str.ParseStringToHostPort("example"))
      printHostPortErr(str.ParseStringToHostPort("127.0.0.1"))

      /*
      OUTPUT:

      Host: example.com Port: 80
    7. 把以,分割的字符串解析成主机信息,可解析内容为网段、IP、域名等。一般用于解析扫描目标主机

      1
      2
      3
      4
      println(str.ParseStringToHosts("baidu.com,127.0.0.1,192.168.1.2/28"))
      // OUTPUT
      // [baidu.com 127.0.0.1 192.168.1.0 192.168.1.1 192.168.1.2 192.168.1.3 192.168.1.4 192.168.1.5 192.168.1.6 192.168.1.7 192.168.1.8 192.168.1.9 192.168.1.10 192.168.1.11 192.168.1.12 192.168.1.13 192.168.1.14 192.168.1.15]

    8. 把字符串按行来分隔

      1
      dump(str.ParseStringToLines("123123123\nasdfasdf\nwfhiuqwe\nasdfasdf\r\nasdfasdf"))
    9. 把字符串(端口和端口的集合例如22,3306,8080-8088)解析成单独端口

      1
      2
      3
      4
      5
      6
      7
      8
      9
      println(str.ParseStringToPorts("22,3306,80-82,8080-8083"))
      println(str.ParseStringToPorts("8080-8083"))
      println(str.ParseStringToPorts("22,xx"))
      println(str.ParseStringToPorts("127.0.0.1/28"))

      /*
      OUTPUT:

      [22 80 81 82 3306 8080 8081 8082 8083]
    10. 把字符串(网络地址)转变为可能的标准格式的Url

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      println(str.ParseStringToUrls("www.baidu.com"))
      println(str.ParseStringToUrls("example.com"))
      println(str.ParseStringToUrls("example.com:80"))
      println(str.ParseStringToUrls("sdfaasdgasd"))
      println(str.ParseStringToUrls("127.0.1.1"))
      println(str.ParseStringToUrls("192.168.1.3:443"))
      println(str.ParseStringToUrls("192.168.1.3:80"))

      /*
      OUTPUT:

      [https://www.baidu.com http://www.baidu.com]
    11. 把字符串(网络地址)转变为可能的标准格式的Url(可能以www作为域名开头)

      1
      2
      3
      4
      5
      6
      println(str.ParseStringToUrlsWith3W("example.com"))
      println(str.ParseStringToUrlsWith3W("example.com:80"))
      println(str.ParseStringToUrlsWith3W("sdfaasdgasd"))
      [https://example.com https://www.example.com http://example.com http://www.example.com]
      [http://example.com http://www.example.com]
      [https://sdfaasdgasd https://www.sdfaasdgasd http://sdfaasdgasd http://www.sdfaasdgasd]
    12. 随机生成一个指定长度的随机字符串,可作为密码

      1
      fn str.RandSecret(var_1: int): string
    13. 随机生成一个指定长度字符串

      1
      fn str.RandStr(var_1: int): string
  • 编码解码库 codec

    1. 不可见字符打印编码(ASCII)

      image-20221228193840819

    2. Base64编码解码

      image-20221228193922215

    3. HTML实体编码

      image-20221228194021247

    4. Url 编码

      image-20221228194339011

      只编码需要编码的字符/字符串?

      image-20221228194419611

    5. 双URL编码,常用于XSS

      image-20221228194449111

    6. 十六进制编码

      如果这个十六进制字符串需要在 mysql 中展示,记得加 0x 前缀

      image-20221228194512450

    7. AES/DES加密编解码

    8. Hash计算与编码

  • 文件操作与IO库 file

    https://www.yaklang.io/docs/buildinlibs/lib_file

    exp

    1. 创建文件

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      // file.OpenFile(var1: string, mode: int, perm: int)
      // 创建简单的文件
      f, err := file.OpenFile("_testFile.txt", file.O_CREATE|file.O_RDWR, 0777)
      die(err)
      f.Write("we write some Message \n\n\n\n\nasdfahsdfasdf Now\n")
      f.Close()

      // 像 cat 一样,把文件打印出来到屏幕上
      file.Cat("_testFile.txt")

      // 移除文件
      file.Rm("_testFile.txt")

      创建临时文件

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      // file.TempFile(dir: string)
      // 创建一个临时文件
      f, err := file.TempFile("")
      die(err)
      println("我们创建了一个临时文件:", f.Name())

      // 往临时文件中写一个字符串
      println("写入一点随机字符串")
      f.Write("asdfasdf")

      // 记得脚本结束要关闭文件
      defer f.Close()

      // 我们验证我们的内容写成功了没?
      raw, err := file.ReadFile(f.Name())
      die(err)

      println("我们写入的文件内容为:")

      // 展示写的结果
      dump(raw)
    2. 文件删除

      1
      2
      3
      4
      // file.Remove 或者 file.Rm
      fileName = "target-filename.txt"
      file.Remove(fileName)
      file.Rm(fileName)
    3. 文件移动

      1
      2
      file.Rename(oldName, newName string)
      file.Mv(oldName: string, newName)
    4. 文件按行读写

      1
      2
      3
      4
      f, err := file.Open("12_fileio.yak")
      die(err)
      dump(f.ReadLines())
      f.Close()
  • 系统读写工具库 io

    遇到再说 https://www.yaklang.io/docs/buildinlibs/lib_io

  • 正则工具库 re

    1. re.Match

      检查字符串

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      // 我们构建一个 match
      pattern := `matchThis(.*?)txt`

      // 我们随便写一个字符串
      result := re.Match(pattern, `
      asdfas sdfa sdfa
      dsfasdfk;iopu34
      matchMatchMatchmatchThisasdfnkaopjryqeryjklijklojkloptxt
      `)
      if !result {
      die("failed to match re:")
      }
      printf("pattern: %v 匹配成功\n", pattern)

      /*
      OUTPUT:

      pattern: matchThis(.*?)txt 匹配成功
      */

      检查字节流

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      pattern := `matchThis(.*?)txt`
      result := re.Match(pattern, []byte(`
      asdfas sdfa sdfa
      dsfasdfk;iopu34
      matchMatchMatchmatchThisasdfnkaopjryqeryjklijklojkloptxt
      `))
      if !result {
      die("failed to match re:")
      }
      printf("pattern: %v 匹配成功\n", pattern)

      /*
      OUTPUT:

      pattern: matchThis(.*?)txt 匹配成功
      */
  • 操作系统库 os

    https://www.yaklang.io/docs/buildinlibs/lib_os

  • TCP 网络连接库 tcp

    image-20221228200325318

    exp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    // 设置日志的级别,方便我们看到 TCP 库的一些信息输出
    loglevel("info")

    // 启动一个 TCP 服务器,在 Goroutine 中异步启动
    go fn{
    tcp.Serve("127.0.0.1", 8085, tcp.serverCallback(func(conn) {
    println("真正的 TCP 服务器收到一个连接:", conn.RemoteAddr())
    bytes, err := conn.RecvLen(4)
    if err != nil {
    conn.Close()
    return
    }
    println("收到连接的前 4 个字符为", string(bytes))
    println("发送一个 Hello World 给客户端")

    conn.Send("你好,世界!Hello World from 127.0.0.1:8085")
    println("发送成功了!")
    conn.Close()
    }))
    }

    // 启动一个 TCP 本地转发,把本地 9000 转发到 127.0.0.1:8085
    go fn{
    tcp.Forward(9000, "127.0.0.1", 8085)
    }

    // 启动一个 TCP 连接,直接访问本地 9000 端口
    conn, err := tcp.Connect("127.0.0.1", 9000)
    die(err)

    // 发送一个消息给 9000 端口
    conn.Send("abdasdf this message from client")

    dump(conn.RecvStringTimeout(1))
    // 等待3秒观察日志
    sleep(3)
  • 模糊测试工具库 fuzz

    1. 模糊测试字符串

      fn fuzz.Strings(origin: string) []string

      这个函数会把核心的 {{ }} 标签转变为需要渲染的内容

      exp

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      origin := "{{int(1,3,4,80-88)}}"
      res := fuzz.Strings(origin)
      println("需要模糊渲染的字符串为:", origin)
      println("渲染结果为:")
      dump(res)

      /*
      OUTPUT:

      需要模糊渲染的字符串为: {{int(1,3,4,80-88)}}
      渲染结果为:
      ([]string) (len=12 cap=12) {
      (string) (len=1) "1",
      (string) (len=1) "3",
      (string) (len=1) "4",
      (string) (len=2) "80",
      (string) (len=2) "81",
      (string) (len=2) "82",
      (string) (len=2) "83",
      (string) (len=2) "84",
      (string) (len=2) "85",
      (string) (len=2) "86",
      (string) (len=2) "87",
      (string) (len=2) "88"
      }
      */
    2. fuzz 标签定义以及使用

      在同一个渲染的字符串中,完全相同的标签不会做排列组合,而是被渲染成相同的元素。如果真的需要标签渲染内容完全相同,并且需要分别渲染,可以在标签函数功能后增加一个数字,例如 {{int1()}}, {{int2()}} 这两个标签同 {{int()}} 完全等效,但是可以分别渲染

      • 基础标签

        {{int}} 渲染整数/端口

        最常用的用户其实是渲染一个端口,端口组;如果我们想要爆破密码的时候,生成密码也可以使用这个标签。

        {{net}}/{{host}} 渲染扫描目标

        本质上和 str.ParseStringToHosts 一样

        我们会把目标拆分成多个主机,支持网段,域名,IP 等。解析结果都是以 , 为分割的。

        经典配合{{int}}使用,批量生成URL

        1
        2
        3
        4
        5
        origin := "http://{{net(176.1.0.1/28,example.com)}}:{{port(8080)}}/admin.php"
        res := fuzz.Strings(origin)
        println("需要模糊渲染的字符串为:", origin)
        println("渲染结果为:")
        dump(res)

        {{randstr}}生成随机字符串

        生成一个随机字符串,只包含二十六个英文字母大小写

        image-20221228202552974

        {{randint}}生成随机数字

        image-20221228202712619

        {{char}} 指定生成单个字符

        1
        2
        3
        for _, r := range fuzz.Strings("生成一字符为:{{char(a-f)}}") {
        println(r)
        }

        {{punctuation}} / {{punc}} Fuzz 所有可见标点符号

        将会被替换为[< > ? , . / : " ; ' { } [ ] | \ _ + - = ) ( * & ^ % $ # @ !]`

        {{rangechar}} 制定生成任意字符

        有时还需要生成一些不可见字符

        image-20221228203142388

        【编码标签】{{md5}} {{sha1}} {{sha256}} {{sha512}}

        支持嵌套

        【编码标签】{{base64}} {{hex}} {{url}} {{durl}} {{html}} {{htmlhex}}

        image-20221228203344981

      • Fuzz Http 请求

        通过 fuzz.HTTPRequest 这个接口可以创建一个 HTTP 请求,这个请求可以支持 Fuzz 相关操作。

        1
        func fuzz.HTTPRequest(params: *http.Request|[]byte|string) (*FuzzHTTPRequest, error)

        exp

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        /*
        构筑 FuzzHTTPRequest
        */


        // 我们构建一个基础数据包,这个数据包是标准 http 请求构建的
        req, err := http.NewRequest("GET", "http://127.0.0.1:8080")
        die(err)

        // 我们自定义个数据包的具体内容,虽然他不标准,但是仍然可以被解析和使用,这点非常棒
        reqBody := `GET / HTTP/1.1
        Host: 127.0.0.1:8082`

        for _, params := range [
        []byte(reqBody), // 测试 []byte / []uint8 类型的数据包是否能被使用
        reqBody, // 测试 string 数据包是否能被使用
        req, // 测试 *http.Request 是否能被正常解析
        ] {
        req, err := fuzz.HTTPRequest(params)
        if err != nil {
        /* 如果解析失败,将会直接在这里打印出失败的原因和原来参数 */
        println("参数错误: ")
        dump(params)
        die(err)
        } else {
        println(str.f("接收 %v 数据包成功", type(params)))
        }
        }

        返回值信息 https://www.yaklang.io/docs/buildinlibs/lib_fuzz#%E6%A0%B9%E6%8D%AE%E4%B8%80%E5%A0%86-url-%E6%89%B9%E9%87%8F%E6%9E%84%E5%BB%BA%E6%95%B0%E6%8D%AE%E5%8C%85

        那么如何对一大批url进行批量测试?

        利用fuzz.UrlsToHTTPRequests

        单个

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        // fuzz.UrlsToHTTPRequests 案例1
        reqGroup, err = fuzz.UrlsToHTTPRequests("http://127.0.0.1:8082")
        die(err)

        // 获取 Fuzz 的结果
        reqs, err := reqGroup.Results()
        die(err)

        // 展示构造后的数据包
        for _, req := range reqs {
        http.show(req)
        }

        /*
        OUTPUT

        GET / HTTP/1.1
        Host: 127.0.0.1:8082
        Content-Length: 0

        */

        多个

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        println("----------")
        // fuzz.UrlsToHTTPRequests 案例
        urls = `http://127.0.0.1:8082
        http://127.0.0.1:8083
        http://127.0.0.1:8084
        http://127.0.0.1:8085
        `
        reqGroup, err = fuzz.UrlsToHTTPRequests(str.ParseStringToLines(urls)...)
        die(err)
        reqs, err := reqGroup.Results()
        die(err)

        for _, req := range reqs {
        http.show(req)
        }

        优化版本

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        println("----------")
        // fuzz.UrlsToHTTPRequests 案例
        urls = `http://127.0.0.1:808{{int(5-8)}}
        http://127.0.0.1:8082`

        reqGroup, err = fuzz.UrlsToHTTPRequests(str.ParseStringToLines(urls)...)
        die(err)
        reqs, err := reqGroup.Results()
        die(err)

        for _, req := range reqs {
        http.show(req)
        }

        image-20221228205356779

      • 链式调用 Fuzz一个HTTPRequest

        https://www.yaklang.io/docs/buildinlibs/lib_fuzz#%E9%93%BE%E5%BC%8F%E8%B0%83%E7%94%A8%EF%BC%9A%E5%A6%82%E4%BD%95-fuzz-%E4%B8%80%E4%B8%AA-httprequest%EF%BC%9F

      • 批量发起Fuzz过的请求

        httpool.Pool(i *FuzzHTTPRequest|[]*http.Request, opts...) (chan map[string]interface{}, error)

        exp

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        // 批量发起请求
        req, err := fuzz.HTTPRequest(`GET /path-target HTTP/1.1
        Host: 127.0.0.1:8082`)
        die(err)

        fReq := req.FuzzPath("/admin/admin{{int(1-4)}}.php")
        ch, err := httpool.Pool(fReq)
        die(err)

        for result := range ch {
        dump(result)
        println("-------------------------------------")
        }
  • HTTP库 http

    API 如下 https://www.yaklang.io/docs/buildinlibs/lib_http#%E6%89%80%E6%9C%89-api

  • 从命令行读参数 cli

    cli.Args()

    处理不同类型的参数值 cli.String() / cli.Bool() / cli.Int

  • servicescan 服务指纹扫描

    image-20221229115750664

  • 网络空间引擎 spaceengine

    https://www.yaklang.io/docs/buildinlibs/lib_spacengine#%E5%9F%BA%E7%A1%80%E4%BD%BF%E7%94%A8%E6%A1%88%E4%BE%8B

    配合servicescan 使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    apiKey := cli.String("token")

    res, err := spacengine.ShodanQuery(apiKey, "jenkins", spacengine.maxRecord(100))
    die(err)

    fpRes, err := servicescan.ScanFromSpaceEngine(res)
    die(err)

    for result := range fpRes {
    println(result)
    }
  • 子域名收集

    1
    2
    3
    4
    5
    6
    res, err := subdomain.Scan("b******u.com" , subdomain.recursive(true ) )
    die(err)

    for result := range res {
    result.Show()
    }
  • 赋予Yak漏扫能力

    nuclei.Scan

    image-20221229120754471

参考链接

https://www.yaklang.io/docs/buildinlibs/lib_str#f