Batch request returns 400 Bad Request.
I convert Japanese character to Shift-JIS: "description": 譌・ (shift_jis)
This is what it contains:
--batch_request
Content-Type:multipart/mixed;boundary=changeset_1
--changeset_1
Content-Type: application/http
Content-Transfer-Encoding:binary
Content-Id: 1
POST https://.... HTTP/1.1
Accept: application/json
Content-Type: application/json
{\"objectId\":\"5f6851c3-99cc-4a89-936d-4bb44fa78a34\",\"description\":\"譌・\"}
--changeset_1--
--batch_request--
Client:
public async Task<List<string>> POSTBatch(string endpoint, string contentbody)
{
HttpResponseMessage response = null;
HttpRequestMessage batchRequest = null;
HttpContent httpContent = null;
try
{
var requestcontent = new DemoRequestContent(contentbody);
httpContent = requestcontent.GetHttpContent(Encoding.UTF8, text/plain);
httpContent.Headers.Add(DemoConst.CSRF_NONCE, getCSRF_NONE().Result);
httpContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/mixed;boundary=batch_request");
var method = new HttpMethod("POST");
batchRequest = new HttpRequestMessage(method, baseURL + endpoint);
batchRequest.Content = httpContent;
response = await httpClient.SendAsync(batchRequest);
.............
// Spilt response
var multipartRespMsgs = getMultiPart(response);
...............
}
catch (Exception ex)
{
}
}
The key is to add a new content type "msgtype" header to the response:
private async Task<List<HttpResponseMessage>> getMultiPart(HttpResponseMessage response){
var multipartContent = await response.Content.ReadAsMultipartAsync();
var multipartRespMsgs = new List<HttpResponseMessage>();
foreach (HttpContent currentContent in multipartContent.Contents) {
// Two cases:
// 1. a "single" response
if (currentContent.Headers.ContentType.MediaType.Equals("application/http", StringComparison.OrdinalIgnoreCase)) {
if (!currentContent.Headers.ContentType.Parameters.Any(parameter => parameter.Name.Equals("msgtype", StringComparison.OrdinalIgnoreCase) && parameter.Value.Equals("response", StringComparison.OrdinalIgnoreCase))) {
currentContent.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("msgtype", "response"));
}
multipartRespMsgs.Add(await currentContent.ReadAsHttpResponseMessageAsync());
// The single object in multipartRespMsgs contains a classic exploitable HttpResponseMessage (with IsSuccessStatusCode, Content.ReadAsStringAsync().Result, etc.)
}
// 2. a changeset response, which is an embedded multipart content
else {
var subMultipartContent = await currentContent.ReadAsMultipartAsync();
foreach (HttpContent currentSubContent in subMultipartContent.Contents) {
currentSubContent.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("msgtype", "response"));
multipartRespMsgs.Add(await currentSubContent.ReadAsHttpResponseMessageAsync());
// Same here, the objects in multipartRespMsgs contain classic exploitable HttpResponseMessages
}
}
}
}
In my example, testString contains:
{\"objectId\":\"5f6851c3-99cc-4a89-936d-4bb44fa78a34\",\"description\":\"譌・\"}
When go to case 1:
multipartRespMsgs.Add(await currentContent.ReadAsHttpResponseMessageAsync()); // 400 Bad Request
UPDATE: Server log
org.apache.catalina.connector.ClientAbortException: java.io.IOException: An established connection was aborted by the software in your host machine
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:372)
at org.apache.catalina.connector.OutputBuffer.flushByteBuffer(OutputBuffer.java:841)
at org.apache.catalina.connector.OutputBuffer.append(OutputBuffer.java:746)
at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:407)
at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:385)
at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:96)
at wt.servlet.ServletRequestMonitor$CountingOutputStream.write(ServletRequestMonitor.java:2388)
at java.util.zip.GZIPOutputStream.finish(GZIPOutputStream.java:168)
at wt.servlet.CompressionFilter$GzippingResponse.finish(CompressionFilter.java:623)
at wt.servlet.CompressionFilter$GzippingResponse.close(CompressionFilter.java:394)
at wt.servlet.CompressionFilter.doFilter(CompressionFilter.java:302)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at wt.servlet.RequestInterrupter.doFilter(RequestInterrupter.java:335)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at wt.servlet.ServletRequestMonitor.doFilter(ServletRequestMonitor.java:1660)
at wt.servlet.ServletRequestMonitorFilter.doFilter(ServletRequestMonitorFilter.java:56)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:543)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.ajp.AjpProcessor.service(AjpProcessor.java:524)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:818)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1637)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.io.IOException: An established connection was aborted by the software in your host machine
at sun.nio.ch.SocketDispatcher.write0(Native Method)
at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:51)
at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
at sun.nio.ch.IOUtil.write(IOUtil.java:65)
at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:471)
at org.apache.tomcat.util.net.NioChannel.write(NioChannel.java:136)
at org.apache.tomcat.util.net.NioBlockingSelector.write(NioBlockingSelector.java:101)
at org.apache.tomcat.util.net.NioSelectorPool.write(NioSelectorPool.java:157)
at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.doWrite(NioEndpoint.java:1322)
at org.apache.tomcat.util.net.SocketWrapperBase.doWrite(SocketWrapperBase.java:692)
at org.apache.tomcat.util.net.SocketWrapperBase.writeBlocking(SocketWrapperBase.java:485)
at org.apache.tomcat.util.net.SocketWrapperBase.write(SocketWrapperBase.java:409)
at org.apache.coyote.ajp.AjpProcessor.writeData(AjpProcessor.java:1390)
at org.apache.coyote.ajp.AjpProcessor.access$900(AjpProcessor.java:58)
at org.apache.coyote.ajp.AjpProcessor$SocketOutputBuffer.doWrite(AjpProcessor.java:1508)
at org.apache.coyote.Response.doWrite(Response.java:600)
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:360)
... 35 more
Please give me the solution to this problem. Thank you