Forum Discussion
Russell_Moore_8
May 10, 2012Nimbostratus
ActiveSync Windows Phone query decode
I used the following rule to decode and locate the Windows Phone device ID for access control to an ActiveSync/OWA service. The AS protocol allows the query to be plain text or base64 encoded hex. If you search Google for base64 ActiveSync you'll find the specification for this query method.
This rule works but I am studying it for optimization as I find it a bit ugly myself.
Feedback welcome! (The following code may contain snippets from other contributors for which I do not take credit but thank those contributors)
when HTTP_REQUEST {
create variable to contain the query string
set string_b64encoded [HTTP::query]
test the contents of the query string to see if it is base64 and if so place the content
in a variable
if {[catch {b64decode $string_b64encoded} string_b64decoded] == 0 and $string_b64decoded ne ""}{
scan the decoded content for the Device ID length
the "x4H2" format says to move forward 4 bytes and select the next 2 places
as HEX and put them in varible IDlenHEX
binary scan $string_b64decoded x4H2 IDlenHEX
convert HEX to decimal
scan $IDlenHEX %x IDlenDEC
multiply by two to get the correct character count
set IDlen [expr "$IDlenDEC * 2"]
knowing the DeviceID starts at the 6th pair we move "x5" to the that starting place
then select "H$IDlen" to put in variable HEXdeviceID
binary scan $string_b64decoded x5H$IDlen HEXdeviceID
try to match the found ID to a data group of allowed IDs
if { [matchclass $HEXdeviceID contains allowHEXdeviceIDs] } {
pool ASOWA.example.com_443
log local0. "Found ALLOWED Hexadecimal DeviceID: $HEXdeviceID"
} else {
log local0. "Found DENIED Hexadecimal DeviceID: $HEXdeviceID"
discard
}
}
}
- Russell_Moore_8Nimbostratus
when HTTP_REQUEST { create variable to contain the query string set string_b64encoded [HTTP::query] test the contents of the query string to see if it is base64 and if so place the content in a variable if {[catch {b64decode $string_b64encoded} string_b64decoded] == 0 and $string_b64decoded ne ""}{ scan the decoded content for the Device ID length the "x4H2" format says to move forward 4 bytes and select the next 2 places as HEX and put them in varible IDlenHEX binary scan $string_b64decoded x4H2 IDlenHEX convert HEX to decimal scan $IDlenHEX %x IDlenDEC multiply by two to get the correct character count set IDlen [expr "$IDlenDEC * 2"] knowing the DeviceID starts at the 6th pair we move "x5" to the that starting place then select "H$IDlen" to put in variable HEXdeviceID binary scan $string_b64decoded x5H$IDlen HEXdeviceID try to match the found ID to a data group of allowed IDs if { [matchclass $HEXdeviceID contains allowHEXdeviceIDs] } { pool ASOWA.example.com_443 log local0. "Found ALLOWED Hexadecimal DeviceID: $HEXdeviceID" } else { log local0. "Found DENIED Hexadecimal DeviceID: $HEXdeviceID" discard } } }
- Russell_Moore_8NimbostratusUpdated to look for either base64 encoded HEX or plain DeviceID query
when HTTP_REQUEST { set string_b64encoded [HTTP::query] if {[catch {b64decode $string_b64encoded} string_b64decoded] == 0 and $string_b64decoded ne ""}{ binary scan $string_b64decoded x4H2 IDlenHEX scan $IDlenHEX %x IDlenDEC set IDlen [expr "$IDlenDEC * 2"] binary scan $string_b64decoded x5H$IDlen HEXdeviceID set string_sentid [string toupper $HEXdeviceID] log local0. "EAS deviceID was HEX: $string_sentid" } else { set string_sentid [string toupper [URI::query [HTTP::uri] "DeviceId"]] } set string_URI [string tolower [HTTP::uri]] set string_useragent [string toupper [HTTP::header User-Agent]] set string_requestmethod [HTTP::method] if { $string_sentid != "" && [class match $string_sentid contains EASDeviceIDAllowed] } { log local0. "EAS Device ID match ALLOWED: URI: $string_URI DeviceID: $string_sentid Agent: $string_useragent Method: $string_requestmethod" pool AS-owa.example.com_443 } else { log local0. "EAS default no match DENIED: $string_URI DeviceID: $string_sentid Agent: $string_useragent Method: $string_requestmethod" discard } }
- Russell_Moore_8NimbostratusWarning. Currently in 10.2.3 the following code will leak memory.
- hooleylistCirrostratusHi Russell,
- hooleylistCirrostratusActually, it looks like this is it:
- Russell_Moore_8NimbostratusAaron,
- hooleylistCirrostratusThat's a novel sanity check you could add. But it still doesn't guarantee you'll avoid the memory leak. Basically, it checks if the query string length is evenly divisible by four. If it is, then the assumption is that it's a base64 encoded string. If it's not, then the input isn't attempted to be decoded.
- Russell_Moore_8NimbostratusI agree that your additional sanity check would be needed. Since we have a known leak when there is a failure of base64decode I am leery to try anything until I have a patch that would hopefully fix it. We have had at least one SEV1 production incident due to the leak so care is required. The code only impacts a small number of users at the moment so we have a bit more time luxury.
- hooleylistCirrostratusIf you do have the ability to wait for a hotfix that seems like the safest and simplest approach. Else, you could try adding more validation to avoid base64 decoding a non-base64 encoded string. It would be crufty, but maybe you could look for more than one = to determine that a query string isn't base64 encoded?
- Russell_Moore_8NimbostratusThat's another good suggestion. Thanks!
Recent Discussions
Related Content
Â
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects