amida (misc 400)
黒丸を高さ470の所になるまで回転させ、位置を補正して、あみだくじをパースした。
本番中はフラグ2まで、終了後同じプログラムでフラグ3を、数行改変することでフラグ4を得ることが出来た。
1 require_relative 'ctf'
2 require 'RMagick'
3 require 'base64'
4 include Magick
5
6 def common_stage(s, base64, n, w)
7 File.binwrite('/tmp/tmp.png', Base64.decode64(base64))
8 img = ImageList.new('/tmp/tmp.png')
9 mp = []
10 (150...450).step(2).each.with_index do |y,i|
11 mp <<= []
12 (n - 1).times do |x|
13 if img.pixel_color((x+1) * w + w / 2, y).red == 0
14 mp[-1] << [x+1,x+2]
15 end
16 end
17 end
18 mp.delete_if {|a| a == [] }
19 target = [*0...n].find{|i| img.pixel_color( ( i + 1 ) * w, 470).red == 0 }
20 current = target + 1
21 mp.reverse.each do |arr|
22 arr.each do |x,y|
23 if x == current
24 current = y
25 elsif y == current
26 current = x
27 end
28 end
29 end
30 s.puts current
31 s.puts
32 end
33
34 def common_stage2(s, base64, n)
35 File.binwrite('/tmp/tmp.png', Base64.decode64(base64))
36 img = ImageList.new('/tmp/tmp.png')
37 mp = []
38 (150...450).each.with_index do |y,i|
39 mp <<= []
40 (n - 1).times do |x|
41 if img.pixel_color((x+1) * 600 / (n + 1) + 1, y).red <= 3*257
42 next if mp.size >= 2 && mp[-2].include?([x+1,x+2])
43 mp[-1] << [x+1,x+2]
44 end
45 end
46 end
47 mp.delete_if {|a| a == [] }
48 target = [*0...n].find{|i| img.pixel_color( 600 * ( i + 1 ) / (n + 1), 470).red == 0 }
49 p mp
50 current = target + 1
51 mp.reverse.each do |arr|
52 p current
53 arr.each do |x,y|
54 if x == current
55 current = y
56 elsif y == current
57 current = x
58 end
59 end
60 end
61 s.puts current
62 s.puts
63 end
64
65 require 'matrix'
66 def common_stage3(s, filename, n)
67 def rotate(x,y,angle)
68 y = 600 - y
69 angle = -angle
70 x,y = x - 300, y - 300
71 nx = x * Math::cos(angle) - y * Math::sin(angle)
72 ny = x * Math::sin(angle) + y * Math::cos(angle)
73 return nx + 300, 600 - (ny + 300)
74 end
75 def dot(x1,y1,x2,y2)
76 x1.to_f*x2.to_f+y1.to_f*y2.to_f
77 end
78 def norm(x,y)
79 x * x.to_f + y * y.to_f
80 end
81 def projection(l, p)
82 p l
83 t = dot(p[0]-l[0][0],p[1]-l[0][1],l[1][0] - l[0][0], l[1][1] - l[0][1]) / norm(l[0][0] - l[1][0], l[0][1] - l[1][1])
84 [l[0][0] + (l[1][0] - l[0][0]) * t, l[0][1] + (l[1][1] - l[0][1]) * t]
85 end
86 img = ImageList.new(filename)
87 cx,cy=nil,nil
88 img.rows.times do |y|
89 break if cx
90 img.columns.times do |x|
91 next unless img.pixel_color(x,y).red == 0
92 ok = true
93 (-1..1).each do |dx|
94 (-1..1).each do |dy|
95 ok = false if img.pixel_color(x + dx * 5, y + dy * 5).red != 0
96 end
97 end
98 if ok
99 # found
100 cx, cy = x,y
101 break
102 end
103 end
104 end
105 p ["Circle:", cx, cy]
106 r = Math::sqrt((300 - cx) ** 2 + (300 - cy) ** 2)
107 angle = Math::atan2(-cy + 300, cx - 300) + Math::PI / 2
108 angle2=nil
109 if r >= 170
110 angle2 = Math::atan2(Math::sqrt(r*r-170*170),170)
111 else
112 angle2 = 0
113 end
114 p angle / Math::PI * 180
115 p angle / Math::PI * 180
116 p rotate(cx,cy,angle)
117 p 'rotate2'
118 p (angle + angle2) / Math::PI * 180
119 p rotate(cx,cy,angle + angle2)
120 angle += angle2
121 ys = [200, 250]
122 xs = ys.map{|y|
123 img.columns.times.to_a.index do |x|
124 img.pixel_color(*rotate(x,y,-angle)).red <= 127 * 257
125 end
126 }
127 p xs
128 dsum = if !xs[1] || !xs[0]
129 9999999
130 else
131 wt = 600 / (n + 1)
132 (xs[0] - wt).abs + (xs[1] - wt).abs
133 end
134 p 'next try'
135 p (angle) / Math::PI * 180
136 fxs = xs + []
137 angle -= angle2 * 2
138 xs = ys.map{|y|
139 img.columns.times.to_a.index do |x|
140 img.pixel_color(*rotate(x,y,-angle)).red <= 127 * 257
141 end
142 }
143 p xs
144 qsum = if !xs[1] || !xs[0]
145 9999999
146 else
147 wt = 600 / (n + 1)
148 (xs[0] - wt).abs + (xs[1] - wt).abs
149 end
150 p ['first', dsum]
151 p ['first', qsum]
152 if dsum < qsum
153 p 'use first'
154 xs = fxs
155 angle += angle2 * 2
156 else
157 p 'use second'
158 end
159
160 proj = projection([[xs[0], ys[0]], [xs[1], ys[1]]], [300,300])
161 rotate = Math::atan2(proj[1] - 300, proj[0]- 300) + Math::PI# / Math::PI * 180
162 angle-=rotate
163 p angle / Math::PI * 180
164 p rotate(cx,cy,angle)
165 angle = -angle
166
167 mp = []
168 (150...450).each.with_index do |y,i|
169 mp <<= []
170 (n - 1).times do |x|
171 if img.pixel_color(*rotate((x+1) * 600 / (n + 1) + 300 / (n + 1), y,angle)).red <= 127*257
172 next if mp.size >= 2 && (
173 mp[-2].include?([x+1,x+2]) || mp[-3].include?([x+1,x+2]) || mp[-4].include?([x+1,x+2])
174 )
175 mp[-1] << [x+1,x+2]
176 end
177 end
178 end
179 mp.delete_if {|a| a == [] }
180 target = [*0...n].find{|i| img.pixel_color(*rotate( 600 * ( i + 1 ) / (n + 1), 470,angle)).red <= 10*257 }
181 p mp
182 current = target + 1
183 mp.reverse.each do |arr|
184 p current
185 arr.each do |x,y|
186 if x == current
187 current = y
188 elsif y == current
189 current = x
190 end
191 end
192 end
193 s.puts current
194 s.puts
195 end
196
197 def stage1(s, base64)
198 common_stage(s, base64, 5, 100)
199 end
200
201 def stage2(s, base64)
202 common_stage(s, base64, 6, 86)
203 end
204
205 def stage3(s, base64)
206 common_stage(s, base64, 7, 75)
207 end
208
209 def stage4(s, base64)
210 common_stage(s, base64, 8, 66)
211 end
212
213 def stage5(s, base64)
214 common_stage2(s, base64, 4)
215 end
216
217 def stage6(s, base64)
218 common_stage2(s, base64, 5)
219 end
220
221 def stage7(s, base64)
222 common_stage2(s, base64, 6)
223 end
224
225 def stage8(s, base64)
226 common_stage2(s, base64, 7)
227 end
228
229
230 def stage9(s, base64)
231 common_stage2(s, base64, 8)
232 end
233
234 def stage10(s, base64)
235 File.binwrite('/tmp/tmp.png', Base64.decode64(base64))
236 common_stage3(s, '/tmp/tmp.png', 4)
237 end
238
239 def stage11(s, base64)
240 File.binwrite('/tmp/tmp.png', Base64.decode64(base64))
241 common_stage3(s, '/tmp/tmp.png', 5)
242 end
243
244 def stage12(s, base64)
245 File.binwrite('/tmp/tmp.png', Base64.decode64(base64))
246 common_stage3(s, '/tmp/tmp.png', 6)
247 end
248
249 def stage13(s, base64)
250 File.binwrite('/tmp/tmp.png', Base64.decode64(base64))
251 common_stage3(s, '/tmp/tmp.png', 7)
252 end
253
254 def stage14(s, base64)
255 File.binwrite('/tmp/tmp.png', Base64.decode64(base64))
256 common_stage3(s, '/tmp/tmp.png', 8)
257 end
258
259 def stage15(s, base64)
260 File.binwrite('/tmp/tmp.png', Base64.decode64(base64))
261 common_stage3(s, '/tmp/tmp.png', 4)
262 end
263
264 def stage16(s, base64)
265 File.binwrite('/tmp/tmp.png', Base64.decode64(base64))
266 common_stage3(s, '/tmp/tmp.png', 5)
267 end
268
269 def stage17(s, base64)
270 File.binwrite('/tmp/tmp.png', Base64.decode64(base64))
271 common_stage3(s, '/tmp/tmp.png', 6)
272 end
273
274 def stage18(s, base64)
275 File.binwrite('/tmp/tmp.png', Base64.decode64(base64))
276 common_stage3(s, '/tmp/tmp.png', 7)
277 end
278
279 def stage19(s, base64)
280 File.binwrite('/tmp/tmp.png', Base64.decode64(base64))
281 common_stage3(s, '/tmp/tmp.png', 8)
282 end
283 def stage20(s, base64)
284 File.binwrite('/tmp/tmp.png', Base64.decode64(base64))
285 common_stage3(s, '/tmp/tmp.png', 4)
286 end
287
288
289
290
291 def solve(sock, stage, base64)
292 case stage
293 when 1
294 stage1(sock, base64)
295 when 2
296 stage2(sock, base64)
297 when 3
298 stage3(sock, base64)
299 when 4
300 stage4(sock, base64)
301 when 5
302 stage5(sock, base64)
303 when 6
304 stage6(sock, base64)
305 when 7
306 stage7(sock, base64)
307 when 8
308 stage8(sock, base64)
309 when 9
310 stage9(sock, base64)
311 when 10
312 stage10(sock, base64)
313 when 11
314 stage11(sock, base64)
315 when 12
316 stage12(sock, base64)
317 when 13
318 stage13(sock, base64)
319 when 14
320 stage14(sock, base64)
321 when 15
322 stage15(sock, base64)
323 when 16
324 stage16(sock, base64)
325 when 17
326 stage17(sock, base64)
327 when 18
328 stage18(sock, base64)
329 when 19
330 stage19(sock, base64)
331 when 20
332 stage20(sock, base64)
333 end
334 end
335
336 TCPSocket.open('203.178.132.117', '42719') do |s|
337 s.echo = true
338 s.echo_color= false
339 stage = 0
340 # 最初のメッセージ
341 7.times{ s.gets }
342 while $_ = s.gets
343 if /^Stage #(\d+)/ =~ $_
344 stage = $1.to_i
345 elsif /^#(\d+)/ =~ $_
346 p $1
347 puts "Stage #{stage}: #{$1}"
348 base64 = s.gets
349 s.gets # Answer?
350 solve(s,stage, base64)
351 end
352 end
353 end
}