Juggling Facts

Target Information

  • IP: 139.59.167.169:32273

Exploitation

  • This problem came with nginx.conf and fpm.conf files, whereas the other problems did not. Inspecting these files did not yield any actionable intelligence.

    My guess is that they were simply included to make the whole Docker image work together, as PHP requires specific configurations to work with nginx.

  • Navigating to the "Secret Facts" tab tells us "Secrets can only be accessed by admin"

    The request to /api/getfacts with the payload {"type": "secrets"} returns the following response:

    {"message":"Currently this type can be only accessed through localhost!"}
    

    Of note, this endpoint only supports POST requests.

  • M@k3l@R!d3s$ is in the Entrypoint as the root user's password, so we can try logging in remotely to directly access the database:

    $ mysql -u root -p'M@k3l@R!d3s$' -h 139.59.167.169 -P 32273
    mysql: [Warning] Using a password on the command line interface can be insecure.
    ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 2
    

    This did not work, it hung on the warning message for a while before returning the error. Trying with -D -D web_juggling_facts for the specific database did not work either. This is probably because we are trying to access the database outside of localhost, so the same issue as the API endpoint.

    The --skip-name-resolve is set, but the localhost limitation is still enforced, so that doesn't get us anywhere.

  • The getfacts($router) function in IndexController.php can return the flag if the $_SERVER['REMOTE_ADDR'] is 127.0.0.1, so we need to trick the server into making an internal request to itself.

    I did some digging to see if I could spoof my IP address as localhost instead of sending a request from within the server, but the closest I could find is with the X-Forwarded-For header, which is not checked in this case. Any other method would result in me not getting the response data.

    We know now that the vulnerability is either some form of SQL injection or sending an internal request somehow. The SQL calls are made in FactModel.php, there doesn't appear to be any way to inject anything due to the nature of how the get_facts($facts_type) function is called, leading me to believe that sending an internal request is the only viable avenue of approach.

  • There is a function getRouteParameters($route) with no discernable reason for existing, so that may be open to exploitation.

    I tried http://139.59.167.169:32273/?type=secrets, but as expected, no dice. REMOTE_ADDR=127.0.0.1 didn't do anything either, but this is just grasping at straws.