C
C#2y ago
Kein

❔ HTTPclient fails to POST properly

Target website has a very basic login form, and I have no problems logging in via curl:
curl1 -vv -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36" -H "Referer: https://www.website.com/session/login" --cookie "PHPSESSID=ehoj1hg8daist388b72k8c2roe" -d "OWhVNUhsOE5ZS2ZIc1hWdWtiZ05pUT09=ZFoyZjBjeWJzTWJMdjkwQWVndlQyUT09&email=my%40mail.com&password=12345" -o N:/login.html https://www.website.com/session/login
curl1 -vv -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36" -H "Referer: https://www.website.com/session/login" --cookie "PHPSESSID=ehoj1hg8daist388b72k8c2roe" -d "OWhVNUhsOE5ZS2ZIc1hWdWtiZ05pUT09=ZFoyZjBjeWJzTWJMdjkwQWVndlQyUT09&email=my%40mail.com&password=12345" -o N:/login.html https://www.website.com/session/login
However, attempt to sent POST with HttpClient always fails:
const string baseURL = @"https://www.website.com";
HttpClient client = new HttpClient();
client.Timeout = new TimeSpan(0, 0, 30);
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36");
//---
// Parsing CRSF tokens and PHPSESSID from first pass
//---
client.DefaultRequestHeaders.Add("Cookie", phpSession);
var credentials = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string,string>(match.Groups[1].Value, match.Groups[2].Value),
new KeyValuePair<string,string>("email", "[email protected]"),
new KeyValuePair<string,string>("password", "12345"),
});
var req = new HttpRequestMessage(HttpMethod.Post, $"{baseURL}/session/login") { Content = credentials };
const string baseURL = @"https://www.website.com";
HttpClient client = new HttpClient();
client.Timeout = new TimeSpan(0, 0, 30);
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36");
//---
// Parsing CRSF tokens and PHPSESSID from first pass
//---
client.DefaultRequestHeaders.Add("Cookie", phpSession);
var credentials = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string,string>(match.Groups[1].Value, match.Groups[2].Value),
new KeyValuePair<string,string>("email", "[email protected]"),
new KeyValuePair<string,string>("password", "12345"),
});
var req = new HttpRequestMessage(HttpMethod.Post, $"{baseURL}/session/login") { Content = credentials };
The response should be 302 Found and then response header contain redirect to profile location, but I'm not getting it. I do get it with curl tho. So the issue is with Httpclient. Any idea what cold be the differences between curl and HttpClient that make the former work?
25 Replies
Buddy
Buddy2y ago
Does said website allow requests to a non-official api?
Kein
KeinOP2y ago
curl works just fine
Buddy
Buddy2y ago
I'm not talking about if it works. I'm talking about the terms of service.
canton7
canton72y ago
but I'm not getting it
What are you getting?
Kein
KeinOP2y ago
200 OK which is a normal request to session/login page, should be 302 found + redirect I really dont want to spend gazzlion of effort for the next few days making BURP work with https, so I can just inspect difference in headers, it is pain I was wondering may be someone who uses both curl and HTTP client knows where the former excels by default so I can just use the info
canton7
canton72y ago
I notice the referrer is different... But we're just taking it on trust that you've got all of the headers correct. First thing I'd check is the response body, see whether it contains e.g. an error message saying what's wrong. Second is to get fiddler up and running. It won't take a "gazillion" -- it'll take a few minutes, and you'll be able to see the exact difference between those two
Kein
KeinOP2y ago
I've compared the headers, here aint that much to differ, Content-type, User-agent (not even needed but for posterity) and cookie, that is. I will try fiddler, hopefully it is less pain then BURP
canton7
canton72y ago
Well, headers and body params, I mean I would just take a look at the response -- the server might be telling you what's wrong And yeah, fiddler is great. Sorts out its own SSL certs (I think you might need to click a button?), etc
Monsieur Wholesome
Use Fiddler and find the difference in the two requests made
Kein
KeinOP2y ago
lmao it does not work for my location, rip
Monsieur Wholesome
ah, I see fiddler somewhere in this convo
Kein
KeinOP2y ago
God I really have to go back to BURP Community and that cert nightmare
Kein
KeinOP2y ago
But yeah it does not make any sense for any header dot content do not match, I've printed the FormURLEncoded data and it is exactly what I send with cURL, same with the headers, cookie is added via DefaultRequestHeaders I dont think it has anything to do with it, I think it is some default client setup between curl and HTTPClient, the former just have it being sent by default because it is often used as REST API debugging tool so it makes sense to hone it for that case, where was HttpClient is too generic Essentially my question boilds down if anyone else stepped on the same rakes and figured the differences out
canton7
canton72y ago
Huh, it used to be entirely free, last time I looked That's a shame
Kein
KeinOP2y ago
Huh, so there is no default Accept: */* for httpclient HTTPToolkit shows the request is pretty much exactly the same, sans Accept which I can add but it wont change anything @canton7 you have experience sending binay data (images) as mutipart form with boundary with HTTPclient?
-----------------------------29077931424107458645579380474
Content-Disposition: form-data; name="uuid"

92da547b-ff8e-44af-aec5-f1c9f36ff65a
-----------------------------29077931424107458645579380474
Content-Disposition: form-data; name="batch"

R2N6cnpLdlRYUFU9
-----------------------------29077931424107458645579380474
Content-Disposition: form-data; name="file"; filename="12345.jpg"
Content-Type: image/jpeg
<BINARY_DATA_HERE>
-----------------------------29077931424107458645579380474
Content-Disposition: form-data; name="uuid"

92da547b-ff8e-44af-aec5-f1c9f36ff65a
-----------------------------29077931424107458645579380474
Content-Disposition: form-data; name="batch"

R2N6cnpLdlRYUFU9
-----------------------------29077931424107458645579380474
Content-Disposition: form-data; name="file"; filename="12345.jpg"
Content-Type: image/jpeg
<BINARY_DATA_HERE>
Do I need to compose it myself or is there a built-in boundary break
canton7
canton72y ago
Yeah there's a content class for that
canton7
canton72y ago
MultipartContent Class (System.Net.Http)
Provides a collection of HttpContent objects that get serialized using the multipart/* content type specification.
Kein
KeinOP2y ago
nice, thanks!
Kein
KeinOP2y ago
Do you know what the proper container to send content raw as in the example on the left:
Kein
KeinOP2y ago
If there is a way to avoid serializing rawstrings to bytes I will take it but otherwise I will go that way
canton7
canton72y ago
You mean, remove the content-type header? Just remove it from the HttpContent
Kein
KeinOP2y ago
No I meant per entry, I'm just gonna go for ByteArrayContent for these strings. However I still have this. Not sure where can I specify MIME type for only last part of the payload, which is JPEG:
var mp = new MultipartFormDataContent("---------------------------29077931424107458645579380474")
{
{ new ByteArrayContent(Encoding.ASCII.GetBytes("92da547b-ff8e-44af-aec5-f1c9f36ff65a")), "\"uuid\"" },
{ new ByteArrayContent(Encoding.ASCII.GetBytes("R2N6cnpLdlRYUFU9")), "\"batch\"" },
};
mp.Add(new ByteArrayContent(File.ReadAllBytes(@"12345.jpg")), "\"file\"", "\"12345.jpg\"");
var mp = new MultipartFormDataContent("---------------------------29077931424107458645579380474")
{
{ new ByteArrayContent(Encoding.ASCII.GetBytes("92da547b-ff8e-44af-aec5-f1c9f36ff65a")), "\"uuid\"" },
{ new ByteArrayContent(Encoding.ASCII.GetBytes("R2N6cnpLdlRYUFU9")), "\"batch\"" },
};
mp.Add(new ByteArrayContent(File.ReadAllBytes(@"12345.jpg")), "\"file\"", "\"12345.jpg\"");
canton7
canton72y ago
I'm confused as to what you want... Were you using a StringContent before, but you didn't want a Content-Type header? Just remove that header from the StringContent. It's added by default, but you can remove it Or there are constructors which let you set the value of that header explicitly new StringContent(string content, (Encoding?)null, (MediaTypeHeaderValue?)null) might do it?
Kein
KeinOP2y ago
@canton7 ah no, I figured it out, you need to force content type per payload:
new ByteArrayContent(data) { Headers = { {"Content-Disposition", @"form-data; name=""file""; filename=""12345.jpg"""}, {"Content-Type", "image/jpeg"} };
new ByteArrayContent(data) { Headers = { {"Content-Disposition", @"form-data; name=""file""; filename=""12345.jpg"""}, {"Content-Type", "image/jpeg"} };
Accord
Accord2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server