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!

 

at

 

3 Gedanken zu „Mit PHP einen simplen Captcha cracken

    1. Ja, natürlich gibt es auch viel komplexere Captchas bei denen es viel aufwändiger ist einen Crack zu schreiben. Aber bei den meisten kleinen bis mittelgroßen Seiten findet man einen Captcha der etwa in diesem Stil ist 😉

Schreibe einen Kommentar zu agrafix Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert