August 28, 2017

pwnable.kr coin1 solution


Mommy, I wanna play a game!
(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!".