(writeupみちゃいました)
調査
ルールは
「コインがN枚が並べてあります。その中に1枚だけ偽物のコインがあるので、一度に何枚でも載せられる天秤をC回だけ使って何番目のコインが偽物か答えてね!
30秒以内でこれを100回解けばフラグをあげるよ」
というゲームです。
上のルールもそうですが、入力や出力の決まりは接続時に表示されるので読んでください。
解法
流れ
人間がやると死ねるのでプログラムに答えてもらいます。
- コイン全体を2等分します
- 片方のグループのコインを全て天秤に載せ、重さを一度に測ります。重さがコインの枚数*10でなければ、このグループに偽物コインがあります。でなければもう一方のグループに偽物コインが含まれています。
- 偽物コインが含まれているグループを基にして、手順1からやり直します。
- 最後に偽物コインが1枚に絞り込めます。
以上!
エクスプロイトコード
# coding: utf-8
import socket
import sys
import re
import time
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('127.0.0.1', 9007)
sock.connect(server_address)
sock.recv(10024) #接続時のルール説明を読み飛ばす
for i in range(100):
arr = sock.recv(100).strip().split(' ')
count = int(arr[1].split('=')[1])
number = int(arr[0].split('=')[1])
print "c:" + str(count)
print "n:" + str(number)
low = 0
high = number
send_data = " "
#二分探索
for _ in range(count):
mid = (low+high)/2
#2分割したコインの先頭側グループを全て秤に載せる(奇数の場合は先頭グループが常に1枚多くなる)
send_data = " ".join([str(i) for i in range(low, mid+1)])+"n"
sock.sendall(send_data)
time.sleep(0.01) #待たないとダメかも?
data = sock.recv(100)
weight = int(data[:-1])
#ちょうど最後の一枚!
if weight == 9:
pass
#このグループには偽コインは含まれていない場合
elif weight == (mid + 1 - low) * 10:
low = mid + 1
#もう一方のグループが残り1枚なら偽物確定。
if (high - low + 1) == 1:
send_data = str(high) +"n"
#このグループに偽コインが含まれている場合
else:
high = mid
sock.sendall(send_data) #結果送信
time.sleep(0.01)
data = sock.recv(100)
print data
time.sleep(0.01)
data = sock.recv(100)
print data
使い方
普通にやるとサーバの応答が遅いせいでタイムアップになります。
上で接続先にlocalhost(ループバックアドレス127.0.0.1)を指定してることからわかるように、SSHログインしたサーバ内から実行してください。
問題文にも「(if your network response time is too slow, try nc 0 9007 inside pwnable.kr server)」
って書いてありますしね。
具体的には
user1@TTsMacBookPro-2 ~/Desktop -> 10:29 PM 金 9 22$ ssh fd@pwnable.kr -p2222 fd@ubuntu:~$ cd /tmp fd@ubuntu:/tmp$ vim solver11.py ((ここで作成したプログラムをコピペして保存)) fd@ubuntu:/tmp$ python solver11.py
として実行すればよいです

コメント