Mit PHP einen simplen Captcha cracken

Solange ein Captcha nicht sehr aufwändig generiert wurde, ist er auch entsprechend leicht zu knacken. Ich habe hier mal ein Beispiel für einen schlechten Captcha:

Ein Beispiel für einen schlechten Captcha

Was ist an diesem Captcha schlecht? Der auszulesende Inhalt ist nicht abwechselnd genug (immer nur Zahlenfolgen), nicht verzerrt, nicht farblich variierend und hebt sich zu gut vom Hintergrund ab. Das alles werden wir nun ausnutzen um den Captcha zu knacken.

Zuerst müssen wir „Zahlendefinitionen“ schreiben. Das heißt wir legen für jede Zahl einige eindeutige Fixpunkte fest, mit denen die Zahl eindeutig identifizierbar ist.

Beispiel an der Zahl „1“:

     OO             
    OOO             
   OOOO             
     OO             
     OO             
     OO             
     OO             
     OO             
     OO             
   OOOOOO           

Die Definition:

function is_one($pix, $x, $y) {
	$c = 0;
	$c += check($pix, $x, $y, 2, -2); // 5 / 5
	$c += check($pix, $x, $y, 3, -2); // 6 / 5
	$c += check($pix, $x, $y, 1, -1); // 4 / 6
	$c += check($pix, $x, $y, 2, -1); // 5 / 6
	$c += check($pix, $x, $y, 3, -1); // 6 / 6
	$c += check($pix, $x, $y, 0, 0); // 3 / 7
	$c += check($pix, $x, $y, 1, 0); // 4 / 7
	$c += check($pix, $x, $y, 2, 0); // 5 / 7
	$c += check($pix, $x, $y, 3, 0); // 6 / 7
	$c += check($pix, $x, $y, 2, 1); // 5 / 8
	$c += check($pix, $x, $y, 3, 1); // 6 / 8
	$c += check($pix, $x, $y, 2, 2); // 5 / 9
	$c += check($pix, $x, $y, 3, 2); // 6 / 9
	$c += check($pix, $x, $y, 2, 3); // 5 / 10
	$c += check($pix, $x, $y, 3, 3); // 6 / 10
	$c += check($pix, $x, $y, 2, 4); // 5 / 11
	$c += check($pix, $x, $y, 3, 4); // 6 / 11
	$c += check($pix, $x, $y, 2, 5); // 5 / 12
	$c += check($pix, $x, $y, 3, 5); // 6 / 12
	$c += check($pix, $x, $y, 2, 6); // 5 / 13
	$c += check($pix, $x, $y, 3, 6); // 6 / 13
	$c += check($pix, $x, $y, 0, 7); // 3 / 14
	$c += check($pix, $x, $y, 1, 7); // 4 / 14
	$c += check($pix, $x, $y, 2, 7); // 5 / 14
	$c += check($pix, $x, $y, 3, 7); // 6 / 14
	$c += check($pix, $x, $y, 4, 7); // 7 / 14
	$c += check($pix, $x, $y, 5, 7); // 8 / 14
	if ($c == 27) {
		return true;
	}
	return false;
}

Dort sind nun alle Fixpunkte relativ zum „ersten“ Fixpunkt gespeichert. Der „erste“ Fixpunkt ist bei der eins der Punkt ganz unten rechts. Nachdem wir solche Definitionen für alle Zahlen von 0-9 erstellt haben geht’s nun an die Wiedererkennung der Zahlen. Dazu muss zuerst der Hintergrund herausgefiltert werden und die Grafik in ein besser (für unser Programm) lesbares Format gebracht werden. Dies mache ich wie folgt:

function read($path) {
	$im = ImageCreateFromPNG($path);
	$pix = array();
	$sy = ImageSy($im);
	$sx = ImageSx($im);

	for ($y = 0;$y<$sy;$y++) {
		for ($x = 0;$x<$sx;$x++) {
			$col = imagecolorat($im, $x, $y);
			$rgb = imagecolorsforindex($im, $col);

			if ($rgb["red"] <= 150) {
				$pix[$x][$y] = "O";
			}
			else {
				$pix[$x][$y] = "W";
			}
		}

	}

	// ...
}

Nun haben wir den Array $pix, der bei [x][y] entweder W (für weiß) oder O (für schwarz) enthält. Jetzt müssen wir nur noch durch den Array durchgehen und nach unseren Fixpunkt-Mustern suchen:

        // ....

        $no = 0;
	$complete_string = "";
	$found_at = array();
	
	for ($x = 0;$x<$sx;$x++) {
		for ($y = 0;$y<$sy;$y++) {
			if ($pix[$x][$y] == "O" && !in_array("$x|$y", $found_at)) {
				$no = 0;
				
				if (is_one($pix, $x, $y)) {
					$no = 1;
				}
				if (is_two($pix, $x, $y)) {
					$no = 2;
				}
				if (is_three($pix, $x, $y)) {
					$no = 3;
				}

				if (is_four($pix, $x, $y)) {
					$no = 4;
				}

				if (is_five($pix, $x, $y)) {
					$no = 5;
				}

				if (is_six($pix, $x, $y)) {
					$no = 6;
				}

				if (is_seven($pix, $x, $y)) {
					$no = 7;
				}

				if (is_eight($pix, $x, $y)) {
					$no = 8;
				}

				if (is_nine($pix, $x, $y)) {
					$no = 9;
				}
				
				if ($no != 0) {
					$found_at[] = "$x|$y";
					$complete_string .= $no;
				}
			}
		}
	}

	//...

Die Variable $complete_string enthält nun den ausgelesenen String. Simple as that 😉

Hier der gesamte Code inklusive der Hilfsfunktion check(). Der Code ist schon etwas älter, also nicht über schlechten Code-Stil wundern – er soll legendlich das Prinzip erklären: http://agrafix.net.pastebin.com/b6exg0SW

Noch ein Screenshot:
Geknackter Captcha

Das war’s schon – viel Vergnügen damit!

 

Visitor-Stats.de Update

Heute habe ich endlich mal wieder ein Update für visitor-stats.de fertiggestellt. Große optische Änderungen sind wohl nicht zu erkennen, dennoch wurde hinter den Kulissen einiges verändert. Die JavaScripts basieren jetzt auf jquery und die AJAX-API gibt json-formatierte Antworten. Außerdem habe ich einen „loadscreen“ eingebaut, der bei gesendeten AJAX-Requests erscheint.

Das Projekt ist unter http://www.visitor-stats.de zu finden.

Für die Realisierung der AJAX-API mit json Antworten habe ich json_encode() benutzt.

 

DSLan v1.4

Liebe Leser,

gerade eben haben wir die DSLan v1.4 veröffentlicht. Die DSLan ermöglicht es einen Local-Area-Netzwerk Server mit maximal 10 Spielern des Spiels Die-Stämme zu erstellen.

Download und weitere Info’s: http://dslan.gfx-dose.de

Liebe Grüße,
Agrafix

 

Zwei einfache Algorithmen: kgV und ggT

Heute präsentiere ich endlich mal wieder einen Beitrag der sich in die Richtung Mathe/Informatik bewegt. Eigentlich nichts weltbewegendes, nur zwei einfache Algorithmen, die einem beispielsweise beim Bruchrechnen das Leben einfacher machen können: Das kleinste gemeinsame Vielfache und der größte gemeinsame Teiler.


Die Ausgabe sollte wie folgt aussehen:

ggT(114, 24) = 6
kgV(45, 35) = 315

Wer den ggT bzw den kgV von mehreren Zahlen braucht, kann sich an folgende Regel halten:

kgV(a, b, c, d) = kgV(kgV(a, b), kgV(c, d))
 

PHP und register_globals

Ich versteh‘ es einfach nicht. Warum gibt es immer noch Webhoster die die php.ini-Setting register_globals aktiviert haben? Ich war gestern abend mindestens eine halbe Stunde auf Bug-Suche, bis ich bemerkt hatte das unser liebes register_globals Variablen definiert hatte – die eigentlich leer bleiben hätte sollen. Ja, man darf mir jetzt unsauberes Coden vorwerfen – ich hätte jeder Variable vor der Verwendung ja einen Initialwert geben können. Allerdings kommt PHP doch eigentlich auch gut ohne aus – und wenn man mal was quick’n’dirty machen will scheitert PHP an seinen eigenen Einstellungen…

register_globals wird endlich mit PHP6 abgeschafft – seit PHP5.3 gillt es als „veraltet“. Und warum gibt’s dann immer noch Webhoster die sowas standardmäßig aktivieren?!

 

Quadratische Gleichung Lösen

Um das wp-syntax plugin zu testen habe ich ein kleines PHP Script zum Lösen von quadratischen Gleichungen veröffentlicht:

 ax² + bx + c = 0
$a = 1;
$b = 3;
$c = 1;

// calc
print "Eq: ".$a."x² + ".$b."x + ".$c." = 0n";

$d = pow($b, 2) - 4*$a*$c;
print "D = $dn";

if ($d