(if your network response time is too slow, try nc 0 9007 inside pwnable kr server)
Running at : nc pwnable.kr 9007
A counterfeit coin is hiding somewhere in the N(Number of coins). If you find the counterfeit coin, you will see the "Correct" message. However, only C chances are given. The counterfeit coin weighs 9 and a normal coin weighs 10.
Because I had to get the right answer for 100 times in 30 seconds, I made a program(python3). I used the socket library.
1024 + 78 bytes of data are sent before the question selection and the question is not exceeding 20 bytes.
My strategy is that dividing the number(N) of coins with 2 and submitting the left coins. 2^10 is 1024. I have not seen the number of coin exceeding 2^C.
The full source code is here
import socket
import time
HOST="pwnable.kr" # in pwnable server(/tmp), change it to 127.0.0.1
PORT=9007
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
data1 = s.recv(1024)
print(data1)
print("----------------")
print(len(data1))
print("----------------")
data2 = s.recv(78)
print(data2)
print("----------------")
print(len(data2))
print("----------------")
isNewGame = 1
while True:
# This is for 100 of the correct
#[START] This prepares the data before the new game.
#sec1S = time.time()
if isNewGame == 1:
rcv = s.recv(100)
print("[Provided]", rcv)
tList = []
nList = []
tList.extend(str(rcv).split(" ")[:])
nList.append(int(tList[0].split("=")[:][1]))
nList.append(int(tList[1].split("=")[:][1][:-3]))
#print("T : ", tList)
#print("N : ", nList)
n = nList[0]
c = nList[1]
leN1 = 0
leN2 = n//2
riN1 = n//2+1
riN2 = n
leWgt = 10*(leN2-leN1+1)
riWgt = 10*(riN2-riN1+1)
#p.s.
#31 : 15,31
#30 : 15,30
isNewGame = 0
#[END] This prepares the data before the new game.
# p.s. It divides the data into halves to see where the fake coin is.
# |-------------------------|----|-----------------------|
# 0 15 16 31
# leN1 leN2 riN1 riN2
# leWgt = 160 (0~15)
# riWgt = 159 (16~31) // If the fake coin is in right data
#[START] This prepares strings to send.
leStr = ""
riStr = ""
for i in range(leN1, leN2+1):
leStr = leStr + str(i) + " "
if i == leN2: leStr = leStr + "\n"
for i in range(riN1, riN2+1):
riStr = riStr + str(i) + " "
if i == riN2: riStr = riStr + "\n"
#print("\n-----------------------------------------------------------")
#print("[I SENT] " + leStr)
leStr = leStr.encode()
riStr = riStr.encode()
#[END] This prepares strings to send.
#[START] This sends left string and receives the result.
s.send(leStr)
#sec1E = time.time()
#print("[SEC1] ", sec1E-sec1S)
#sec2S = time.time()
rstWgt = s.recv(100)
#sec2E = time.time()
#print("[SEC2] ", sec2E-sec2S)
rstWgt = rstWgt.decode()
if rstWgt[0] == "C":
print("[MESSAGE] ", rstWgt)
isNewGame = 1
continue;
else:
rstWgt = int(rstWgt)
#print("[I RECIEVED] " + str(rstWgt))
#[END] This sends left string and receives the result.
#[START] This selects left data or right data
if rstWgt != leWgt:
l2 = leN1+(leN2-leN1)//2
r1 = 1+leN1+(leN2-leN1)//2
r2 = leN2
leN2 = l2
riN1 = r1
riN2 = r2
leWgt = 10*(leN2-leN1+1)
riWgt = 10*(riN2-riN1+1)
#("[Go left] (", leN1, leN2, leWgt, "), (", riN1, riN2, riWgt, ")")
#print("-----------------------------------------------------------")
# If the fake coin is in left
else:
l1 = riN1
l2 = riN1+(riN2-riN1)//2
r1 = riN1+1+(riN2-riN1)//2
leN1 = l1
leN2 = l2
riN1 = r1
leWgt = 10*(leN2-leN1+1)
riWgt = 10*(riN2-riN1+1)
#print("[Go right] (", leN1, leN2, leWgt, "), (", riN1, riN2, riWgt, ")")
#print("-----------------------------------------------------------")
# If the fake coin is in right
#[END] This selects left data or right data
When I tested in my pc, the time is exceed because of network environment. So I moved the source to pwnable server.
After I made the source file(/tmp/~), executed it($python3 /tmp/xxx.py). The flag is provided after the 99th "Correct!".