Lucky @ Flagyard
Lucky - Flagyard
Difficulty: Easy
Overview: Lucky chains a stack-reuse bug to force a local variable to attacker-controlled values, allowing bypass of safety checks. That bypass triggers an out-of-bounds write which lets you corrupt critical memory. A separate libc leak reveals a libc address so you can compute the base and turn the OOB write into full code execution.
Basic File Checks
First all we do some basic file checks to see the security protections enabled on the binary.
1
2
3
4
5
6
7
8
9
mcsam@0x32:~/Desktop/ctf/flagyard/pwn/lucky$ checksec --file lucky
[*] '/home/mcsam/Desktop/ctf/flagyard/pwn/lucky/lucky'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
SHSTK: Enabled
IBT: Enabled
The binary is 64 bit little endian and the build lacks stack canaries, which lets us overwrite the saved return address on the stack. Also we can see that PIE is enabled.
Decompiling and identifying vulnerabilities
The binary is stripped, meaning it contains no symbol information to explain functions or variables. As a result we must reverse engineer names and annotate the decompiled output by hand so the program logic is easy to follow.
1
2
mcsam@0x32:~/Desktop/ctf/flagyard/pwn/lucky$ file lucky
lucky: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=1ef13a48326a28ecbf0cc6fcaa356cedec9d00d5, for GNU/Linux 3.2.0, stripped
Let’s start off by running the binary to analyse it’s behaviour.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
mcsam@0x32:~/Desktop/ctf/flagyard/pwn/lucky$ ./lucky
Welcome to the 100 percent accurate lucky number generator. You will definitely win the lottery with this number generator.
1. Enter your name and birthday
2. Generate numbers
> 1
Enter your name: mcsam
Enter your birth year: 9
Enter your birth month: 9
Enter your birth day: 9
Hello mcsam
, your ID is 11464902665060
Welcome to the 100 percent accurate lucky number generator. You will definitely win the lottery with this number generator.
Welcome to the 100 percent accurate lucky number generator. You will definitely win the lottery with this number generator.
1. Enter your name and birthday
2. Generate numbers
> 2
Oh it's your first time here? I'll give you more lucky numbers than usual!
NUM 8
Your lucky numbers are:
60
56
5
14
54
38
62
88
How many numbers do you want to change?
3
Enter new number: 2
Enter new number: 3
Enter new number: 4
The program is an interactive lucky number generator with a simple menu. Option one asks for name and birthday and prints a generated ID. Option two produces a set of lucky numbers, prints an extra message the first time it is used, and then lets you overwrite a chosen number of generated values.
Now that we’ve observed the program’s behavior, we can start static analysis and decompilation in IDA to map out its logic and find the bugs. Because the binary is stripped, I renamed functions and variables in my decompilation to make the logic easier to follow. You will not see the same names if you load the binary into IDA.
In the decompilation of the main function, the setup()
function is called firstly. It then enters a menu loop driven by show_menu()
. If the user chooses 1
, gen_user_id()
is called; if they choose 2
, gen_lucky_numbers()
is called. Any other input causes th program to exit.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
int user_menu_choice; // [rsp+Ch] [rbp-4h]
setup();
while ( 1 )
{
while ( 1 )
{
user_menu_choice = show_menu();
if ( user_menu_choice != 1 )
break;
gen_user_id(a1, a2);
}
if ( user_menu_choice != 2 )
exit(1);
gen_lucky_numbers(a1, a2);
}
}
Let’s see what the show_menu()
function does.
1
2
3
4
5
6
7
8
9
10
11
12
13
__int64 show_menu()
{
unsigned int v1; // [rsp+Ch] [rbp-4h] BYREF
printf(
"Welcome to the 100 percent accurate lucky number generator. You will definitely win the lottery with this number gen"
"erator.\n"
"1. Enter your name and birthday\n"
"2. Generate numbers\n"
"> ");
__isoc99_scanf("%d", &v1);
return v1;
}
The show_menu()
function displays the program’s main menu and reads the user’s choice using scanf("%d", &v1)
. It then returns that integer to the caller. This return value is used in main()
to decide which feature to execute, either generating a user ID (gen_user_id
) or producing the lucky numbers (gen_lucky_numbers
).