Artikel in der Kategorie Programmieren

Freitag, 23. Oktober 2009

Injektionen – die Querygrippe

von j-zero

Mahlzeit.

Nach dem ich ja schon länger nichts gepostet habe wollte ich mal wieder ein aktuelles mit einem alten Thema verbinden.
Was fällt uns denn im Moment zum Thema “Injektionen” ein? Richtig! Schweinegrippe!

Was viel dem ein oder anderen (vermutlich nur Nerds) früher bei “Injektionen” ein? Wieder richtig! SQL.

Nun ich bin in den letzten zwei Tagen nicht nur auf das erstere sondern auch auf das zweite gestoßen und das nicht auf einer ewig alten, nicht mehr gepflegten Webseite, sondern auf einer die noch irgendwie in der Entwicklungsphase ist aber schon produktiv mit sensiblen Daten arbeitet.
Die SQL-Injections waren nicht das einzige Problem, aber vermutlich das welches am häufigsten auch bei anderen Projekten möglich ist.

Ich möchte an dieser Stelle mal (für alle die, die mal was davon gehört haben, aber nicht wissen um was es sich handelt) erläutern, was bei SQL-Injections das Problem ist.
ACHTUNG: Der nachfolgende Text ist für rein edukative Zwecke gedacht und ich übernehme keinerlei Haftung für dadurch entstandenen Schaden!
Stellt euch vor, ihr habt eine tolle Seite in PHP gebastelt auf der ihr für die Familie die Grönland-Urlaubsbilder zur Verfügung stellen wollt oder die vom Jahr davor im Dschungel von Guatemala. Ihr habt sogar eine kleine Datenbank in der jedes Album eine Nummer hat. Grönland hat die Nummer 2009 und der Dschungel hat 2008 oder 1 und 2. Wie auch immer.
Nun rufen eure Verwandten diese Bilder mittels: “http://www.example.com/meinalbum.php?album=2008″ ab. Schön und gut.

Ihr habt also eine SQL-Abfrage in dem PHP die in etwa so lautet:

1
$result=mysql_query("SELECT * FROM alben WHERE album = " . $_GET['album'] . " ORDER BY id ASC");

Na, wer findet das Problem?

Richtig! Es fehlen die Anführungszeichen im SQL-Query. Nun kommen wieder einige Scriptkiddies und meinen: Die brauchen wir nicht, geht ja auch so!
Damn! Ihr habt mal wieder recht! Für alle die wissen wollen was noch geht, lest einfach weiter.
Viele werden es schon vermuten: SQL-Injections.
Nun wie tun wir das? Erstmal testen, ob’s klappt: Erstmal schauen wir ob wir einen Fehler erzeugen können in dem wir ein ‘ hinter die 2008 hängen. Bekommen wir dann das:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right foo bar...

Sind wir schon mal einen Schritt weiter. Das bedeutet in den meisten Fällen, die Seite ist verwundbar.
Nun wollen wir herausfinden wie viele Spalten denn wohl diese “alben”-Tabelle hat, das kann man einfach per “ORDER BY” machen:

meinalbum.php?album=2008 ORDER BY 1/*
meinalbum.php?album=2008 ORDER BY 2/*
meinalbum.php?album=2008 ORDER BY 3/*
meinalbum.php?album=2008 ORDER BY 4/*
meinalbum.php?album=2008 ORDER BY 5/* <-- hier gibts einen Fehler ("Unknown column 5 in ...")

Da wir nicht nach Spaltennamen sondern deren Index sortieren muss es 4 Spalten geben, wenn bei 5 keine kommt.

Fein, aber wie bringt uns das Weiter? Hmm… UNION!
UNION in SQL ist sowas wie ein “DOWNER JOIN” man kann also zwei SELECT-Ergebnisse untereinander hängen.

Wir benutzen also

meinalbum.php?album=2008 UNION ALL SELECT 1,2,3,4/*

und schon haben wir alle Einträge der Tabelle.
Oder:

meinalbum.php?album=2008 UNION ALL SELECT 1,2,3,4 FROM mysql.user/*

Und schon haben wir im Grunde Zugriff auf die gesamte Datenbank.

Wie schafft man sich als Programmierer Abhilfe?

  • Immer Anführungszeichen vor und nach den Werten im Query verwenden! Vor allem vor Werten die direkt vom User geändert werden können!
  • Werte immer so weit wie möglich auf den Datentyp oder Inhalt testen! (Im Beispiel z.B. mit “is_numeric”)

Falls noch Fragen oder Kritiken oder Anregungen da sind. Bitte Mail oder Kommentar.

Bis neulich.

j-zero



Donnerstag, 11. Juni 2009

HTML-Link-Target dynamisch ändern…

von j-zero

Mahlzeit,
folgendes Problem ereilt einen des öfteren, wenn man z.B. in WordPress Links in dem HTML Editor manuell einfügt:
Das Link-Target (z.B. “_blank”) muss manuell eingetragen werden, damit beim Klicken auf einen Link die Seite in einem Neuen Fenster geöffnert wird. Es ist aber unschön diesen jedes mal manuell zu setzen, gerade wenn man mehr als einen Link hat.
Man könnte nun in der Tat einfach innerhalb des “<head>”-Tags ein

1
<base target="_blank" />

setzen, dieses würde aber Links die schon ein Target haben nicht ändern, was sehr gut ist, wenn man es nicht will. Wenn aber doch muss man sich anders helfen…
Dazu habe ich folgendes kleines Script gebastelt:

1
2
3
4
5
6
7
8
9
10
function setLinkTargets(){
 var l = document.getElementById("contentbox").getElementsByTagName("div");
  for (var i = 0; i < l.length; i++) {
    if(l[i].getAttribute("class") == "post"){
    var j = l[i].getElementsByTagName("a");
    for (var k = 0; k < j.length; k++) {
       if(j[k].getAttribute("class") == null){
          j[k].target = "_blank";
  }}}}
}

Damit wird allen “a”-Tags, die sich in dem div “contentbox” und innerhalb eines divs, welches die Class “post” hat das Target-Attribute “_blank” gegeben.
Unter Umständen müsst ihr noch den Class-Namen ändern oder eben das Target auf das Setzen was ihr möchtet.
Einzubinden ist das Script einfach folgendermaßen:

1
2
3
4
5
6
7
8
9
10
<html>
<head>
   <script type="text/javascript">
   ...
   </script>
</head>
<body onLoad="setLinkTargets()">
   ...
</body>
</html>

Viel Spaß damit.
j-zero
PS: Sicherlich wäre es eleganter die Links mit den richtigen Targets zu versehen, aber es wäre langweilig. ;)

Nachtrag:
Wie ich gerade eben gesehen habe, ist es nicht XHTML 1.0 Strict-Konform Links mit Targets zu versehen. Daher habe ich das Script deaktiviert.



Dienstag, 12. Mai 2009

Ping auf einen TCP-Port

von j-zero

Mahlzeit,

wie von schmidt24 schon angekündigt habe ich das tcpping-Skript ein wenig erweitert, da ich finde, das Timeouts nicht markant genug dargestellt wurden, habe ich diese in rot und erfolgreiche Pings durch ein grünes “ok” markiert.

Zudem ist es nun möglich, anstatt des Ports den Namen aus der /etc/services anzugeben (falls man z.B. mal den Port von IMAPS nicht im Kopf hat).

Beispiel: “tcpping.sh 127.0.0.1 imaps” ist equivalent zu “tcpping.sh l27.0.0.1 993″.
Der Standardport ist auch nun 22, also SSH da dieser ja meist auf Linux/UN*X Maschinen auf ist.
Man kann also einfach “tcpping.sh 127.0.0.1″ nutzen und es wird automatisch auf SSH geprüft.
Die Namens- und Portauflösung sind nur eine nette Spielerei aber für den ein oder anderen Skripter vielleicht ganz nützlich. :)

Hier ist es:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/bin/sh

i=0

if [ $# = 1 ]; then PORT=22
else PORT=$2
fi

if [ $# -eq 0  ]; then
    echo "Usage: $0 <HOST> [PORT]"
    echo "   PORT can be numeric or name from /etc/services"
    echo "   Default port is 22 (ssh)"
    exit 1
fi

if [ $(echo "$1." | grep -E "([0-9]{1,3}\.){4}") ]; then
    HOST=$(host -v $1 | grep -1 -m1  -A1 ";; ANSWER SECTION" | awk '{print $5}' | awk NF | sed 's/\.$//')
    IP=$1
else
    IP=$(host -v $1 | grep -i -m 1 -A1 ";; ANSWER SECTION" | awk '{print $5}' | awk NF | sed 's/\.$//')
    HOST=$1
fi

case $PORT in
    *[!0-9]* )  PORT=$(cat /etc/services | grep -i -m 1 $PORT | awk '{print $2}' | sed "s/\/tcp//g")
esac

PROTO=$(cat /etc/services | grep -i -m 1 $PORT | awk '{print $1}' | sed "s/\/tcp//g")

while (true) do
        TIME=`date +%s%N| cut -c -13`
        SCAN=`nmap -P0 -p$PORT $1`
        if [ $? != 0 ]; then exit 1; fi
        echo $SCAN | grep -q open
        if [ $? != 0 ]; then
                echo "tcp ping from $HOST ($IP) port $PORT ($PROTO): tcp_seq=$i time=$(($((`date +%s%N| cut -c -13`-$TIME))))ms\t[\033[1;31mtimeout\033[0m]"
        else
                echo "tcp ping from $HOST ($IP) port $PORT ($PROTO): tcp_seq=$i time=$(($((`date +%s%N| cut -c -13`-$TIME))))ms\t[\033[1;32mok\033[0m]"
        fi
        sleep 1
        i=$((i+1))
done

viel spaß und erfolg damit.

Known Bugs:

  • Wenn als Host ein Nmap Parameter übergeben wird wie z.B: “–help” ist der Ping “[ok]“, da Nmap die Hilfe ausgibt, “grep -q open” ist in dem Fall Wahr, da auch in der Help ein “open” vorkommt.
  • Die Domainauflösung zur IP funktioniert zurzeit nicht bei einem Alias, da dann als erstes Ergebnis von “host” der CNAME zurückgeliefert wird.

Wenn jemand eine Idee hat, wie das zu lösen ist (bevor ich eine habe oder das ganze Ding in Perl implementiere) wäre ich dankbar.

bis neulich

j-zero



Freitag, 6. März 2009

Perl Twitter

von j-zero

Mahlzeit!

Ich bin nun auch unter die Twitterer gegangen, nach dem ich ja den Blogkram auch schon mit gemacht habe. Nach kurzer Zeit habe ich ein Tool gesucht, mit dem ich aus der Kommandozeile unter Linux einen Tweet absetzen kann, habe aber erstmal nix gefunden. Also habe ich mal geschaut, ob es ein Perl Modul gibt. Und ja(!), es gibt eins, und zwar: “Net::Twitter” – wär hätte das gedacht! Ihr könnt das einfach mittels “perl -MCPAN -e “install Net::Twitter” installieren.

Hier ist mein kleines Script, welches aus der Konsole Tweets sendet, viel Spaß damit.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/usr/bin/perl
use Getopt::Std;
use Term::ReadKey;
use Net::Twitter;
getopt('upt',\%opts);
$usage= <<USAGE;
commandline twitter 0.1b - www.j-zero.de
Usage
: twitter_cmd -u username [-t tweet] [-p password]
USAGE
sub gp{
    print "password: ";
    ReadMode 2;
    chomp($l = ReadLine(0));
    ReadMode 0;
    print "\n";
    return $l;
}
if(!$opts{u}){print $usage;exit 1;}
    else{$u=$opts{u};}

if(!$opts{t}){print "tweet: ";chomp($t=<STDIN>);}
    else{$t=$opts{t};}

if(!$opts{p}){$p=&gp;}
    else{$p=$opts{p};}
$s=Net::Twitter->new({username=>"$u",password=>"$p" });
$s->update({status=>"$t"});
exit 0;

j-zero



Montag, 23. Februar 2009

Cross-Site Scripting

von j-zero

Mahlzeit,

Es ist gar unglaublich wie einfach man bei einigen Seiten im Netz, die sich professionell geben Cross-Site Scripts einfügen kann. Gerade auf Seiten, die es Facebook gleich tun wollen, Foren, oder ähnlichem. Wenn man z.B. in Kontaktformularen oder im Kommentar zum eigenen Profil HTML ausführen kann, bleibt dies ja nunmal nicht aus. Aber welcher Webprogrammierer lässt sowas zu? Die Antwort: Zu viele.

Also bitte liebe Webprogrammierer oder solche die es werden wollen, achtet drauf.

Zu meiner Schande muss ich gestehen, dass ich es auch oft nicht mache ;)

bis neulich

j-zero