Блог пользователя prophet_

Автор prophet_, история, 4 года назад, По-английски

After investigating an issue resulting in a 403 error when trying to access codeforces as described in this blog: https://mirror.codeforces.com/blog/entry/80065

I believe I have found the issue and the solution.

Codeforces uses a "slow aes" decryption function to require users to perform a non-trivial amount of computational work before they can access the site, presumably to protect against malicious users spamming the server. A parameter is given based on the user's IP address and the user must decrypt using this to generate a RCPC token in order to access the site.

Those experiencing the 403 error likely are victims of a bug that causes the last 2 characters (last byte in binary) to be deleted. You can confirm this by checking your RCPC token in your cookies. This token should be 32 characters, but is only 30 if you experience this bug.

The aes javascript implementation is from here: https://mirror.codeforces.com/aes.min.js

I believe the issue is with the function "unpadBytesOut". In the image below I am logging the "bytesOut" variable, which stores the final token, before and after this function.

                console.log("BEFORE" ,bytesOut.toString(), bytesOut.length);
                this.unpadBytesOut(bytesOut);
                console.log("AFTER" ,bytesOut.toString(), bytesOut.length);

Console Log

As you can see, in this particular case, the last byte has been deleted by this function. I have found that around 8% of randomly generated aes parameters (the one based on your ip) has this issue.

If you are having this issue, download the javascript and run it locally, after removing the line calling this function. I am also happy to generate the token for anyone who has difficulty doing it themselves. If you send me your response from codeforces.com without redirects and I can send you the corrected token. If you're on linux or max for example, you can send me the response to the command "curl codeforces.com". Note that this token won't compromise the security of your account as I believe it is purely to protect again a DDOS by verifying the IPs.

I hope MikeMirzayanov can get this fixed as soon as possible.

UPD: I believe the issue has now been resolved. The aes.min.js has been updated with an additional conditional in the previously broken unpadBytesOut function. Below is a diff of the new change:

Diff

UPD: I have written an ad hoc script that may serve as a potential foundation for fixing various cf tools broken by this. You can find more about this here: https://mirror.codeforces.com/blog/entry/80135

  • Проголосовать: нравится
  • +232
  • Проголосовать: не нравится

»
4 года назад, # |
  Проголосовать: нравится +15 Проголосовать: не нравится

How did you do that?

  • »
    »
    4 года назад, # ^ |
    Rev. 4   Проголосовать: нравится +21 Проголосовать: не нравится

    403 generally means that an authorization is provided but is invalid (opposed to 401 where authorization is not provided). This lead me to suspect the issue laid in the token.

    Critically I made the insight, after further investigation, that the RCPC token in the above linked blog was a shorter length than my RCPC token, as well as other RCPC tokens I generated. This lead me to suspect that the problem was with the client side code that generated the token.

    By using curl, I downloaded the codeforces.com page (before redirect to the actual site) and found the link to the aes implementation with the parameters. Testing locally, I noticed that only one value changed between different requests with different IPs, namely the "cipherIn" parameter for the aes decrypt function.

    I reverse engineered this function by testing the aes js locally, leading me to find the exact bug. Furthermore, this allowed me to fix my local aes code, and decrypt the missing byte using the provided initial parameters (also included in the original blog post).

»
4 года назад, # |
  Проголосовать: нравится +25 Проголосовать: не нравится

Codeforces uses a "slow aes" decryption function to require users to perform a non-trivial amount of computational work before they can access the sight

To clarify, it's "slow" because it runs in JS (SlowAES)

Those experiencing the 403 error likely are victims of a bug that causes the last 2 characters (last byte in hexadecimal) to be deleted.

Small correction, more characters may also be deleted. From the implementation I can see it that the padding scheme is to pad it with the byte equal to the number of padding bytes required.

I'm not sure what this measure is supposed to prevent though, it can be somewhat easily bypassed.
What it has achieved is broken a bunch of existing CF tools.

  • »
    »
    4 года назад, # ^ |
      Проголосовать: нравится +8 Проголосовать: не нравится

    Thank you for your comment.

    During my testing, I have run 10**7 random parameters, around 8% of which got the last byte deleted, and the rest remained fully intact. I have yet to investigate further into how the padding works, but these results have lead me to conclude only the last byte may be deleted by this bug.

    However I can not say for certain that this is the case as my conclusion is based off of statistics rather than grounded in logic.

»
4 года назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

UPD: I believe the issue has now been resolved. I have updated the blog with the diff of the new code.

  • »
    »
    4 года назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    The codeforces related tools are still not functional, will this new decryption requirement permanently break them?

    • »
      »
      »
      4 года назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      It shouldn't be very difficult to create a bypass for the new token system, as the decryption protocol is open source. Furthermore, you only need to generate the token once per IP address. Even without a local aes implementation, you could simply read the RCPC token from your browser's cookies, and append it as a header for all cf requests. This could work as a quick ad hoc fix.

»
4 года назад, # |
  Проголосовать: нравится +43 Проголосовать: не нравится

Nice! I always enjoy these kinda reverse engineering problems.

»
4 года назад, # |
Rev. 2   Проголосовать: нравится +8 Проголосовать: не нравится

Yesterday I also received 403 error.

I think its because the recent security update, it might have changed the way cookie codes, and I also noticed that CF tool and some software with CF on phone was broken.

I fixed the 403 problem by erasing old cookie and re-login.

But still a curious question, why I can enter CF with proxy server while I receive 403 if I don't do so?

  • »
    »
    4 года назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    The initial AES parameters changed based on your IP. The bug only effects a small percentage of these parameters, from my testing, around 8%. It seems that only your initial IP was part of this 8%, while your proxy IP was not.

»
4 года назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

Codeforces has added this again now... Edit: Wrong blog, sorry