0

I'm working on a new project and I'd like to implement a "wait until the website is open" fonction, where it would look up if http://switch-check.cf/index.php is open and then continue.

For now with the help of .htaccess and php I tried my best for that all .php files are forbidden access. So if you try to access the webpage I mentioned you should get a

403 Access denied

So I'm using urllib (tried with requests too) to see if the website is open or still in forbidden access print(urllib.request.urlopen("http://switch-check.cf/index.php").getcode()) However whatever I try I always get a 200 HTTP status code, not a 403. Even if I try unexistant subdomains and files, the status code is always 200. Is there anyway to fix this? Or to achieve the same result I'm looking for with a different approach?>

Thank you :)

Tom
  • 571
  • 2
  • 11
  • 29
  • 2
    If you visit the same URL in your browser, do you also get success instead of a 403? If so, your problem has nothing to do with your Python code; it’s about configuring your server. I don’t know if that’s a question for Stack Overflow or for somewhere else like Server Fault, but it’s definitely not a question for the tags and description you’re using. – abarnert Jul 18 '18 at 17:34
  • Oh sorry, but on my browser and my phone I do get a "403 Access denied" page on the link I provided (as it should) – Tom Jul 18 '18 at 17:35
  • 1
    From the browser, I get a 302 error code, whereas I get 200 when I run Liam's python code. This looks like a Python question – Gelineau Jul 18 '18 at 17:36
  • Please put that information into the question. Meanwhile, you've tagged this `apache`, and what you're describing sounds like Apache configuration, but the response (both the 403 from Chrome and the 200 from requests) say `'Server': 'nginx'`. So… are you sure you're configuring the right server instance? – abarnert Jul 18 '18 at 17:56
  • After debugging this… it actually _is_ a server config problem, even though that wasn't obvious. See my answer for details. But this just means you need to open a new question on how to properly deny access in Apache—or in nginx, if your headers are correct. – abarnert Jul 18 '18 at 18:12

1 Answers1

4

The way to debug this is to try it in a browser (where you get a 403) and in your code (where you get a 200), compare the request headers, and bisect on the differences.

--

I did this using the "Network" panel in Chrome's devtools, and using requests so I can just print(page.request.headers).

From Chrome:

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cache-Control: max-age=0
Connection: keep-alive
Cookie: __test=9eea7a0d55374cb5b0673e2058581017
Host: switch-check.cf
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36

From requests:

User-Agent python-requests/2.18.4
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive

Before even getting to those headers: Chrome requested index.php?i=1 instead of just index.php. So apparently there was a redirect while I wasn't paying attention. And that redirect isn't happening in requests, which implies that it's likely scripted.

And meanwhile, I know I said to bisect, but the fact that there's a cookie there is immediately suspicious.


So, let's look at the actual 200 response, run through a pretty-printer:

<html>

<body>
    <script type="text/javascript" src="/aes.js"></script>
    <script>
        function toNumbers(d) {
            var e = [];
            d.replace(/(..)/g, function(d) {
                e.push(parseInt(d, 16))
            });
            return e
        }

        function toHex() {
            for (var d = [], d = 1 == arguments.length && arguments[0].constructor == Array ? arguments[0] : arguments, e = "", f = 0; f < d.length; f++) e += (16 > d[f] ? "0" : "") + d[f].toString(16);
            return e.toLowerCase()
        }
        var a = toNumbers("f655ba9d09a112d4968c63579db590b4"),
            b = toNumbers("98344c2eee86c3994890592585b49f80"),
            c = toNumbers("c4ba932dbf1d8d33ca88410be4f79eb0");
        document.cookie = "__test=" + toHex(slowAES.decrypt(c, 2, a, b)) + "; expires=Thu, 31-Dec-37 23:55:55 GMT; path=/";
        location.href = "http://switch-check.cf/index.php?i=1";
    </script>
    <noscript>This site requires Javascript to work, please enable Javascript in your browser or use a browser with Javascript support</noscript>
</body>

</html>

Well, there's your problem. You're not actually rejecting access to index.php at all; you're returning a 200 with some JavaScript that adds a randomized cookie and then redirects to index.php?i=1. And that's where you reject them.

Is it the cookie, or the redirect, that triggers the 403? Let's try both with Requests:

>>> r = requests.get('http://switch-check.cf/index.php', headers={'Cookie': '__test=9eea7a0d55374cb5b0673e2058581017'})
>>> r.status_code
403

>>> r = requests.get('http://switch-check.cf/index.php?i=1')
>>> r.status_code
200

So, you're only forbidding access based on a cookie that's generated by JavaScript.

What if we just send a nonsense cookie?

>>> r = requests.get('http://switch-check.cf/index.php', headers={'Cookie': '__test=' + '0'*32})
>>> r.status_code
403
>>> r = requests.get('http://switch-check.cf/index.php', headers={'Cookie': '__test=' + str(uuid.uuid4().hex})
>>> r.status_code
403

Wow. It actually has to be the right cookie, the one the server was expecting, or you don't get rejected? That's the opposite of the logic you'd normally want.


You could write some urllib or requests code to cooperate the way a browser does—either run a JS interpreter, or parse out the three numbers and AES them and build a cookie yourself. But that seems like a silly thing to do.

The right thing to do is to change the server to actually forbid access to index.php, instead of returning JS code that generates a special cookie that will allow you to get forbidden if you want.


How do you do that?

Well, you say:

with the help of .htaccess and php I tried my best for that all .php files are forbidden access

First, as far as I can tell, you think you're using Apache, and are following some guide somewhere to how to forbid access in Apache, but you're actually using nginx. (Look at the Server header in the responses.)

And meanwhile, I don't know what you're doing in PHP, but you probably got some code that's intended to require a valid cookie from a valid JS-running browser that's (a) wrong and gets it backward, (b) overly complicated, and (c) not what you wanted in the first place.

I don't know whether you have a PHP question here, or an nginx question on Server Fault, or something else. But that's the side you need to fix.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • Wow, thank you for your detailed explanation! I do realise now that I am using a nginx server (even though it was quite counterintuitive as the FTP hosting plan I'm using had .htaccess files pre-installed, and uses htdocs folders, but that's free hosting for you I guess) I've removed the .php file and .htaccess file, and I'm gonna try to start back from the beginning with an actual Apach server and this time with better documentation. Thank you for your help! – Tom Jul 18 '18 at 19:41