Coinslot (CSAW '16)

We qualified for the CSAW’16 finals at IIT Kanpur! /o/.
Here is a write-up for Coinslot automation challenge.

from pwn import *
import math

# All the denominations of notes/coins
denoms = ["10000", "5000", "1000", "500", "100", "50", "20", "10",
"5", "1", "0.5", "0.25", "0.1", "0.05", "0.01"]
# Integral denominations for ease in calculation
integral_denoms = ["10000", "5000", "1000", "500", "100", "50", "20",
"10","5", "1"]
# Float denoms
float_denoms = ["0.5", "0.25", "0.1", "0.05", "0.01"]

# Function to return the number of notes/coins required for each denomination
# Takes in an arbitrary value and returns a hash containing the key as the
# denomination and the number as the corresponding value.
# Eg. calculate_min(0.1) = {"0.1": 1}
def calculate_min(value):
    result_hash = {}

    # Separate the decimal and integral part.
    split_num = str(value).split('.')

    # Get the integral value.
    int_val = int(split_num[0])
    # Get the float value.
    if len(split_num[1]) == 2:
        float_val = int(split_num[1])
    else:
        float_val = int(split_num[1])*10

    # For each integral denomination, calculate the number of coins/notes.
    for i in integral_denoms:
        if value >= int(i):
            result_hash[i] = int_val/int(i)
            int_val = int_val%int(i)

    # For each float denomination, calculate the number of coins.
    for i in float_denoms:
        temp_i = int(float(i)*100)
        if float_val >= temp_i:
            result_hash[i] = float_val/temp_i
            float_val = float_val%temp_i

    return result_hash

# Connecting to remote.
r = remote("misc.chal.csaw.io", 8000)
# Parse the fist line which contains the amount to get the value.
val = float(r.recvline().replace("$", ""))

r.recvuntil("$10,000 bills:")

print "[+] Here we go."

# Count the number of times we solve the challenge.
count = 0
while 1:
    # Calculate min function returns a hash containing the denoms as the key
    # and number of notes/coins as values.
    result_hash = calculate_min(val)

    # For all keys
    for i in denoms:
        # If there exists a corresponding value
      if i in result_hash:
          r.sendline(str(result_hash[i]))
      else:
          r.sendline("0")

      # Get dat flag at the 399th attempt
      if count == 299:
          line = r.recv(128)
          print line
      else:
          line = r.recvuntil(":")

      if "correct" in line:
          # Receive the next amount from the server and set it to val
          val = float(line.split("\n")[1].replace("$", ""))
          print "[+] Solved: {}".format(str(count))
          count += 1

We get the flag which is flag{started-from-the-bottom-now-my-whole-team-fucking-here}. Stay tuned for more! :)