Recently I run into the problem of figuring out what was wrong with a combination of parameters I needed to use the Amazon Simple Queue Service -SQS for short- (more information here). The Amazon SQS requires the following query string parameters when establishing a HTTP get request:

http://END-POINT/ACCOUNT#/QUEUE-NAME?AWSAccessKeyId=ACCESS-KEY&Action=SendMessage&MessageBody=hello%20world&SignatureMethod=HmacSHA1&SignatureVersion=2&Timestamp=2012-12-11T13%3A14%3A02&Version=2012-11-05&Signature=YOUR-CALCULATED-SIGNATURE

After reading MANY Amazon forums plus the official documentation I figured out that it’s tricky defining what parameters are required and most importantly, in what format. For example: some forums say the ACCOUNT# and QUEUE-NAME are required, others don’t; some say the time stamp time zone needs to be included, some others don’t.

So I came up with a solution for looking the right parameters and formats in an efficient way. I listed all parameters which potentially could cause the issue as follows:

END-POINT
Ireland end point (HTTP) OR Global end point (HTTP) OR
Ireland end point (HTTPS) OR Global end point (HTTPS) OR
OR Ireland end point (HTTP) plus %0A at the end

QUEUE-NAME (within the signature):
Empty OR with queue name OR with queue name plus account number

Timestamp:
Url Enconded OR Not Url Encoded
AND
with time zone OR without time zone
AND
based on the current time OR based on the current UTC time

Query String Separator:
Ampersand (&) OR Url encoded ampersand

Protocol
HTTP OR HTTPS

Query String Parameters’ ordering:
Lexicographically or random

Signature result:
Url encoded OR not URL encoded

Server end point:
Including Account# plus queue name OR only the end point address

After listing the possible alternatives I did some filtering according to what I thought the most likely working parameters were,  otherwise I would had to test more than 1.000 combinations. The following is the filtered list:

(A) Ireland end point (HTTP)
(B) Ireland end point (HTTP) plus %0A at the end
(C) With queue name
(C1) With queue name plus account number
(D) Timestamp: Url Enconded
(E) Timestamp: with time zone
(E1) Timestamp: without time zone
(F) Timestamp: based on the current time
(F1) Timestamp: based on the current UTC time
(G) Ampersand query string separator
(H) HTTP protocol
(I) Lexicographically ordering
(I1) Random ordering
(J) URL encoding the signature result
(K) Including Account# plus queue name

With the previous filtered list in my hands I only had to find the combinations. So I used PICT (I already commented it in a previous post here). I built the following model in a text file named model.txt:

Hostname: A, B
Quename: C, C1
Timestamp1:D
Timestamp2:E, E1
Timestamp3:F, F1
General1: G
General2: H
General3: I, I1
General4: J
General5: K

Then I instructed PICT to sign my model and changed the default order of the combinations from 2 to 10 (because I want to test all my 10 variables) with the following line:

pict model.txt /o:10 > model.xls

And I got the following combinations:

amazon_http_get_request_pict

Then I applied some filtering again because the (I1) is technically valid but it makes no sense a random order if you already have one in place. So I filtered again and got the following nice data set of 16 items:

amazon_http_get_request_pict_items

I wrote a function to create a query string and then I automated the creation of the 16 test cases with the following code:

string A = "sqs.eu-west-1.amazonaws.com";
 string B = "sqs.eu-west-1.amazonaws.com%0A";
 string C = "/";
 string C1 = "/YOUR_ACCOUNT_NUMBER/YOUR_QUEUE_NAME";
 string DE1F1 = DateTime.Now.ToString("s");
 DE1F1 = HttpUtility.UrlEncode(DE1F1).ToUpper();
 string DE1F = DateTime.UtcNow.ToString("s");
 DE1F = HttpUtility.UrlEncode(DE1F).ToUpper();
 string DEF1 = DateTime.Now.ToString("s") + "Z";
 DEF1 = HttpUtility.UrlEncode(DEF1).ToUpper();
 string DEF = DateTime.UtcNow.ToString("s") + "Z";
 DEF = HttpUtility.UrlEncode(DEF).ToUpper();

string G = "&";
 string H = "http";
 bool I = false; //Not possible
 bool I1 = true;
 bool J = true;
 string K = "/YOUR_ACCOUNT_NUMBER/YOUR_QUEUE_NAME";
 string url = "";
 string canonicalStr = "";

//Case #: 1
 ParametersFinder(A, C1, DE1F1, G, H, I1, J, K, out url, out canonicalStr);
 //Case #: 2
 ParametersFinder(B, C, DE1F1, G, H, I1, J, K, out url, out canonicalStr);
 //Case #: 3
 ParametersFinder(B, C1, DE1F, G, H, I1, J, K, out url, out canonicalStr);
 //Case #: 4
 ParametersFinder(B, C1, DE1F1, G, H, I1, J, K, out url, out canonicalStr);
 //Case #: 5
 ParametersFinder(B, C, DEF1, G, H, I1, J, K, out url, out canonicalStr);
 //Case #: 6
 ParametersFinder(A, C, DE1F1, G, H, I1, J, K, out url, out canonicalStr);
 //Case #: 7
 ParametersFinder(A, C1, DEF, G, H, I1, J, K, out url, out canonicalStr);
 //Case #: 8
 ParametersFinder(A, C, DEF, G, H, I1, J, K, out url, out canonicalStr);
 //Case #: 9
 ParametersFinder(B, C, DE1F, G, H, I1, J, K, out url, out canonicalStr);
 //Case #: 10
 ParametersFinder(A, C, DE1F, G, H, I1, J, K, out url, out canonicalStr);
 //Case #: 11
 ParametersFinder(A, C, DEF1, G, H, I1, J, K, out url, out canonicalStr);
 //Case #: 12
 ParametersFinder(B, C, DEF, G, H, I1, J, K, out url, out canonicalStr);
 //Case #: 13
 ParametersFinder(A, C1, DE1F, G, H, I1, J, K, out url, out canonicalStr);
 //Case #: 14
 ParametersFinder(A, C1, DEF1, G, H, I1, J, K, out url, out canonicalStr);
 //Case #: 15
 ParametersFinder(B, C1, DEF, G, H, I1, J, K, out url, out canonicalStr);
 //Case #: 16
 ParametersFinder(B, C1, DEF1, G, H, I1, J, K, out url, out canonicalStr);

Finally I run the code, recorded the the result of each ParametersFinder call to a file and quickly tested them in my favorite web browser. At the end I found the right parameters and it was a good exercise. Certainly there are tons of ways to take desitions like this, tons of tools and tons of things to improve in this solution but due the fact that actually this is something  you do not have to do every day then a simple yet powerful set of tools and methods like these ones help you to be successful in this kind of black operations.

Thanks,

Cheers,

Javier Andrés Cáceres Alvis

Microsoft Most Valuable Professional – MVP
Intel Black Belt Software Developer