Write Metasploit Module in Golang

Metaploit에서 2018년 12월부터 golang module 지원이 시작되었습니다. 저도 잘 모르고 있다가 최근에서야 알게 되었네요.

Contributing modules in GO can be achieved in a few simple steps as outlined below. As for supported GO version, we have tested with 1.11.2, no promised for version 2.

오늘은 go로 metasploit 모듈 만드는 방법에 대해 가볍게 이야기하려고 합니다.

Supports feature

모든 기능을 지원하진 않고 아래 모듈에 한정해서만 go 사용이 가능합니다. 사실상 exploit쪽과 scanner 쪽만 사용할 수 있다면 대다수의 PoC코드를 가지고 공격 모듈을 쉽게 만들 수 있으니 사용하는데 있어 크게 지장은 없을 것 같습니다.

  • remote_exploit
  • remote_exploit_cmd_stager
  • capture_server
  • dos
  • single_scanner
  • single_host_login_scanner
  • multi_scanner

Format

Execution

Execution은 cross-language 간 동작 실행을 위해서 맞추는 format 중 실행에 관련된 부분입니다.

Include this line at the top of your module: //usr/bin/env go run “$0” “$@”; exit “$?” Ensure your file is an executable file

Metasploit은 루비 기반이고, go쪽 코드 실행을 위해선 실행 경로나 환경에 대한 정보가 필요하기 때문에 파일 맨 상단에 주석으로 위에 구문을 넣어줘야합니다.

e.g

//usr/bin/env go run "$0" "$@"; exit "$?"

package main

import (
 "crypto/tls"
 "metasploit/module"
 "msmail"
 "net/http"
 "sort"
 "strconv"
 "sync"
 "time"
)

Metadata

이 부분은 Ruby와 동일합니다. 아래 포맷에 맞춰서 작성하면 Metasploit에서 해당 정보를 기반으로 읽고 검색하고 사용할 수 있습니다.

import "metasploit/module"
func main() {
  metadata := &module.Metadata{
    Name: "<module name",
    Description: "<describe>",
    Authors: []string{"<author 1>", "<author 2>"},
    Date: "<date module written",
    Type:"<module type>",
    Privileged:  <true|false>,
    References:  []module.Reference{},
    Options: map[string]module.Option{ 
      "<option 1":     {Type: "<type>", Description: "<description>", Required: <true|false>, Default: "<default>"},  
      "<option 2":     {Type: "<type>", Description: "<description>", Required: <true|false>, Default: "<default>"},
  }}
  module.Init(metadata, <the entry method to your module>)
}

여기서 main() 함수에 실행되는건 module.Init 시 지정한 메소드입니다. 실제 예시 코드로 보면 이렇습니다.

func main() {
 metadata := &module.Metadata{
  Name:        "On premise user enumeration",
  Description: "On premise enumeration of valid exchange users",
  Authors:     []string{"poptart", "jlarose", "Vincent Yiu", "grimhacker", "Nate Power", "Nick Powers", "clee-r7"},
  Date:        "2018-11-06",
  Type:        "single_scanner",
  Privileged:  false,
  References:  []module.Reference{},
  Options: map[string]module.Option{
   "USERNAME":   {Type: "string", Description: "Single user name to do identity test against", Required: false, Default: ""},
   "USER_FILE":  {Type: "string", Description: "Path to file containing list of users", Required: false, Default: ""},
  }}

 module.Init(metadata, run_onprem_enum)
}

이 모듈이 실행되면 run_onprem_enum 를 실행하고, 리턴으로 msmail.ReportValidUsers(host, validUsers) 를 반환합니다. ReportValidUsers를 보면 module의 LogInfo() 와 ReportCredentialLogin() 등의 메소드를 호출하는데 이를 통해서 Metasploit 과 데이터를 주고받을 수 있습니다.

func ReportValidUsers(ip string, validUsers []string) {
 port := "443"
 service := "owa"
 protocol := "tcp"
 for _, user := range validUsers {
  opts := map[string]string{
   "port":         port,
   "service_name": service,
   "address":      ip,
   "protocol":     protocol,
  }
  module.LogInfo("Loging user: " + user)
  module.ReportCredentialLogin(user, "", opts)
 }
}

Go Module method

func Init(metadata *Metadata, callback RunCallback) 
func parseParams(passedParams interface{}) (map[string]interface{}, error) 
func rpcSend(res interface{}) error 
func LogError(message string)
func LogWarning(message string) 
func LogGood(message string) 
func LogInfo(message string) 
func LogDebug(message string) 
func msfLog(message string, level string) 

Golang base module at now

아직은 go 기반의 모듈이 많지는 않습니다. msmail 관련 3개가 있습니다.

References

  • https://github.com/rapid7/metasploit-framework/wiki/Writing-External-GoLang-Modules
  • https://github.com/rapid7/metasploit-framework/blob/master/modules/auxiliary/scanner/msmail/shared/src/msmail/msmail.go
  • https://github.com/rapid7/metasploit-framework/search?l=Go&q=go&type=