Bad Seed | Binary Exploitation

Exploiting
User avatar
TheVikingsofDW
Posts: 65
Joined: Thu Feb 01, 2024 5:54 pm

Bad Seed | Binary Exploitation

Postby TheVikingsofDW » Tue Mar 12, 2024 10:59 pm

The Bad Seed serves as the initial trigger or malevolent input capable of instigating an undesired sequence of occurrences within the targeted program. This may encompass the exploitation of programming flaws like buffer overflows, code injection, or other vulnerabilities with the intent of compromising the system.

For illustrative purposes, we shall delve into the basic exploitation of the specified binary file to elucidate the mechanism by which the program employs a seed for pseudo-random number generation and how this insight can be leveraged to anticipate the sequence of generated numbers.

(The detailed exploit is built on Arch Linux and with Ghidra tool)

1. Proceeding with the acquisition of the binary file:

Code: Select all

wget https://github.com/guyinatuxedo/nightmare/raw/master/modules/09-bad_seed/h3_time/time
file time
chmod +x time

2. Let us examine the binary using 'pwn checksec' and proceed to its execution:

Code: Select all

pwn checksec time; ./time

Welcome to the number guessing game!
I'm thinking of a number. Can you guess it?
Guess right and you get a flag!
Enter your number: 9999
Your guess was 9999.
Looking for 15596408.
Sorry. Try again, wrong guess!


Code: Select all

./time

Welcome to the number guessing game!
I'm thinking of a number. Can you guess it?
Guess right and you get a flag!
Enter your number: 1111
Your guess was 1111.
Looking for 68342923.
Sorry. Try again, wrong guess!


3. In this instance, we encounter a 64-bit binary. Upon execution, it requests our input to guess a number. Let us delve into the analysis provided by Ghidra for this binary:

undefined8 main(void)

{
time_t tVar1;
long in_FS_OFFSET;
uint local_18;
uint local_14;
long local_10;

local_10 = *(long *)(in_FS_OFFSET + 0x28);
tVar1 = time((time_t *)0x0);
srand((uint)tVar1);
local_14 = rand();
puts("Welcome to the number guessing game!");
puts("I\'m thinking of a number. Can you guess it?");
puts("Guess right and you get a flag!");
printf("Enter your number: ");
fflush(stdout);
__isoc99_scanf(&DAT_00400bbc,&local_18);
printf("Your guess was %u.\n",(ulong)local_18);
printf("Looking for %u.\n",(ulong)local_14);
fflush(stdout);
if (local_14 == local_18) {
puts("You won. Guess was right! Here\'s your flag:");
giveFlag();
}
else {
puts("Sorry. Try again, wrong guess!");
}
fflush(stdout);
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
}]


Within this context, an intriguing observation unfolds. Initially, the presence of the 'rand' function, intended to provide a random number, and the 'scanf' call utilising the '%u' format string stored in 'local_18', piques interest. Fundamentally, the main function initiates a random number generation, solicits input for a numerical value to be stored in 'local_18', subsequently verifying if the two numbers align. Should a match occur, access to the 'giveFlag' function is granted:

void giveFlag(void)

{
FILE *__stream;
long in_FS_OFFSET;
char local_118 [264];
long local_10;

local_10 = *(long *)(in_FS_OFFSET + 0x28);
memset(local_118,0,0x100);
__stream = fopen("/home/h3/flag.txt","r");
if (__stream == (FILE *)0x0) {
puts("Flag file not found! Contact an H3 admin for assistance.");
}
else {
fgets(local_118,0x100,__stream);
fclose(__stream);
puts(local_118);
}
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return;
}


In this context, the function in question is responsible for reading and displaying the flag file located at /home/h3/flag.txt. Our focus lies in determining the output of the 'rand' function. It's crucial to note that the 'rand' function does not produce truly random outputs; instead, it relies on a 'seed' value to dictate the sequence of numbers generated. By obtaining and replicating this seed value, we can compel 'rand' to generate an identical number sequence.
Upon scrutinising the decompiled code, the following insights emerge:

tVar1 = time((time_t *)0x0);
srand((uint)tVar1);


In this instance, tVar1 acquires the present time to serve as a seed. Consequently, we can devise a C program that utilises the current time as a seed, generates a digit, and redirects the output to the designated target:

Code: Select all

vim exploit.c

Code: Select all

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<stdint.h>
#include<string.h>

int main()
{
    uint32_t rand_num;
    srand(time(0)); //seed with current time
    rand_num = rand();
    uint32_t ans;
    printf("%d\n", rand_num);   
}


4. Final Exploitation: We have successfully achieved the printing of the flag

Code: Select all

gcc exploit.c -o exploit
./exploit
./exploit
./exploit | ./time


Welcome to the number guessing game!
I'm thinking of a number. Can you guess it?
Guess right and you get a flag!
Enter your number: Your guess was 5456739200.
Looking for 5456739200.
You won. Guess was right! Here's your flag:
${h0pel_cat}

Return to “Exploits”