From: "ara.t.howard" Date: 2007-07-08T02:17:40+09:00 Subject: Re: flatulent-0.0.3 On Jul 6, 2007, at 12:29 PM, jannis@harderweb.de wrote: > The method used in this captcha is very is to break. In fact I can > solve > the captchas 6 times as fast as it takes to generate them (locally) > in > only 63 lines of code. I do this by generating a regexp for each > possible > character. As the characters don't get damaged by the noise (as they > get > in most image bases captchas) this works all of the time. hmmm - not for me? cfp:~ > ruby a.rb user system total real generate: 0.140000 0.020000 0.170000 ( 0.178928) setup: 0.020000 0.000000 0.020000 ( 0.022138) break: Flatulent.version : 0.0.4 a.rb:63: failed on attempt 1 (RuntimeError) from /opt/local/lib/ruby/1.8/benchmark.rb:293:in `measure' from /opt/local/lib/ruby/1.8/benchmark.rb:377:in `report' from a.rb:63 from /opt/local/lib/ruby/1.8/benchmark.rb:177:in `benchmark' from /opt/local/lib/ruby/1.8/benchmark.rb:207:in `bm' from a.rb:59 cfp:~ > cat a.rb require 'flatulent' require 'benchmark' require 'flatulent' class Deflatulent def initialize font="big" font = Text::Figlet::Font.new(File.join(Flatulent.fontdir,font +".flf")) typesetter = Text::Figlet::Typesetter.new font letters = ('A'..'Z').to_a + ('1'..'9').to_a @lines_array = letters.map{|letter| [letter, gen_figlet_lines_array(typesetter[letter])] } end def deflatulent string if string =~ /
(.*?)< 
\/ pre>/m
       string = $1
       [[/<\/?span>/,''],[" "," "],["
","\n"],["<","<"], [">",">"],[""",'"'],["&","&"]].each do |args| string.gsub!(*args) end end width = string.index("\n") string.tr!("\n","") solution = [] @lines_array.each do |(letter,(length,lines))| re = "(?=" lines.each{|line| re << line << ".{#{width-length}}" } re << ")" string.scan(Regexp.new(re, Regexp::MULTILINE)) do solution[$~.begin(0) % width] = letter end end solution.join end private def gen_figlet_lines_array string lines = string.split("\n") lines.shift while lines.first.strip.empty? lines.pop while lines.last.strip.empty? lines.each{|e|e[0,1]=""} while lines.all?{|e|e[0,1]==' '} lines.each{|e|e[-1,1]=""} while lines.all?{|e|e[-1,1]==' '} [lines[0].length,lines.map{|e|e.split('').map{|q|(q == ' ' ? '.' : Regexp.escape(q))}.join}] end end defl = html = code = nil pairs = Array.new(200) GC.disable i = 0 begin Benchmark.bm(13) do |x| i += 1 x.report("generate:") { flat = Flatulent.new; html = flat.form; code = flat.string } x.report("setup:") { defl = Deflatulent.new } x.report("break:") { raise "failed on attempt #{ i }" unless defl.deflatulent(html) == code } x.report("generate 200:") { 200.times{|index| flat = Flatulent.new; pairs[index] = [flat.form,flat.string] } } x.report("break 200:") { pairs.map{|(html,code)| raise unless defl.deflatulent(html) == code } } end ensure puts "Flatulent.version : #{ Flatulent.version }" end nevertheless, i'm not for one second claiming flatulent is ready for prime time. however, i will state that i think it's quite a bit of work if you use it in the intended way, which is for the html to make an ajax call to get the flatulent source because this make said source available only to javascript. no doubt someone could crack it from there, but the latest version adds vertical and horizontal offset to each char. my version is turning that source into a png. anyhow, the attention is welcome - but next time send a patch! ;-) -a -- we can deny everything, except that we have the possibility of being better. simply reflect on that. h.h. the 14th dalai lama