I'm making a program that tries brute forcing a cookie value with python.
I'm working on an environment that is meant for IT-security students, it's like a CTF-as-a-service.
The mission i'm working on is a badly programmed login site that has a weak way of creating a cookie session.
The cookie consist of three values, an integer returned from the server side, the username, and a hash. I've already managed to acquire the username and hash, but i need to brute force the int value.
I have never done anything with cookies or tried to brute force them.
I was thinking i can manually observer the program running and returning the header of the site, until the content-length changes.
This is the code i have at the moment.
from requests import session
import Cookie
def createCook(salt):
#known atrributes for the cookie
salt = int('to_be_brute_forced')
user = str('user')
hash = str('hash_value')
# create the cookies
c = Cookie.SimpleCookie()
#assing cookie name(session) and values (s,u,h)
c['session'] = salt + user + hash
c['session']['domain'] = '127.0.0.1:7777'
c['session']['path'] = "/"
c['session']['expires'] = 1*1*3*60*60
print c
def Main():
print "Feed me Seymour: "
salt = 0
while (salt < 1000):
print 'this is the current cookie: ', createCook(salt)
cc = createCook(salt)
salt = salt + 1
try:
with session() as s:
s.post('http://127.0.0.1:7777/index.php', data=cc)
request = s.get('http://127.0.0.1:7777/index.php')
print request.headers
print request.text
except KeyboardInterrupt:
exit(0)
if __name__ == '__main__':
Main()
So my questions are:
1. Do i need to save the cookie before posting?
2. How do i always add +1 to the salt and recreate the cookie?
3. how do i post it to the site and know that the correct one is found?
While posting the request you have to use cookies as the argument instead of data
s.post(url, cookies=<cookiejar>)
Related
My use case is to generate token for reset password api. Which I am doing with itsdangerous library in python.
https://pythonhosted.org/itsdangerous/.
This token(within reset password link) is forwarder through email to client, the token has expiry time limit which is validated and after that password reset can go through successfully.
Issue here is that once password reset is successful how do I make sure the same token(email link) cannot be used again within the expiry time limit. I can see itsdangerous has URLSafeTimedSerializer which helps evaluate during the validation phase on how old the token is. On the other hand TimedJSONWebSignatureSerializer helps set the expiry time while generating token. Please check the attached piece of code.
Is there a better way to expire token forcefully? If not what would be the best way to save the state of token that it has been used?
import itsdangerous
key = "test"
# signer = itsdangerous.URLSafeTimedSerializer(key)
signer = itsdangerous.TimedJSONWebSignatureSerializer(key, expires_in=5)
email = "email#test.com"
# token = email # to be used with URLSafeTimedSerializer
token = signer.dumps({"email": email})
print token
# print signer.loads(token, max_age=5) # to be used with URLSafeTimedSerializer
print str(signer.loads(token)["email"]) # to be used with TimedJSONWebSignatureSerializer
Once your token is generated and signed it remains valid until it expires. You cannot change that anymore. With that in mind, it also means that you cannot change any of its payload once it was signed, otherwise it will be rendered invalid (due to an invalid signature).
One thing you could do however is to generate an unique key ("some_key") once you generate your token and store the key in your database. In the end, the tokens payload which will be issued to the user could look like this: {"email": email, "reset_key": "some_key"}.
Each time someone would try to reset his password, you would simply verify that key first in order to allow or reject a request.
Once the reset was successfull you would simply remove that key from your database (or flag it as invalid). That would make the following requests containing the same token invalid, even though the token itself is still valid from an expiry perspective.
I hope that helps!
I realise this is a late answer, so added for the benefit of others finding this question.
Another approach might be to use a boolean session variable such as tokenused and set this to True once the token has been de-serialised; thus invalidating the use of the token.
For example, using the session object in Flask:
uid = {}
try:
if not session['tokenused']:
session['tokenused'] = True
s = Serializer(app.config['SECRET_KEY'])
uid = s.loads(token)
except Exception as err:
errors.internal_server_error(err)
return uid
I'd like to start off by saying that I love this tool and the API is written in a very easy to follow way if you are familiar with Zap. The only troubles I've had is that I can't find much documentation on the python API, so I've gone off of the source code and verifying how it works against the app. I've been able to pull of scans and set contexts, but I can't seem to be able to correctly call anything from the authentication module. One of my problems, I believe, is that I'm not entirely sure the exact variables to use or their respective formats when calling the functions. below is some example code that I've scrapped together. Every use of the authentication functions below fail me. Even if someone were to look at this and tell me where to go or look to solve this problem myself, I would be very grateful.
from zapv2 import ZAPv2
context = 'new_attack'
authmethodname = 'formBasedAuthentication'
authmethodconfigparams = "".join('loginUrl=someloginpage' 'loginRequestData=username%3D%7B%25user1%25%7D%26' 'password%3D%7B%25password%25%7D')
target = 'some target but I cant put more than 2 links in this question'
apikey = 'password'
zap = ZAPv2(apikey=apikey)
print zap.context.new_context('new_attack')
print zap.context.include_in_context(context, 'https://192.168.0.1.*')
print zap.context.context(context)
#anything below here gives me 'Missing Params' an error from zap
print zap.authentication.set_logged_in_indicator(context, loggedinindicatorregex='Logged in')
print zap.authentication.set_logged_out_indicator(context, 'Sorry, the username or password you entered is incorrect')
print zap.authentication.set_authentication_method(context, authmethodname, authmethodconfigparams)
A Dev member on the project was able to answer my question so I thought I would put it here as well. Essentially the authentication functions take the contextid and userid as parameters and I was passing the context name and user name. There are a few other mistakes that I interpreted from the source code as well. Hopefully this helps someone else who's starting out with the API as well, since there is not a lot of documentation.
from github page zaproxy; username thc202 - "
from zapv2 import ZAPv2
context = 'new_attack'
authmethodname = 'formBasedAuthentication'
authmethodconfigparams = "".join('loginUrl=https://192.168.0.1/dologin.html' '&loginRequestData=username%3D%7B%25username%25%7D%26' 'password%3D%7B%25password%25%7D')
target = 'https://192.168.0.1'
apikey = 'password'
zap = ZAPv2(proxies={'http': 'http://127.0.0.1:8119', 'https': 'http://127.0.0.1:8119'}, apikey=apikey)
contextid = zap.context.new_context(context)
print contextid
print zap.context.include_in_context(context, 'https://192.168.0.1.*')
print zap.context.context(context)
print zap.authentication.set_authentication_method(contextid, authmethodname, authmethodconfigparams)
# The indicators should be set after setting the authentication method.
print zap.authentication.set_logged_in_indicator(contextid, loggedinindicatorregex='Logged in')
print zap.authentication.set_logged_out_indicator(contextid, 'Sorry, the username or password you entered is incorrect')
userid = zap.users.new_user(contextid, 'User 1')
print userid
print zap.users.set_authentication_credentials(contextid, userid, 'username=MyUserName&password=MySecretPassword')
print zap.users.set_user_enabled(contextid, userid, True)
print zap.spider.scan_as_user(contextid, userid, target)
"
I'm looking for a possibility to get a followers and following list in JSON format via web request (in the same way as on the Instagram web site).
For example, I can login via requests, and get user info:
def get_user_info(self, user_name):
url = "https://www.instagram.com/" + user_name + "/?__a=1"
try:
r = requests.get(url)
except requests.exceptions.ConnectionError:
print 'Seems like dns lookup failed..'
time.sleep(60)
return None
if r.status_code != 200:
print 'User: ' + user_name + ' status code: ' + str(r.status_code)
print r
return None
info = json.loads(r.text)
return info['user']
I tried to see what request chrome send to server, but was unsuccessful.
The question is: how to prepare a similar get or post request to retrieve followers list without the Instagram API?
GraphQL queries with query_hash = "58712303d941c6855d4e888c5f0cd22f" (followings) and "37479f2b8209594dde7facb0d904896a" (followers) return this information. With being logged in, do a GET query to instagram.com/graphql/query with parameters query_hash and variables, where variables is a JSON-formatted set of variables id (user id, as in the return dictionary of your get_user_info() function), first (a page length, it seems the current maximum is 50) and in subsequent requests after set to the end_cursor in the previous response dictionary.
Alternatively, the Instaloader library provides a convenient way to login and then programmatically access a profile's followers and followings list.
import instaloader
# Get instance
L = instaloader.Instaloader()
# Login or load session
L.login(USER, PASSWORD) # (login)
L.interactive_login(USER) # (ask password on terminal)
L.load_session_from_file(USER) # (load session created w/
# `instaloader -l USERNAME`)
# Obtain profile metadata
profile = instaloader.Profile.from_username(L.context, PROFILE)
# Print list of followees
for followee in profile.get_followees():
print(followee.username)
# (likewise with profile.get_followers())
Besides username, the attributes full_name, userid, followed_by_viewer and many more are defined in the Profile instance that is returned for each followee.
Easy(just replace _a with __a)
'https://www.instagram.com/'+user_name+'/followers/?_a=1'
'https://www.instagram.com/'+user_name+'/following/?_a=1'
for some reason I'm unable to retrieve a secure cookie I've set with tornado. Using firebug I can see the cookie and it's expiration date, but when I try to print or retrieve it, it keeps coming up as None. Is there some way I'm invalidating it that I can't see. This is the code I'm using:
class loginHandler(tornado.web.RequestHandler):
def post(self):
# first type of request made to this page is a post
userEmail = self.get_argument("username")
password = self.get_argument("password")
deviceType = self.get_argument("deviceType")
# get some info from the client header
userIp = self.request.headers['X-Real-Ip']
userAgentInfo = self.request.headers['User-Agent']
result = pumpkinsdb.loginUser(userEmail, password, deviceType, userIp, userAgentInfo)
if result == None:
self.redirect("/")
else:
fullname = pumpkinsdb.pumpkinsdb_user['fullName']
this_page_title = fullname if fullname else pumpkinsdb.pumpkinsdb_user['userEmail']
# successful login set up user's cookies
# self.set_secure_cookie("memberId", str(user['memberId']), expires_days=0.1, secure=True, httponly=True)
self.set_secure_cookie("memberId", str(pumpkinsdb.pumpkinsdb_user['memberId']))
self.write(str(self.get_secure_cookie("memberId")))
time_now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print "{} [{}::get] pid[{}] login requested for user: [{}] from [{}] using [{}]".format(
time_now, self.__class__.__name__, os.getpid(), pumpkinsdb.pumpkinsdb_user['emailAddress'],
pumpkinsdb.pumpkinsdb_user['userIp'], pumpkinsdb.pumpkinsdb_user['userAgentInfo'])
self.render('calendar.html', title = this_page_title)
def get(self):
validSession = self.get_secure_cookie("memberId")
if validSession:
this_page_title = pumpkinsdb.pumpkinsdb_user['fullName']
self.render('calendar.html', title = this_page_title)
else:
print self.get_secure_cookie("memberId")
self.write(str(validSession))
Is your cookie secret changing somehow when you restart the server? If the cookie secret changes, all existing cookies are invalidated. Note that even though the cookie secret should be randomly generated, this doesn't mean you should have something like cookie_secret=os.urandom(16) in your code, because that will generate a new secret every time. Instead, you need to call os.urandom once and save its output somewhere (keep it safe and private, like your TLS keys).
so basically the problem was I had four tornado processes running behind nginx and for each tornado process I generated a unique random string with:
cookie_secret = base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes)
obviously that was my problem because each tornado process had a different secret so when i tried to read it tornado thought it was invalid.
The key is to generate a unique random string but then store it somewhere secure such as in your options:
define(cookie_secret, "934893012jer9834jkkx;#$592920231####")
or whatever string you deem fit.
Thank you to everyone that responded. sorry about that.
I have a site im working on, i want to store a value in a cookie
this is an number, when the user comes to the website, i want to know what the number was on their last visit, so I'm thinking of having a persistant cookie that stores the current value, when the user comes to the site, if there is no session cookie, then the session cookie grabs a copy of the persistant cookie.
This way the session cookie always has the value from the last visit.
how ever it seems that my persistant cookie isnt being persisted even though i've set the expiry date 1 year from now
here is my python code:
persistentCookieKey = category + '_highest_id'
sessionCookieKey = 'session_' + persistentCookieKey + '_highest_id'
persistentCookieValue = request.get_cookie(persistentCookieKey)
if persistentCookieValue == None:
persistentCookieValue = 0 # each time i restart my browser it comes through here!
sessionCookieValue = request.get_cookie(sessionCookieKey)
print 'persistentCookieValue:', persistentCookieValue
print 'sessionCookieValue:', sessionCookieValue
if sessionCookieValue == None:
print 'session cookie not set, setting to:', persistentCookieValue
sessionCookieValue = persistentCookieValue
response.set_cookie(sessionCookieKey, str(persistentCookieValue))
print 'setting persistent cookie to value:', highestId
expireDate = date.today() + timedelta(days=365)
response.set_cookie(persistentCookieKey, str(highestId), expires=expireDate)
highestIdLastVisit = int(sessionCookieValue)
Bottle uses http://docs.python.org/library/cookie.html to implement cookie support. This implementation requires the expires parameter to be a string in the Wdy, DD-Mon-YY HH:MM:SS GMT format. Passing datetime or date objects fails silently.
I'll fix that in future versions of Bottle (hi, I'm the author) but for now I suggest using max_age instead.
Edit: Oh, and I just noticed it is also documented incorrectly. Sorry for that.
Edit2: Fixed (in master)