So I have been testing quite a bit recently. A while back I ran into an application which had a Flex frontend. The Flex UI talked to a backend server which ran Flourine FX. This eventually talked to a .NET application - MSSQL Db combination. The Flex client used AMF 3.0 to talk to the server.
This whole thread by the way is just a sort of a rant on how I could NOT do things and all the things I failed at. It offers no solutions. It is however interesting if you want to know what to avoid. If that's okay..read on.
Now I knew that Burp had support for AMF for sure. And the application was browser based, so everything should have been normal. Testing for SQL Inj, XSS, Authorization bypass tend to take the most time in a test. Usually though, if you can reliably intercept and replay traffic, it is quite doable. I had no reason to think that this would be anywhere different; considering that Burp talked AMF.
a) Authorization Test
Now, this particular app had 2 types of users: user & manager. So I tried to replay a manager request as a user, but it kept failing. So I think..okay..protected. Then I took a menu which both users had access to. Replayed request. Fail. Huh? Both have access, why should it fail? Something very funny going on. Or maybe I have no clue (more likely :)). The last test I did was trap a user request and replay it as the same user, inside the same session, inside the same TAB. Surely this should work?? FAIL. Huh?
Now I'm confused. This means that something is happening ON the client itself. Sent 2 user requests to Burp Comparer. Turns out there are 3 values that change with every request. They are: ClientID, MessageID(under body) and DSId (under body and then headers). Now the ClientID and DSId didn't seem like they were too important, as in, tampering with those didn't give me an invalid request. However anytime I touched the MessageID, I was rebuffed.
So drilling down further MessageID seems to be of the structure of a 32 bit Guid. Spoofing an older valid message ID or a newer message ID or a pre-generated but not sent (Dropped request) message ID all fail. There is nothing that comes back in the response either; like an Anti CSRF token in a hidden field. So I am sure it is nothing that is stored on the server. If it isn't though, how does it recognize just THAT ONE message ID? And no... it does not seem to be all client side either. This is because I could see AMF requests being sent; dropping them also caused an error.
b) SQL Injection and XSS
At this point I hit a limitation with Burp. In a normal request (non AMF) you can add, modify and delete parameters. Right? So in AMF, while I can still modify data in individual parameters, I cannot add or delete anything through Burp.
This probably has something to do with the structure of the request. I tried Charles too, but have the same problem. Now I can sit and manually put a single quote and < > in every parameter but I'd probably die before I complete the test. Meaning...I cannot fuzz every parameter reliably using Burp. That's cause although there is repeater and intruder support to parse AMF, it doesn't detect the exact places properly...so I can choose which parameters to fuzz.
The closest I came was to carefully look at the 'Raw' request which tended to be just 1 value and fuzz just that. I got a few errors here but nothing concrete from a SQL Inj perspective. Ditto XSS. I tried deblaze, Pinta and a ton of tools which are already out there on the OWASP Flash page. None worked. It almost certainly meant I'd have to write my own client specially for FlourineFX. A custom BlazeDS client written by a colleague also failed. On this particular engagement I ran out of time.
The last thing I wanted to talk about was that the Response content type was x-amf. So all the Stack overflow and Google threads I read, talked about how this was real hard to do. I bounced this off a few guys and everyone did say...If there is no HTML content type responses...you can't get JS to execute. Which made sense.
c) CSRF
The fact that the message ID was 'unspoofable' automatically gave this Flex app protection against CSRF. No token. No nothing.
So in a nutshell, its super hard to test for SQL, XSS, CSRF and Replay traffic with existing tools. Almost certainly a custom FlourineFX client has got to be written. How and when and by whom I don't know. Maybe I'll write one some day :)
You guys have any ideas on how anything could have been done better? I saw a talk on BlackHat12 which talked about this. I'll check that out. That apart..anything?
This whole thread by the way is just a sort of a rant on how I could NOT do things and all the things I failed at. It offers no solutions. It is however interesting if you want to know what to avoid. If that's okay..read on.
Now I knew that Burp had support for AMF for sure. And the application was browser based, so everything should have been normal. Testing for SQL Inj, XSS, Authorization bypass tend to take the most time in a test. Usually though, if you can reliably intercept and replay traffic, it is quite doable. I had no reason to think that this would be anywhere different; considering that Burp talked AMF.
a) Authorization Test
Now, this particular app had 2 types of users: user & manager. So I tried to replay a manager request as a user, but it kept failing. So I think..okay..protected. Then I took a menu which both users had access to. Replayed request. Fail. Huh? Both have access, why should it fail? Something very funny going on. Or maybe I have no clue (more likely :)). The last test I did was trap a user request and replay it as the same user, inside the same session, inside the same TAB. Surely this should work?? FAIL. Huh?
Now I'm confused. This means that something is happening ON the client itself. Sent 2 user requests to Burp Comparer. Turns out there are 3 values that change with every request. They are: ClientID, MessageID(under body) and DSId (under body and then headers). Now the ClientID and DSId didn't seem like they were too important, as in, tampering with those didn't give me an invalid request. However anytime I touched the MessageID, I was rebuffed.
So drilling down further MessageID seems to be of the structure of a 32 bit Guid. Spoofing an older valid message ID or a newer message ID or a pre-generated but not sent (Dropped request) message ID all fail. There is nothing that comes back in the response either; like an Anti CSRF token in a hidden field. So I am sure it is nothing that is stored on the server. If it isn't though, how does it recognize just THAT ONE message ID? And no... it does not seem to be all client side either. This is because I could see AMF requests being sent; dropping them also caused an error.
b) SQL Injection and XSS
At this point I hit a limitation with Burp. In a normal request (non AMF) you can add, modify and delete parameters. Right? So in AMF, while I can still modify data in individual parameters, I cannot add or delete anything through Burp.
This probably has something to do with the structure of the request. I tried Charles too, but have the same problem. Now I can sit and manually put a single quote and < > in every parameter but I'd probably die before I complete the test. Meaning...I cannot fuzz every parameter reliably using Burp. That's cause although there is repeater and intruder support to parse AMF, it doesn't detect the exact places properly...so I can choose which parameters to fuzz.
The closest I came was to carefully look at the 'Raw' request which tended to be just 1 value and fuzz just that. I got a few errors here but nothing concrete from a SQL Inj perspective. Ditto XSS. I tried deblaze, Pinta and a ton of tools which are already out there on the OWASP Flash page. None worked. It almost certainly meant I'd have to write my own client specially for FlourineFX. A custom BlazeDS client written by a colleague also failed. On this particular engagement I ran out of time.
The last thing I wanted to talk about was that the Response content type was x-amf. So all the Stack overflow and Google threads I read, talked about how this was real hard to do. I bounced this off a few guys and everyone did say...If there is no HTML content type responses...you can't get JS to execute. Which made sense.
c) CSRF
The fact that the message ID was 'unspoofable' automatically gave this Flex app protection against CSRF. No token. No nothing.
So in a nutshell, its super hard to test for SQL, XSS, CSRF and Replay traffic with existing tools. Almost certainly a custom FlourineFX client has got to be written. How and when and by whom I don't know. Maybe I'll write one some day :)
You guys have any ideas on how anything could have been done better? I saw a talk on BlackHat12 which talked about this. I'll check that out. That apart..anything?
4 comments:
I don't necessarily know of any additional tools off top of my head that would help you.
To clarify, the message ID was pre-generated by the client software and was not something returned in a response value, yes? (meaning.... a macro to retrieve that msgid and send in a subsequent request would fail).
Thnx cktricky.
Yeah. Something seems to happen on the client that auto generates a 32 bit GUID (8bit-4bit-4bit-4bit-12bit) which cannot be reused. So no...a macro of that kind would not work.
I did try what you suggested, only I did it manually.
Hmm. No way to decompile the Flex Client and see how that number is generated? (I'm asking because I have no idea, just throwing out ideas)
Did that yeah. I used SWFScan to decompile the SWF. Got a big bunch of .as files. Action Script 3 if it helps.
I tried looking at things a little but time was against me and the fact that this was brand new didn't help. So no...I didn't exactly search hard enough, you can say.
One thing that I can tell you though is, that a colleague had written a tool to test a BlazeDs service (mine was Flourine as mentioned); he was using something like this in Python to generate a message ID -
_msg_id = str(uuid.uuid4()).upper()
... and then using that in an AMF request. So that seemed to be quite a random method of generation, so I didn't dig further.
Maybe, you know, it is 'supposed' to be random. But if that IS the case, how the *&^# does the server know?
The other sad part (from a testing point) was this was all HTTPS; so Wireshark also is useless. If it had been HTTP, maybe I could've seen if there was some other protocol being used to send and receive things.
I will mostly hack something up (some time :)) but want to get as many ideas till then. Do keep thinking aloud like now; it certainly helps even if not directly.
Thnx
Post a Comment