This is a hack, but it works.

    UploadFile[url_, filePath_, urlParams___] := With[
      {
        bytes = Import[filePath, "Byte"],
        filename = StringJoin[FileBaseName[filePath], ".", FileExtension[filePath]]
      },
      URLExecute[
        url,
        urlParams,
        "Method" -> "POST",
        "MultipartElements" -> {
          {"file\"; filename=\"" <> filename, "application/octet-stream", bytes}
        },
        "Headers" -> {
          "Accept" -> "application/json; charset=UTF-8",
          "Content-Type" -> "multipart/form-data"
        }
      ]
    ]

Notice that I'm stuffing the `filename` parameter in the first element of `"MultipartElements"` along with the field name in order to get it in `Content-Disposition` for that element.

    (* Get a new ephemeral RequestBin from http://requestb.in/, then put URL below: *)
    UploadFile["http://requestb.in/1hyjbdl1", "ExampleData/rose.gif"]

result:

    Content-Disposition: form-data; name="file"; filename="rose.gif"

Theoretically you could also specify `"Content-Disposition" -> "form-data; filename=\"foo\""` in the request header, but the server would have to be expecting exactly one file in the form-data and parse accordingly, whereas the above approach with filenames in each part I think is more commonly expected.

---

**Edit**

In version 11, there's a no-hack way to do this:

    image = FindFile["ExampleData/Ocelot.jpg"];
    req = HTTPRequest[url, <|"Body" -> {"image" -> File[image]}|>];
    URLRead[req, "Body"]

[Docs](https://reference.wolfram.com/language/ref/URLRead.html) (see Scope > "To send files...")

**Edit 2** This evidently uses `expect: "100-continue"`, which is not supported by some common load balancers that may be between you and your server. Thus, it may not work in many cases.