c2.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. package c2
  2. import (
  3. "bytes"
  4. "crypto/tls"
  5. "fmt"
  6. "github.com/acarl005/stripansi"
  7. "github.com/bettercap/bettercap/modules/events_stream"
  8. "github.com/bettercap/bettercap/session"
  9. "github.com/evilsocket/islazy/log"
  10. "github.com/evilsocket/islazy/str"
  11. irc "github.com/thoj/go-ircevent"
  12. "strings"
  13. "text/template"
  14. )
  15. type settings struct {
  16. server string
  17. tls bool
  18. tlsVerify bool
  19. nick string
  20. user string
  21. password string
  22. saslUser string
  23. saslPassword string
  24. operator string
  25. controlChannel string
  26. eventsChannel string
  27. outputChannel string
  28. }
  29. type C2 struct {
  30. session.SessionModule
  31. settings settings
  32. stream *events_stream.EventsStream
  33. templates map[string]*template.Template
  34. channels map[string]string
  35. client *irc.Connection
  36. eventBus session.EventBus
  37. quit chan bool
  38. }
  39. type eventContext struct {
  40. Session *session.Session
  41. Event session.Event
  42. }
  43. func NewC2(s *session.Session) *C2 {
  44. mod := &C2{
  45. SessionModule: session.NewSessionModule("c2", s),
  46. stream: events_stream.NewEventsStream(s),
  47. templates: make(map[string]*template.Template),
  48. channels: make(map[string]string),
  49. quit: make(chan bool),
  50. settings: settings{
  51. server: "localhost:6697",
  52. tls: true,
  53. tlsVerify: false,
  54. nick: "bettercap",
  55. user: "bettercap",
  56. password: "password",
  57. operator: "admin",
  58. eventsChannel: "#events",
  59. outputChannel: "#events",
  60. controlChannel: "#events",
  61. },
  62. }
  63. mod.AddParam(session.NewStringParameter("c2.server",
  64. mod.settings.server,
  65. "",
  66. "IRC server address and port."))
  67. mod.AddParam(session.NewBoolParameter("c2.server.tls",
  68. "true",
  69. "Enable TLS."))
  70. mod.AddParam(session.NewBoolParameter("c2.server.tls.verify",
  71. "false",
  72. "Enable TLS certificate validation."))
  73. mod.AddParam(session.NewStringParameter("c2.operator",
  74. mod.settings.operator,
  75. "",
  76. "IRC nickname of the user allowed to run commands."))
  77. mod.AddParam(session.NewStringParameter("c2.nick",
  78. mod.settings.nick,
  79. "",
  80. "IRC nickname."))
  81. mod.AddParam(session.NewStringParameter("c2.username",
  82. mod.settings.user,
  83. "",
  84. "IRC username."))
  85. mod.AddParam(session.NewStringParameter("c2.password",
  86. mod.settings.password,
  87. "",
  88. "IRC server password."))
  89. mod.AddParam(session.NewStringParameter("c2.sasl.username",
  90. mod.settings.saslUser,
  91. "",
  92. "IRC SASL username."))
  93. mod.AddParam(session.NewStringParameter("c2.sasl.password",
  94. mod.settings.saslPassword,
  95. "",
  96. "IRC server SASL password."))
  97. mod.AddParam(session.NewStringParameter("c2.channel.output",
  98. mod.settings.outputChannel,
  99. "",
  100. "IRC channel to send commands output to."))
  101. mod.AddParam(session.NewStringParameter("c2.channel.events",
  102. mod.settings.eventsChannel,
  103. "",
  104. "IRC channel to send events to."))
  105. mod.AddParam(session.NewStringParameter("c2.channel.control",
  106. mod.settings.controlChannel,
  107. "",
  108. "IRC channel to receive commands from."))
  109. mod.AddHandler(session.NewModuleHandler("c2 on", "",
  110. "Start the C2 module.",
  111. func(args []string) error {
  112. return mod.Start()
  113. }))
  114. mod.AddHandler(session.NewModuleHandler("c2 off", "",
  115. "Stop the C2 module.",
  116. func(args []string) error {
  117. return mod.Stop()
  118. }))
  119. mod.AddHandler(session.NewModuleHandler("c2.channel.set EVENT_TYPE CHANNEL",
  120. "c2.channel.set ([^\\s]+) (.+)",
  121. "Set a specific channel to report events of this type.",
  122. func(args []string) error {
  123. eventType := args[0]
  124. channel := args[1]
  125. mod.Debug("setting channel for event %s: %v", eventType, channel)
  126. mod.channels[eventType] = channel
  127. return nil
  128. }))
  129. mod.AddHandler(session.NewModuleHandler("c2.channel.clear EVENT_TYPE",
  130. "c2.channel.clear ([^\\s]+)",
  131. "Clear the channel to use for a specific event type.",
  132. func(args []string) error {
  133. eventType := args[0]
  134. if _, found := mod.channels[args[0]]; found {
  135. delete(mod.channels, eventType)
  136. mod.Debug("cleared channel for %s", eventType)
  137. } else {
  138. return fmt.Errorf("channel for event %s not set", args[0])
  139. }
  140. return nil
  141. }))
  142. mod.AddHandler(session.NewModuleHandler("c2.template.set EVENT_TYPE TEMPLATE",
  143. "c2.template.set ([^\\s]+) (.+)",
  144. "Set the reporting template to use for a specific event type.",
  145. func(args []string) error {
  146. eventType := args[0]
  147. eventTemplate := args[1]
  148. parsed, err := template.New(eventType).Parse(eventTemplate)
  149. if err != nil {
  150. return err
  151. }
  152. mod.Debug("setting template for event %s: %v", eventType, parsed)
  153. mod.templates[eventType] = parsed
  154. return nil
  155. }))
  156. mod.AddHandler(session.NewModuleHandler("c2.template.clear EVENT_TYPE",
  157. "c2.template.clear ([^\\s]+)",
  158. "Clear the reporting template to use for a specific event type.",
  159. func(args []string) error {
  160. eventType := args[0]
  161. if _, found := mod.templates[args[0]]; found {
  162. delete(mod.templates, eventType)
  163. mod.Debug("cleared template for %s", eventType)
  164. } else {
  165. return fmt.Errorf("template for event %s not set", args[0])
  166. }
  167. return nil
  168. }))
  169. mod.Session.Events.OnPrint(mod.onPrint)
  170. return mod
  171. }
  172. func (mod *C2) Name() string {
  173. return "c2"
  174. }
  175. func (mod *C2) Description() string {
  176. return "A CnC module that connects to an IRC server for reporting and commands."
  177. }
  178. func (mod *C2) Author() string {
  179. return "Simone Margaritelli <evilsocket@gmail.com>"
  180. }
  181. func (mod *C2) Configure() (err error) {
  182. if mod.Running() {
  183. return session.ErrAlreadyStarted(mod.Name())
  184. }
  185. if err, mod.settings.server = mod.StringParam("c2.server"); err != nil {
  186. return err
  187. } else if err, mod.settings.tls = mod.BoolParam("c2.server.tls"); err != nil {
  188. return err
  189. } else if err, mod.settings.tlsVerify = mod.BoolParam("c2.server.tls.verify"); err != nil {
  190. return err
  191. } else if err, mod.settings.nick = mod.StringParam("c2.nick"); err != nil {
  192. return err
  193. } else if err, mod.settings.user = mod.StringParam("c2.username"); err != nil {
  194. return err
  195. } else if err, mod.settings.password = mod.StringParam("c2.password"); err != nil {
  196. return err
  197. } else if err, mod.settings.saslUser = mod.StringParam("c2.sasl.username"); err != nil {
  198. return err
  199. } else if err, mod.settings.saslPassword = mod.StringParam("c2.sasl.password"); err != nil {
  200. return err
  201. } else if err, mod.settings.operator = mod.StringParam("c2.operator"); err != nil {
  202. return err
  203. } else if err, mod.settings.eventsChannel = mod.StringParam("c2.channel.events"); err != nil {
  204. return err
  205. } else if err, mod.settings.controlChannel = mod.StringParam("c2.channel.control"); err != nil {
  206. return err
  207. } else if err, mod.settings.outputChannel = mod.StringParam("c2.channel.output"); err != nil {
  208. return err
  209. }
  210. mod.eventBus = mod.Session.Events.Listen()
  211. mod.client = irc.IRC(mod.settings.nick, mod.settings.user)
  212. if log.Level == log.DEBUG {
  213. mod.client.VerboseCallbackHandler = true
  214. mod.client.Debug = true
  215. }
  216. mod.client.Password = mod.settings.password
  217. mod.client.UseTLS = mod.settings.tls
  218. mod.client.TLSConfig = &tls.Config{
  219. InsecureSkipVerify: !mod.settings.tlsVerify,
  220. }
  221. if mod.settings.saslUser != "" || mod.settings.saslPassword != "" {
  222. mod.client.SASLLogin = mod.settings.saslUser
  223. mod.client.SASLPassword = mod.settings.saslPassword
  224. mod.client.UseSASL = true
  225. }
  226. mod.client.AddCallback("PRIVMSG", func(event *irc.Event) {
  227. channel := event.Arguments[0]
  228. message := event.Message()
  229. from := event.Nick
  230. if from != mod.settings.operator {
  231. mod.client.Privmsg(event.Nick, "nope")
  232. return
  233. }
  234. if channel != mod.settings.controlChannel && channel != mod.settings.nick {
  235. mod.Debug("from:%s on:%s - '%s'", from, channel, message)
  236. return
  237. }
  238. mod.Debug("from:%s on:%s - '%s'", from, channel, message)
  239. parts := strings.SplitN(message, " ", 2)
  240. cmd := parts[0]
  241. args := ""
  242. if len(parts) > 1 {
  243. args = parts[1]
  244. }
  245. if cmd == "join" {
  246. mod.client.Join(args)
  247. } else if cmd == "part" {
  248. mod.client.Part(args)
  249. } else if cmd == "nick" {
  250. mod.client.Nick(args)
  251. } else if err = mod.Session.Run(message); err == nil {
  252. } else {
  253. mod.client.Privmsgf(event.Nick, "error: %v", stripansi.Strip(err.Error()))
  254. }
  255. })
  256. mod.client.AddCallback("001", func(e *irc.Event) {
  257. mod.Debug("got 101")
  258. mod.client.Join(mod.settings.controlChannel)
  259. mod.client.Join(mod.settings.outputChannel)
  260. mod.client.Join(mod.settings.eventsChannel)
  261. })
  262. return mod.client.Connect(mod.settings.server)
  263. }
  264. func (mod *C2) onPrint(format string, args ...interface{}) {
  265. if !mod.Running() {
  266. return
  267. }
  268. msg := stripansi.Strip(str.Trim(fmt.Sprintf(format, args...)))
  269. for _, line := range strings.Split(msg, "\n") {
  270. mod.client.Privmsg(mod.settings.outputChannel, line)
  271. }
  272. }
  273. func (mod *C2) onEvent(e session.Event) {
  274. if mod.Session.EventsIgnoreList.Ignored(e) {
  275. return
  276. }
  277. // default channel or event specific channel?
  278. channel := mod.settings.eventsChannel
  279. if custom, found := mod.channels[e.Tag]; found {
  280. channel = custom
  281. }
  282. var out bytes.Buffer
  283. if tpl, found := mod.templates[e.Tag]; found {
  284. // use a custom template to render this event
  285. if err := tpl.Execute(&out, eventContext{
  286. Session: mod.Session,
  287. Event: e,
  288. }); err != nil {
  289. fmt.Fprintf(&out, "%v", err)
  290. }
  291. } else {
  292. // use the default view to render this event
  293. mod.stream.Render(&out, e)
  294. }
  295. // make sure colors and in general bash escape sequences are removed
  296. msg := stripansi.Strip(str.Trim(string(out.Bytes())))
  297. mod.client.Privmsg(channel, msg)
  298. }
  299. func (mod *C2) Start() error {
  300. if err := mod.Configure(); err != nil {
  301. return err
  302. }
  303. return mod.SetRunning(true, func() {
  304. mod.Info("started")
  305. for mod.Running() {
  306. var e session.Event
  307. select {
  308. case e = <-mod.eventBus:
  309. mod.onEvent(e)
  310. case <-mod.quit:
  311. mod.Debug("got quit")
  312. return
  313. }
  314. }
  315. })
  316. }
  317. func (mod *C2) Stop() error {
  318. return mod.SetRunning(false, func() {
  319. mod.quit <- true
  320. mod.Session.Events.Unlisten(mod.eventBus)
  321. mod.client.Quit()
  322. mod.client.Disconnect()
  323. })
  324. }