feat: complete basic functions

Support http,dns and mysql connection. Support custom http, dns response. Support dns rebinding.
Support mysql load local files and jdbc deserialize exploit.
This commit is contained in:
Li4n0
2021-04-21 18:55:16 +08:00
parent e9db8ddb24
commit 3559894acc
114 changed files with 41617 additions and 0 deletions
+47
View File
@@ -0,0 +1,47 @@
package notice
import (
"sync"
"github.com/li4n0/revsuit/internal/record"
log "unknwon.dev/clog/v2"
)
var (
lock sync.RWMutex
announcer *Announcer
)
// Bot is used to send notice
type Bot interface {
notice(record.Record) error
buildPayload(record.Record) string
}
// Announcer is used for storage and schedule bots
type Announcer struct {
Bots []Bot
}
// New initializes a new Announcer
func New() *Announcer {
announcer = &Announcer{Bots: make([]Bot, 0)}
return announcer
}
// AddBot add a new bot to Announcer
func (a *Announcer) AddBot(b Bot) *Announcer {
lock.RLock()
a.Bots = append(a.Bots, b)
lock.RUnlock()
return a
}
// Notice let bots to send notice
func Notice(r record.Record) {
for _, bot := range announcer.Bots {
if err := bot.notice(r); err != nil {
log.Error(err.Error())
}
}
}
+71
View File
@@ -0,0 +1,71 @@
package notice
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"github.com/li4n0/revsuit/internal/record"
)
var _ Bot = (*DingTalk)(nil)
type DingTalk struct {
URL string
}
type dingAt struct {
AtMobiles []string `json:"atMobiles"`
IsAtAll bool `json:"isAtAll"`
}
type dingMarkdown struct {
Title string `json:"title"`
Text string `json:"text"`
}
type dingPayload struct {
MsgType string `json:"msgtype"`
Markdown dingMarkdown `json:"markdown"`
At []dingAt `json:"at"`
}
func (d *DingTalk) buildPayload(r record.Record) string {
payload := dingPayload{
MsgType: "markdown",
Markdown: dingMarkdown{
Title: "New Connection",
Text: "**<font color=\"#e96900\" face=\"Fira Code\" size=\"3\">New Connection</font>**\n" +
formatRecordField(r, "> **<font color=\"#e96900\" face=\"Fira Code\">%s: </font>**<font color=\"#e96900\" face=\"Fira Code\">%v</font>\n"),
},
At: []dingAt{
{
IsAtAll: true,
},
},
}
p, err := json.Marshal(&payload)
if err != nil {
return ""
}
return string(p)
}
func (d *DingTalk) notice(r record.Record) error {
resp, err := http.DefaultClient.Post(d.URL, "application/json", strings.NewReader(d.buildPayload(r)))
if err != nil {
return fmt.Errorf("HTTP request: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode/100 != 2 {
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("read HTTP response body: %v", err)
}
return fmt.Errorf("non-success response status code %d with body: %s", resp.StatusCode, data)
}
return nil
}
+32
View File
@@ -0,0 +1,32 @@
package notice
import (
"fmt"
"reflect"
"strings"
"github.com/li4n0/revsuit/internal/record"
)
func formatRecordField(r record.Record,fieldFormat string) (content string) {
structType := reflect.ValueOf(r)
for i := 0; i < structType.NumField(); i++ {
structField := structType.Type().Field(i)
fieldName := structField.Name
tag := structField.Tag
label := tag.Get("notice")
if label == "-" {
continue
} else if label != "" {
fieldName = label
}
value := structType.Field(i).Interface()
if value, ok := value.(record.Record); ok {
content += formatRecordField(value, fieldFormat)
continue
}
content += fmt.Sprintf(fieldFormat+"\n", strings.ToUpper(fieldName), value)
}
strings.TrimSuffix(content, "\n")
return
}
+86
View File
@@ -0,0 +1,86 @@
package notice
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"github.com/li4n0/revsuit/internal/record"
)
var _ Bot = (*Lark)(nil)
type Lark struct {
URL string
}
type larkText struct {
Content string `json:"content"`
Tag string `json:"tag"`
}
type larkElement struct {
Tag string `json:"tag"`
Text larkText `json:"text"`
}
type larkCard struct {
Header larkHeader `json:"header"`
Elements []larkElement `json:"elements"`
}
type larkHeader struct {
Title larkText `json:"title"`
}
type larkPayload struct {
MsgType string `json:"msg_type"`
Card larkCard `json:"card"`
}
func (d *Lark) buildPayload(r record.Record) string {
payload := larkPayload{
MsgType: "interactive",
Card: larkCard{
Header:larkHeader{
Title: larkText{
Tag: "plain_text",
Content: "New Connection",
},
},
Elements: []larkElement{
{
Tag: "div",
Text: larkText{
Tag: "lark_md",
Content: formatRecordField(r,"**%s**: %v"),
},
},
},
},
}
p, err := json.Marshal(&payload)
if err != nil {
return ""
}
return string(p)
}
func (d *Lark) notice(r record.Record) error {
resp, err := http.DefaultClient.Post(d.URL, "application/json", strings.NewReader(d.buildPayload(r)))
if err != nil {
return fmt.Errorf("HTTP request: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode/100 != 2 {
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("read HTTP response body: %v", err)
}
return fmt.Errorf("non-success response status code %d with body: %s", resp.StatusCode, data)
}
return nil
}
+84
View File
@@ -0,0 +1,84 @@
package notice
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"github.com/li4n0/revsuit/internal/record"
)
var _ Bot = (*Slack)(nil)
type Slack struct {
URL string
}
type slackText struct {
Type string `json:"type"`
Text string `json:"text"`
}
type slackBlock struct {
Type string `json:"type"`
Text slackText `json:"text"`
}
type slackAttachments struct {
Color string `json:"color"`
Blocks []slackBlock `json:"blocks"`
}
type slackPayload struct {
Attachments []slackAttachments `json:"attachments"`
}
func (d *Slack) buildPayload(r record.Record) string {
payload := slackPayload{
Attachments: []slackAttachments{
{
Color: "#f2c744",
Blocks: []slackBlock{
{
Type: "header",
Text: slackText{
Type: "plain_text",
Text: "New Connection",
},
},
{
Type: "section",
Text: slackText{
Type: "mrkdwn",
Text: formatRecordField(r, "- `%s: %v`"),
},
},
},
},
},
}
p, err := json.Marshal(&payload)
if err != nil {
return ""
}
return string(p)
}
func (d *Slack) notice(r record.Record) error {
resp, err := http.DefaultClient.Post(d.URL, "application/json", strings.NewReader(d.buildPayload(r)))
if err != nil {
return fmt.Errorf("HTTP request: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode/100 != 2 {
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("read HTTP response body: %v", err)
}
return fmt.Errorf("non-success response status code %d with body: %s", resp.StatusCode, data)
}
return nil
}
+59
View File
@@ -0,0 +1,59 @@
package notice
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"github.com/li4n0/revsuit/internal/record"
)
var _ Bot = (*Weixin)(nil)
type Weixin struct {
URL string
}
type weixinMarkdown struct {
Content string `json:"content"`
}
type weixinPayload struct {
ToUser string `json:"touser"`
MsgType string `json:"msgtype"`
Markdown weixinMarkdown `json:"markdown"`
}
func (w *Weixin) buildPayload(r record.Record) string {
payload := weixinPayload{
ToUser: "@all",
MsgType: "markdown",
Markdown: weixinMarkdown{
Content: "<font color=\"#e96900\" face=\"Fira Code\" size=3>New Connection</font>\n" +
formatRecordField(r, `> **<font color="#e96900" face="Fira Code">%s: </font>**<font color="#e96900" face="Fira Code">%v</font>`),
},
}
p, err := json.Marshal(&payload)
if err != nil {
return ""
}
return string(p)
}
func (w *Weixin) notice(r record.Record) error {
resp, err := http.DefaultClient.Post(w.URL, "application/json", strings.NewReader(w.buildPayload(r)))
if err != nil {
return fmt.Errorf("HTTP request: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode/100 != 2 {
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("read HTTP response body: %v", err)
}
return fmt.Errorf("non-success response status code %d with body: %s", resp.StatusCode, data)
}
return nil
}