1

I have the following script:

from twisted.internet import reactor
import time,hashlib,urllib2,json,treq
from urllib import urlencode

#This is used to print out the Password that is found. This is called at the
# end of each loop. And checks if response code == 200.
def done(response):
    if response.code == 200:
        sys.stdout.write( Password + "FOUND" )
#The Password is basically a 4 digit number, the line under starts with number 0.
PasswordStart = 0
#This is an array to make sure that the script does not do double requests to the host.
executed = []
#Loop which runs the URL request 10000 times
while PasswordStart<9999:
    #Checks if PasswordStart is in array
    if PasswordStart not in executed and PasswordStart<9999:
        #Since PasswordStart is not in array, it will add it to the array
        #and then run the rest of the code.
        executed.append(PasswordStart)
        #Makes a variable of the time/date, used later in headers
        Timing = time.strftime("%Y-%m-%dT%H:%M:%S.00+00:00")
        #Just four variables for registration date, which is used later in
        # the datas_p variable
        YearRegD = time.strftime("%Y")
        DateRegD = time.strftime("-%m-%d")
        YearRegD2 = str((int(YearRegD)-1))
        RegD = YearRegD2 + DateRegD
        #UserAgent for the request
        UserAgent = "Samsung Galaxy S8 - 7.0.0"
        #Username for datas_p data later
        UName = "JamesRicky"
        #Makes the PasswordStart into 4 digits: 0 becomes 0000, 40 becomes 0040.
        Password = str(PasswordStart).zfill(4)
        #These two hashes my string and makes a variable with the hash,
        # which is later used in the headers part of request
        HASH = hashlib.md5()
        HASH.update(time.strftime("%Y-%m-%dT%H:%M:%S.00+00:00")+UName+Password)

        #Now the fun part, defines url for the post request
        url = "http://example.com/user"
        #JSON data for the POST request
        datas_p = {'Username': UName, 'Password': Password, 'RegDate': RegD}
        #URLencodes JSON - Not sure if this is needed or not
        datas = urlencode(datas_p)

        #The headers for the POST request
        headers = ({
                'User-Agent': [UserAgent],
                'Date': [Timing],
                'Secret-Key': [HASH.hexdigest()],
                'Content-type': ['application/json'],
                'Accept-encoding': ['gzip'],
                'Accept': ['*/*'],

        })

        #Sends the treq.post request using the information from above (url, data, headers)
        d = treq.post(url, data=datas, headers=headers)
        #Adds call back in done def above.
        d.addCallback(done)
        #Adds up on the PasswordStart, so it tries another password for the
        next request in the loop.
        PasswordStart+=1

reactor.run()

When I run it, it runs through the loop, but makes 0 requests (no matter which host I have put). Which means there is something wrong with the treq.post request.

What am I doing wrong here?

EDIT: Here is the documentation for treq: https://treq.readthedocs.io/en/latest/ It is supposed to be a lot like requests and based on twisted.

EDIT 2: Here is an example code of how treq is supposed to make requests:

http://nullege.com/codes/show/src%40b%40t%40btcx-HEAD%40btcx%40btce.py/51/treq.post/python

I have had no luck in finding out what I did wrong reading the above code.

ivan_pozdeev
  • 33,874
  • 19
  • 107
  • 152
JamesRicky
  • 201
  • 1
  • 3
  • 17
  • `Unhandled error in Deferred:` is not the error message, so include something more representative. – ivan_pozdeev Apr 19 '17 at 00:20
  • The code above works just like my original code. I have removed some personal information I do not want leaked online, but you get same problem when running the above code as the one I have. I will edit the code to make it smaller and add some comments. – JamesRicky Apr 19 '17 at 00:25
  • On second look, the code seems to have few irrelevant bits (which is quite pleasant, for a change). But it's still not of much use as long as we can't reproduce the problem. So, pay extra attention to providing useful error info for us to be able to say anything. – ivan_pozdeev Apr 19 '17 at 00:29
  • @ivan_pozdeev, it does not technically give me an error (unless you count the Unhandled error at the end of the loop). The problem is that I am checking for traffic which gets sent out from the script using Charles Proxy (Traffic sniffer/fiddler), but the script does not send any requests. Which means that the treq.post request part is not working the right way. I have configured something wrong there. It counts up the Password and goes through the loop, but it does not send the request to the server. – JamesRicky Apr 19 '17 at 00:37
  • Sheesh... [include all the relevant info in the question so that someone not already in the know can see what's happening](/help/how-to-ask) - there are no psychics here (that I know of :) ). – ivan_pozdeev Apr 19 '17 at 00:40
  • @ivan_pozdeev, What is wrong with the question I am asking? I am wondering why the code above does not make the POST requests which it is supposed to do. You can run the code in Python and you would face the same problem (after you install the necessary modules). It won't make any request to the host url provided in the code. How can I explain this in a better way? – JamesRicky Apr 19 '17 at 00:45
  • You mean, this doesn't depend on the host? I thought you're having a very specific problem with a very specific site or device. – ivan_pozdeev Apr 19 '17 at 00:47
  • 1
    @ivan_pozdeev, no, it does not depend on the host. The script just doesn't want to make the requests. No matter what host you put. That's the problem. – JamesRicky Apr 19 '17 at 00:49
  • Why are you using an array to check if you have counted from 1 to 10000? – smac89 Apr 19 '17 at 01:08
  • @smac89, the array is there so I don't make double requests. The code is transported from requests to treq, in requests I had to have it to not make multiple requests which are exactly the same. I am not sure if I need it for treq. – JamesRicky Apr 19 '17 at 01:12
  • Change `datas` to `datas = json.dumps(datas_p)` – smac89 Apr 19 '17 at 01:21
  • @smac89, same problem, not requests sent. – JamesRicky Apr 19 '17 at 01:24
  • Here is a link for an example using treq: http://nullege.com/codes/show/src%40b%40t%40btcx-HEAD%40btcx%40btce.py/51/treq.post/python If this helps, I checked it out and could not figure out what I did wrong. – JamesRicky Apr 19 '17 at 01:26
  • Well one thing I can say which looks fishy is the fact that the `reactor.run` is the last and final thing to run within the application. What is the purpose of that line when everything else has finished at that point? Try structuring your application to look like this [simple application](https://treq.readthedocs.io/en/latest/_downloads/basic_post.py) – smac89 Apr 19 '17 at 01:30
  • @smac89, I removed it, did nothing (did not fix the problem nor did it break anything else). I just read somewhere that I was supposed to have it to run the treq.post requests (if I recall correctly). – JamesRicky Apr 19 '17 at 01:33
  • Well that's your first clue that it was either not needed (doubt it), or you were using it wrong (most likely). See the last part of my previous comment on how to possibly remedy this – smac89 Apr 19 '17 at 01:34
  • @smac89, The code you sent, I do not have the module "_utils", so it gives me an error. That's why I did not base my application on it. Every time I run that script, it tells me: "from _utils import print_response ImportError: No module named _utils" – JamesRicky Apr 19 '17 at 01:35
  • Remove `from _utils import print_response` and replace `d.addCallback(print_response)` with `d.addCallback(done)`, just as you had in your previous code – smac89 Apr 19 '17 at 01:37
  • As per [PEP8](https://www.python.org/dev/peps/pep-0008), CamelCase is used for type names. For variables, lowercase_with_underscores is recommended. – ivan_pozdeev Apr 19 '17 at 12:50
  • @ivan_pozdeev, Thanks for the link! Can you take a look here and see what I am doing wrong? https://pastebin.com/bvEn5WSb – JamesRicky Apr 19 '17 at 13:35
  • This is the output from the logging I get: https://pastebin.com/BJBeTPL5 – JamesRicky Apr 19 '17 at 13:41
  • The code looks good (except the `executed` list which is completely unnecessary, as others pointed out). Assuming you have Windows, too, I think `msvcrt` is running out of descriptors once you make more than 252 sockets at once (in Win32, sockets don't consume descriptors but Twisted may be doing something that does). – ivan_pozdeev Apr 20 '17 at 20:21
  • Exactly. I found that when printing "Malformed file descriptor...", Twisted is swallowing a "Too many file descriptors in select()" error. This is a bug in Twisted, but we still have to limit the number of simultaneous connections made to avoid this error. – ivan_pozdeev Apr 20 '17 at 20:50
  • Okay, I've got it. But it's completely out of scope of this question - the problem outlined in this one has been solved, and SO is one concern per question to stay useful for future readers. Could you ask another one, with the problem description taken from your last two comments? I'll answer there if you give me a link. – ivan_pozdeev Apr 22 '17 at 02:45

2 Answers2

2

First of all, twisted is a server app, so logging is a must to know what's happening:

twisted.python.log.startLogging(sys.stdout)

Now, Password is not defined in the context that done() is executing in (or maybe it is but has an irrelevant value once the Deferred is executing). You need to pass the extra data to the callback explicitly as per How to pass extra arguments to callback register functions with twisted python api? :

def done(response,Password):
    if response.code == 200:
        sys.stdout.write( Password + "FOUND" )

<...>
d.addCallback(done,Password)

(Note that for variables, PEP8 recommends lowercase_with_underscores naming convention, CamelCase is used for type names. I only deviated from it to conform to your existing code.)

Finally, there's no reactor.stop(), so your code will run indefinitely. One way to stop is to use twisted.internet.task.react instead of reactor and defer.gatherResults as the main task that will call all the others, the completion of which will signal the reactor to stop, as per stop a twisted reactor after a gatherResults has finished:

def main():
    #checkPassword() returns a Deferred for trying the corresponding password
    calls = [checkPassword(password) for password in ('%04d'%i for i in range(10000))]
    d=defer.gatherResults(calls)
    return d

twisted.internet.task.react(main,[])
Community
  • 1
  • 1
ivan_pozdeev
  • 33,874
  • 19
  • 107
  • 152
0

The problem is that you were not using the reactor properly. Note I don't actually know what this reactor does, but I believe it was essential for the application to function properly.

Judging from an example found online, you are not to import the reactor directly, but rather have twisted create and pass it to you via a method callback.

As an example (taken online and modified):

import json

from twisted.internet import defer, task
import treq

def response_recieved(response, password):
    response.json().addCallback(lambda payload: print(payload, password))

def main(reactor, *args):
    d = treq.post('http://httpbin.org/post',
                  json.dumps({"msg": "Hello!"}).encode('ascii'),
                  headers={b'Content-Type': [b'application/json']})
    d.addCallback(response_recieved, 42)
    return d

task.react(main, [])

The output I get after running this is:

{'url': 'http://httpbin.org/post', 'json': {'msg': 'Hello!'}, 'files': {}, 'headers': {'Connection': 'close', 'Content-Type': 'application/json', 'Content-Length': '17', 'Accept-Encoding': 'gzip', 'Host': 'httpbin.org'}, 'origin': '127.0.0.1', 'args': {}, 'form': {}, 'data': '{"msg": "Hello!"}'} 42

NOTE

With python 2, to run the above example, you also need to have the following import statement at the top of the file:

from __future__ import print_function
smac89
  • 39,374
  • 15
  • 132
  • 179
  • I did this exactly like yours: https://pastebin.com/nic4U2mQ But I get: "There is an invalid syntax in your program" and print is marked as red. By print I mean the print in: response.json().addCallback(lambda payload: print(payload)) – JamesRicky Apr 19 '17 at 02:37
  • @JamesRicky, this is a syntax error so I can only suggest you check your indentation and spaces. – smac89 Apr 19 '17 at 02:42
  • I copied the code you posted. Are you sure it's the correct code? Even when you run it on https://pythoniter.appspot.com/ it still gives syntax error on print. – JamesRicky Apr 19 '17 at 02:47
  • @JamesRicky, I see what's happening. Something about that line does not sit well with python 2, but it works with python 3. Since you are using python 2, do this at the top of the file `from __future__ import print_function` – smac89 Apr 19 '17 at 02:48
  • it works flawlessly. Thank you. How can I make it send 10000 requests with different pin each time (just like my previous loop)? Also how do I print the "Password" with when the script runs print(payload)? Thank you so much, I have been struggling with this for a few days. – JamesRicky Apr 19 '17 at 02:58
  • @JamesRicky, you should check out the other answer posted. He has some nice tips and the last snippet of code in that answer actually answers your question – smac89 Apr 19 '17 at 03:00
  • I did indeed check it out, but I did not quite get how to setup the code. I started developing in Python 3 days ago, so all of this is a bit new. I left the author a question, but I do not think *he is online. Therefor I asked you. Again, thank you for everything. – JamesRicky Apr 19 '17 at 03:10
  • @JamesRicky, firstly, bravo for sticking out your neck so far in your first adventure with python, you will be rewarded handsomely. Second, I updated my answer with a way to achieve what you want. *Note how the callback now has an extra parameter, also take note of the output*. You can use a similar method to pass the password to the callback – smac89 Apr 19 '17 at 03:26
  • @JamesRicky, in short, here is the full code https://pastebin.com/sTym1NNS. Note might contain some syntax errors as I cannot run it – smac89 Apr 19 '17 at 03:41
  • thanks again. I will give your code a try. This is what I came up: https://pastebin.com/c2hP8Ukv but it doesn't work, not sure why. I will try out your code and post back. – JamesRicky Apr 19 '17 at 03:45
  • I tried it, but it did not work. Here is the output: https://pastebin.com/54x9xjc1 "The Starting factory" and "Stopping factory" part of the output repeated itself 10 thousand times each. I just copied the output in middle of 20 thousand lines. It did neither print out any Passwords along the way. – JamesRicky Apr 19 '17 at 03:54
  • I edited a few things from your code and got this code: https://pastebin.com/bNYtE8na Now new output is: https://pastebin.com/mffPB8Aq Any ideas? – JamesRicky Apr 19 '17 at 04:09
  • @JamesRicky are you making sure to remove example.com and also you seem to be checking for error code 500. Are these all in order? – smac89 Apr 19 '17 at 04:13