codemanki / cloudscraper

--DEPRECATED -- 🛑 🛑 Node.js library to bypass cloudflare's anti-ddos page
MIT License
603 stars 141 forks source link

Cloudfare POST request returns error code 500: "This domain does not exist" #255

Closed ConorEB closed 5 years ago

ConorEB commented 5 years ago

Hello! I am trying to bypass a site called BSTN. They recently implemented Cloudflare and I have decided to use your library to bypass it. You can tell if you visit the link: https://raffle.bstn.com/air-jordan-1-retro-high-og-obsidian- that they have Cloudflare enabled. I tried GET requests using cloud scraper to their raffle page and that worked fine however the POST endpoint: https://raffle.bstn.com/api/register returns the error:

{"name":"GeneralError","message":"Forbidden: This domain does not exist","code":500,"className":"general-error","data":{},"errors":{}}

My code for the post request is:

var cloudscraper = require('cloudscraper');

var options = {
    method: 'POST',
    url: 'https://raffle.bstn.com/api/register',
    headers: {
        'cache-control': 'no-cache',
        Referer: 'https://raffle.bstn.com/air-jordan-1-retro-high-og-obsidian-',
        Connection: 'keep-alive',
        'Content-Type': 'application/json;charset=utf-8',
        'Accept-Language': 'en-US,en;q=0.5',
        Accept: 'application/json, text/plain, */*',
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:68.0) Gecko/20100101 Firefox/68.0'
    },
    body: '{"additional":{"instagram":"hdbfff"},"title":"male","email":"test@gmail.com","firstName":"Fake","lastName":"Name","street":"Yesfv Avenue","streetno":"3132","address2":"","zip":"60141","city":"New York","country":"US","acceptedPrivacy":true,"newsletter":false,"state":"New York","recaptchaToken":"(insertValidRecaptchaToken)","raffle":{"raffleId":"air-jordan-1-retro-high-og-obsidian-","parentIndex":0,"option":"40"},"issuerId":"raffle.bstn.com"}'
};

cloudscraper.post(options).then(console.log);`

My version of Cloudscraper is 4.1.4 This error occurs on every request using a normal cloudflare request. The way I got it to work locally is:

Code snippet ```js var cloudscraper = require('cloudscraper'); var request = require("request"); var rp = require('request-promise'); cloudScraper.debig = true cloudScraper(); function cloudScraper() { var options = { method: 'POST', url: 'https://raffle.bstn.com/api/register', headers: { 'cache-control': 'no-cache', Connection: 'keep-alive', 'Accept-Language': 'en-US,en;q=0.5', Accept: 'application/json, text/plain, */*', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:68.0) Gecko/20100101 Firefox/68.0' }, body: '{"additional":{"instagram":"hdbfff"},"title":"male","email":"test@gmail.com","firstName":"Fake","lastName":"Name","street":"Yesfv Avenue","streetno":"3132","address2":"","zip":"60141","city":"New York","country":"US","acceptedPrivacy":true,"newsletter":false,"state":"New York","recaptchaToken":"03AOLTBLQt8oFAs7FHLdt12D2hrroUdIEexUALXv9msV_1nMwVOZ3IiIrl_-Oo4lDXxwO6hiV6zwo_3nKHlS8w16u9-R4cnn-ZcNvuLTkH04C6Fl5T6KCG1JPM0ysebufyuxsH5S9vUJNWfgP7ej1hE1nybfd9_VjqWeq8o_f-QolO45eqst3DCrZ4FYDinsNwzB3w84UaqihYfcO3HLR3fVBMcJM4C5HIBS2n1xyZKccbxeTcAr__BWrrS9VOuUidKb8RKa6fz8NcGXz0EC4a2Oxav5g1aj9DrNtOsyDo3yuma6a8h5XGVbpD8MfeStk3QqmY_LT8znnE","raffle":{"raffleId":"air-jordan-1-retro-high-og-obsidian-","parentIndex":0,"option":"40"},"issuerId":"raffle.bstn.com"}', JSON: true }; cloudscraper.post(options).then(onResponse).catch(onError); async function onResponse(response) { await delay(4000) var request = await response.request.toJSON() var headers = await JSON.stringify(response.headers, null, 2); var cookies = JSON.stringify(request["headers"].cookie).split(";") await console.log("Clearance: " + cookies[1].replace(`"`, "")) await console.log("UID: " + cookies[0].replace(`"`, "")) submitRaffle(cookies[0].replace(`"`, ""), cookies[1].replace(`"`, "")) } function onError(error) { console.error(error.stack); if (error.cause) { console.log('Cause: ', error.cause); } if (error.response) { onResponse(error.response); } } } function submitRaffle(uid, clearance) { var cookie = `_ga=GA1.2.860778441.1565723692; cookieconsent_status=dismiss; ${uid}; __cf_bm=3892a44b19e11906234dd85e0e6a812495735938-1567037712-1800-AUyxq0xIEoeer5COx5/3mL8k659l+fBOGmFA85z+3YgE+0+zfKNkujSUPrh3cMhOejH7411YkYbcKLRTlSmKByU=; _gcl_au=1.1.1318149485.1567037735; _gid=GA1.2.728282739.1567037736; ${clearance}` var body = '{"additional":{"instagram":"conor.de"},"title":"male","email":"conorebeling@gmail.com","firstName":"Conor","lastName":"Ebeling","street":"Wesley Avenue","streetno":"1325","address2":"","zip":"60201","city":"Evanston","country":"US","acceptedPrivacy":true,"newsletter":false,"state":"Illinois","recaptchaToken":"03AOLTBLQUZj3k8q7ZN-lyTVzVcqI8kcLaVqHDe_7Bl3GbeV5VW4ZjrfqzSVs-YZnhYHZ2h3RYkVLRhUTtmyhBLBYVRNZY7EP_YuNL1WAP4iZbSD9fJtZDlEyfQyTM57g96Zn5wVaNPXu0roVjRfgW-kG7pARZWvkBAnmFXqtp4et6XWIvtcM3wdP2c4eU9qpCv5XvZnFeveuLKp4ZgxZHKMEVm-wHD4TMYbxkBGSoC2t31ukXfLGUJo8A_045wRMdS-NPBroyDoDvBVNbAc7k5lbJcFVfSz9LQ25xtd9Udr5bXG02WcnE8Z-JW3H6_ILh9J0EyVFneYVc","raffle":{"raffleId":"air-jordan-1-retro-high-og-obsidian-","parentIndex":0,"option":"40"},"issuerId":"raffle.bstn.com"}' console.log("Final Cookie: " + cookie) var options = { method: 'POST', url: 'https://raffle.bstn.com/api/register', headers: { 'cache-control': 'no-cache', 'Content-Length': '767', Host: 'raffle.bstn.com', 'Cache-Control': 'no-cache', Cookie: cookie, Referer: 'https://raffle.bstn.com/air-jordan-1-retro-high-og-obsidian-', Connection: 'keep-alive', 'Content-Type': 'application/json;charset=utf-8', 'Accept-Language': 'en-US,en;q=0.5', Accept: 'application/json, text/plain, */*', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:68.0) Gecko/20100101 Firefox/68.0' }, body: body }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log("Status: " + response.statusCode); console.log("Body: " + body); }); } function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } ```

I have tried using valid Recaptcha tokens and it makes no difference. Please let me know if you have any insight into this error, thanks!

ghost commented 5 years ago

Hi @ConorEB,

The error has nothing to do with Cloudscraper. It's a rest API error so if you were to simulate the exact same request with your browser, you'd get the same response. If there was an error with cloudscraper, you'd see a stacktrace unless things REALLY went bad.

The error doesn't have anything to do with Cloudflare either. If the response was from Cloudflare, there would be a Server: cloudflare header. The response type is JSON, in this scenario, Cloudflare wouldn't respond like that.

'Content-Type': 'application/json;charset=utf-8',

I don't know if you're misusing the server's rest API or if the server is just buggy but there's nothing we or Cloudflare can do to fix this. You'll need to determine what the problem is on your own.

Cheers

ConorEB commented 5 years ago

Still having issues, tried a request-promise request and it failed but regular request-js works. Is there a way that I can just get the cookies to pass to request-js? Or use request-js instead of the promise version.

ghost commented 5 years ago

Yes and yes.

But first would you mind editing your issue?

What works with request but doesn't work with Cloudscraper?

ConorEB commented 5 years ago

Done! Github is not making all of my code formatted correctly so sorry about that :/

ghost commented 5 years ago

I'm just guessing but if it worked with request but not request-promise then the problem you're experiencing most likely bulls down to the response status code not being 2xx. The reason this makes sense is because request-promise doesn't do anything different from request, it uses request, same options, etc.

Maybe try simple: false so request-promise doesn't complain?

I'll take a more in-depth look a little later. Until then, you can try to use request instead of request-promise:

// The callback argument is required when using `request` as the requester.
const cloudscraper = require('cloudscraper').defaults({ requester: require('request') });
ConorEB commented 5 years ago

Thanks for the help! FYI: When I try using request like that that this error pops up: throw new TypeError('Expected a callback function, got ' + ^

TypeError: Expected a callback function, got undefined instead.

ghost commented 5 years ago

@ConorEB

I've checked the code. The only difference between request and request-promise is the latter throws a StatusCodeError for non-2xx responses (500 in this case). The only difference between request or request-promise and Cloudscraper is the response is Cloudflare's IUAM JS challenge response when not using Cloudscraper. When using Cloudscraper, the challenge is solved for you and the rest API error which is a user error is seen.

TypeError: Expected a callback function, got undefined instead.

You have to use a callback as I stated when I provided the example code. My apologies but this isn't a problem with any of the libraries or Cloudflare. You need to figure out how to use the site's API properly.

Good luck

ConorEB commented 5 years ago

Hey, last thing before I go off on my own. I noticed that it seems to be sending a GET even though I said POST Request { _events: [Object], _eventsCount: 4, _maxListeners: undefined, requester: [Function], headers: [Object], cloudflareMaxTimeout: 30000, followAllRedirects: true, challengesToSolve: 2, decodeEmails: false, gzip: true, agentOptions: [Object], method: 'GET', url: [Url], realEncoding: 'utf8', encoding: null, callback: [Function], uri: [Url], readable: true, writable: true, explicitMethod: true, _qs: [Querystring], _auth: [Auth], _oauth: [OAuth], _multipart: [Multipart], _redirect: [Redirect], _tunnel: [Tunnel], _rp_resolve: [Function], _rp_reject: [Function], _rp_promise: [Promise], _rp_callbackOrig: [Function], _rp_options: [Object], setHeader: [Function], hasHeader: [Function], getHeader: [Function], removeHeader: [Function], localAddress: undefined, pool: [Object], dests: [], __isRequestRequest: true, _callback: [Function: RP$callback], proxy: null, tunnel: true, setHost: true, originalCookieHeader: undefined, _jar: [RequestJar], port: 443, host: 'raffle.bstn.com', path: '/api/register', httpModule: [Object], agentClass: [Function], agent: [Agent], cloudscraper: true, href: 'https://raffle.bstn.com/api/register', ntick: true, response: [Circular], originalHost: 'raffle.bstn.com', originalHostHeaderName: 'Host', _started: true, req: [ClientRequest], responseContent: [Circular], _destdata: true, _ended: true }, toJSON: [Function: responseToJSON], caseless: Caseless { dict: [Object] }

ghost commented 5 years ago

The first request in your snippet is a POST request. The second request in your snippet defaults to a GET request because the method was not explicit. I can tell that's the second request because the JSON: true (which is a typo) isn't set on the request object. It should be json: true btw.

Try correcting some of the the typos:

// cloudscraper.debig = true;
cloudscraper.debug = true; // <-- So you can see the debug information
cloudscraper.get({ url, json: true })
ConorEB commented 5 years ago

Fixed the typos and json:true. I verified that it has to do with GET/POST because I copied the cookies over to postman and it gave the same error when using GET. I am defining both cloudscraper.post(options) and method:"POST" in both requests so I am confused when you say my second request defaults to GET. Thanks for the help by the way... I see that this is totally my fault and just wanted to let you know that what you are doing is amazing and to keep it up :).

ghost commented 5 years ago

Thanks,

Cloudscraper never specifies or changes the request method unless you're using the reCAPTCHA helper API and you're not using that. The underlying request library might change the request method to get in the case of 3xx redirects but I forget. In any case, I can tell you that none of these libraries are playing tricks on you. If you use the verb methods e.q. request.get or cloudscraper.post the method will be overridden to GET or POST respectively. So if you use the verb methods, the method option will be ignored.

It's easy to see what requests are being made: cloudscraper.debug = true

I hope you get everything working!

ConorEB commented 5 years ago

The data that I showed you above was from cloudscraper.debug = true. Which is why I was confused why I was getting a GET instead of POST even though I defined

` var options = { method: 'POST', url: 'https://raffle.bstn.com/api/register', headers: { 'origin': 'raffle.bstn.com', 'accept-language': 'en-GB,en-US;q=0.9,en;q=0.8', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36', 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', 'accept': 'application/json, text/javascript, /; q=0.01', 'referer': 'https://raffle.bstn.com/air-jordan-1-retro-high-og-obsidian-', 'authority': 'raffle.bstn.com', 'x-requested-with': 'XMLHttpRequest' }, body: body, json: true };

cloudscraper.post(options).then(console.log, console.error)`
ConorEB commented 5 years ago

Here is my entire code snippet, you can tell me if I am defining anything incorrectly. I will also include the debug details.


var cloudscraper = require('cloudscraper');
cloudscraper.debug = true

submitRaffle();

async function submitRaffle() {
    var body = await hidingBody (it works)

    var options = await {
        method: 'PUT',
        url: 'https://raffle.bstn.com/api/register',
        headers: {
            'origin': 'raffle.bstn.com',
            'accept-language': 'en-GB,en-US;q=0.9,en;q=0.8',
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
            'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'accept': 'application/json, text/javascript, */*; q=0.01',
            'referer': 'https://raffle.bstn.com/air-jordan-1-retro-high-og-obsidian-',
            'authority': 'raffle.bstn.com',
            'x-requested-with': 'XMLHttpRequest'
        },
        body: body,
        json: true
    };

    await cloudscraper(options).then(console.log, console.error)

}```
ghost commented 5 years ago

@ConorEB

I stand corrected, you are specifying POST for both requests. The reason you're seeing the GET is because of redirects where request appears to be changing the method to GET. That behavior is to be expected with redirects.

REQUEST redirect /api/register
REQUEST redirect to /api/register

The solution:

const cloudscraper = require('cloudscraper');

const xhrHeaders = Object.assign({}, cloudscraper.defaultParams.headers, {
  'X-Requested-With': 'XMLHttpRequest'
})

cloudscraper.debug = true;

const  options = {
  url: 'https://raffle.bstn.com/api/register',
  headers: xhrHeaders,
  json: true,
  formData: {
    foo: 'bar'
  }
};

cloudscraper.get({ simple: false, url: 'https://raffle.bstn.com/api/register' }).then(() => {
  // Now that we have the cf_clearance cookie
  return cloudscraper.post(options).then(console.log);
}).catch(console.error);
ConorEB commented 5 years ago

Hey, I think we are almost there but still getting some errors... can we chat in https://tlk.io/cloudflare to make it easier?

ConorEB commented 5 years ago

I really appreciate all of the help by the way, I just need to drive it home :)

ghost commented 5 years ago

The followOriginalHttpMethod option is supported by requests and thus by Cloudscraper as well.

requests README excerpt



Note: The followAllRedirects defaults to true when using Cloudscraper.

ConorEB commented 5 years ago

Hey thanks that seems to do the trick (sorry for the late reply). The site or cloudflare seemed to have flagged my IP so I am working on getting good proxies to use. Do you have any recommendations as to why cloudflare seems to detect my server every time I try to run the script on it? Not sure if it has to do with specific ciphers or my IP. Anyways let me know, I will be here 🙂

Sent with GitHawk

ConorEB commented 5 years ago

@pro-src

Sorry for the tag, just hoping you saw this

ghost commented 5 years ago

Hey @ConorEB,

You can rule out the IP issue by tunneling your local traffic through your remote server. I recommend using Chromium (Google Chrome) for a very clear test since it uses BoringSSL. If you experience the same problem in Chromium when tunneling, it's an IP issue.

If it's not an IP issue or you're hoping for an easier way to determine the cause, here's a couple of things that you may try:

If you need to know which ciphers are being sent, you can use https://www.howsmyssl.com/a/check

const cloudscraper = require('cloudscraper')
cloudscraper.get({ uri: 'https://www.howsmyssl.com/a/check', json: true }).then(console.log)

The TLS inspection conducted by Cloudflare goes beyond checking which cipher suite is advertised by the client and excluding ciphers might not help. AFAIK, Cloudflare's TLS checks only flag insecure TLS connections, meaning things like SHA1 being in the signature algorithms will result in a CAPTCHA.

You can reach me on IRC.