I had a network security class in my university.
And there is a challenge for finding a secret number.
Here is the code
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
void init() {
setbuf(stdin, NULL);
setbuf(stdout, NULL);
}
int main() {
init();
srand(time(0));
int secret = 0;
puts("Your secret: ");
scanf("%d", &secret);
if(secret == rand()) {
system("/bin/sh");
} else {
puts("failed");
}
}
I actually could not understand my professor's explanation.
Anyone can explain the meaning of this code, and how can i find the secret number?
Technically you shouldn't be able to find the "secret" number - that's the whole point of the exercise: the "secret number" is generated using a strong PRNG seeded with a more-or-less random set of bits coming from the system clock.
Theoretically, if you have complete knowledge about the system - i.e. you both know the specific PRNG implementation used and the exact value used to seed it (the result of the time() call) - you should be able to guess the number simply by seeding another instance of the same PRNG and getting the next random int from it.
In this specific case, as the attacker you have complete control of the execution of the code and you should be able to predict the value returned from time() with very good accuracy (it is only a second resolution), so if you can build a program on the same system, that takes the predicted time value, seeds it to the same srand() implementation and returns the first random int - you can guess the "secret number".
So maybe the point of the exercise is to show that PRNG security trivially depends on knowing to start when no one is looking - otherwise you aren't secure, and possibly to not use time() to seed srand() and instead rely on something actually robust, like /dev/urandom 🤷.
Pseudo random number generators rely on a seed to generate their random numbers: if you use the same seed, you'll get the same sequence of "random" numbers.
See here:
Consider this code:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
srand(0);
printf("random number 1: %d\n", rand());
printf("random number 2: %d\n", rand());
printf("random number 3: %d\n", rand());
printf("random number 4: %d\n", rand());
return 0;
}
Running the program (a.out) multiple times always generates the same numbers:
marco#Marcos-MacBook-Pro-16 Desktop % ./a.out
random number 1: 520932930
random number 2: 28925691
random number 3: 822784415
random number 4: 890459872
marco#Marcos-MacBook-Pro-16 Desktop % ./a.out
random number 1: 520932930
random number 2: 28925691
random number 3: 822784415
random number 4: 890459872
marco#Marcos-MacBook-Pro-16 Desktop % ./a.out
random number 1: 520932930
random number 2: 28925691
random number 3: 822784415
random number 4: 890459872
marco#Marcos-MacBook-Pro-16 Desktop % ./a.out
random number 1: 520932930
random number 2: 28925691
random number 3: 822784415
random number 4: 890459872
Of course the exact numbers will differ on the exact implementation used to generate the numbers. So the sequence of numbers probably will be different on your system. Nevertheless, using the same seed will always result in the same sequence.
Real systems use a combination of "real" (based on physical randomness) random numbers + a pseudo random number generator simply because its way more efficient to generate random numbers that way.
These are usually cryptographically secure pseudorandom number generators because the numbers are used for cryptographic operations (cryptography heavily relies on randomness to work).
The basic idea is as long as the initial seed is "secret" (unknown) you can't work it back and determine the pre-defined sequence of numbers generated.
It is possible (and has been done) to work back the initial seed simply by looking at the numbers generated by a pseudorandom number generator.
Now on how to solve the exercise given by your professor:
The easiest way would be to "freeze" time to have a fixed seed value for the random numbers (as shown in my code example above).
Since there isn't an easy way to do that, you can print the current seed by running another program to just output the first random number generated (since that's the "secret"):
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
srand(time(0));
printf("the secret number is %d\n", rand());
return 0;
}
You can then use that number to "unlock" the program given by your professor.
However you have to do that within a second or less, since time() returns a new value every second.
The more reliable way would be to have your program input the "random" number as soon as you generated it.
Here's an example code of how you could do that:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
// where to put the "random" number on disk
const char *tmp_file = "/tmp/input";
// where the executable of your professor is
const char *executable = "/path/to/your/professors/executable";
void writeRandomNumberToDisk(const char *path, int number) {
char buf[128];
// convert int to string
memset(buf, 0, sizeof(buf));
snprintf(buf, sizeof(buf), "%d\n", number);
FILE *fp = fopen(path, "w+");
fwrite(buf, strlen(buf), 1, fp);
fclose(fp);
}
int main(void) {
srand(time(0));
int secret = rand();
printf("the secret number is %d\n", secret);
writeRandomNumberToDisk(tmp_file, secret);
char buf[512];
memset(buf, 0, sizeof(buf));
snprintf(buf, sizeof(buf), "/bin/sh -c 'cat %s | %s'", tmp_file, executable);
printf("Now executing %s\n", buf);
system(buf);
return 0;
}
Essentially, it writes the first "random" number to disk, then invokes the shell that will feed the "random" number into the program.
You can also bypass the file system entirely by using something like:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
// where the executable of your professor is
const char *executable = "/path/to/your/professors/executable";
int main(void) {
srand(time(0));
int secret = rand();
printf("the secret number is %d\n", secret);
char buf[512];
memset(buf, 0, sizeof(buf));
snprintf(buf, sizeof(buf), "/bin/sh -c 'printf \"%d\\n\" | %s'", secret, executable);
printf("Now executing %s\n", buf);
system(buf);
return 0;
}
Related
I'm trying to reproduce from code from Ivor Horton's Beginning C. I couldn't get the results that the code is expecting so I wrote a smaller program with the specific code that I'm having a problem with.
Please see the first for loop. It should print out two random numbers. If I comment out the second for loop which creates an approximate 5 second delay and the subsequent printf("\rHello) I will see the two random numbers. However if I uncomment the second for loop and the subsequent printf, I will never see the two random numbers, only the output Hello, even though the for loop delays the printf("\rHello") for 5 seconds. I thought I would be able to see the two random numbers for at least 4 seconds or so before they are overwritten by the printf("\rHello"). Can anybody tell me what is going on here?
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <time.h>
#include <ctype.h>
#include <stdlib.h>
int main(void) {
clock_t wait_start = 0;
time_t seed = 0;
unsigned int digits = 2;
unsigned int seconds = 5;
wait_start = clock();
srand((unsigned int) time(&seed));
for (unsigned int i = 1; i <= digits; ++i)
printf("%u ", rand() % 10);
// printf("%Lf\n", ((long double)clock()) / CLOCKS_PER_SEC);
for (; clock() - wait_start < seconds * CLOCKS_PER_SEC; )
;
// printf("%Lf\n", ((long double)clock()) / CLOCKS_PER_SEC);
printf("\rHello");
return 0;
}
The suggested answer is good, if you know what you're looking for. The title of my question is very straight forward literal explanation of what is happening in my code. A beginner may not search for "flush" and "stdout buffer". I didn't search for that and didn't find this solution to my question. It is complementary to the solution to this question to give more understanding to the beginner. The solution to my question gave a straight-forward solution to my question, and then it was followed with more information giving insight as to why I need to use fflush.
The reason the random digits do not appear is you do not flush the stdout stream to the terminal and since you did not output a trailing newline, it is pending in the stream buffer because stdout is usually line buffered by default when attached to a terminal.
Note also that waiting for 5 seconds with a busy loop asking for elapsed CPU time is wasteful. You should instead use a sleep() system call or the equivalent call on the target system (probably _sleep() on Microsoft legacy systems).
Here is a modified version:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#if defined _WIN32 || defined _WIN64
#include <windows.h>
#else
#include <unistd.h>
#endif
int main(void) {
int digits = 2;
int seconds = 5;
srand((unsigned int)time(NULL));
for (int i = 0; i < digits; i++) {
printf("%d ", rand() % 10);
}
fflush(stdout);
#if defined _WIN32 || defined _WIN64
Sleep(seconds * 1000UL);
#else
sleep(seconds);
#endif
printf("\rHello\n");
return 0;
}
I'm trying to generate big random numbers for the public key and private key. I have problem with the initial seed to generate a random 256-bit private key on client-side.
as you may know, we shouldn't use rand or srand function in C because it's easy to break.
how can I generate a random seed to generate a random 256-bit private key?
I use GMP's Linear congruential Algorithm to generate random number in C.
On unix systems, you can read from /dev/random and /dev/urandom files to get some "randomness" byte sequences. Those sequences are based on your system entropy.
See this post for more details about their differences.
#include <unistd.h> // read
#include <fcntl.h> // open
#include <stdio.h> // printf
int main(void)
{
int fd;
unsigned int seed;
fd = open("/dev/urandom", O_RDONLY);
read(fd, &seed, sizeof seed);
printf("%u\n", seed);
// Then you can use srand with your new random seed
return (0);
}
Note: Don't forget to check for errors after open and read, and to close fd after use.
hey guys i really want to know how to use this function to load random number from a .txt file which contains :
0 1 2 3 4 5 6 7 8 9
int main(int argc, char *argv[]) {
FILE* file = NULL;
int score[3] = {0};
file = fopen("test.txt", "r");
if (file != NULL)
{
fscanf(file, "%d %d %d", &score[0], &score[1], &score[2]);
printf("Les meilleurs scores sont : %d, %d et %d", score[0], score[1], score[2]);
fclose(file);
}
return 0;
}
but the problem is i have to make the computer choose a sequence of number randomly
maybe with srand(time(NULL));
i really appreciate your help :D
Getting a random number from a text file containing numbers 0-9 (inclusive) is slower than using srand and rand. Seed srand with the current time and call rand with %10 to get a (mostly) random number.
#include <stdlib.h> // Contains srand
#include <time.h> // Contains time
srand(time(NULL));
rand()%10;
However, if you're trying load random lines from a text file, I'd suggest reading all the lines into an ARRAY of size LINES and then calling ARRAY[rand()%LINES] to access a random index of that array, which would be the same as accessing a random line of the text file.
Unless you HAVE to get the number from the file, you can always do srand, rand etc and take the result modulo 10.
I am new to C programming.
I am trying to work through an example in my textbook.
Problem:
1 : Can't make random number generator pause for one second, without having to
insert printf(); in a place where I shouldn't.
2: Can't make the program pause for 1 second, and then delete random sequence. I have tried using printf(\r), but it just deletes the entire sequence without pausing for 1 second.
Help appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
time_t Start_Of_Seq = (time(NULL));
time_t Now = 0;
Now = clock();
srand((unsigned int)Start_Of_Seq);
for(int i = 1; i <= 5; i++)
{
printf("%d",rand()% 10);
}
printf("\n"); //This shouldn't be here.
for(; clock() - Now < CLOCKS_PER_SEC;);
printf("Testing the to see if there is a pause\n");
}
The printf function outputs everything to a buffer. The buffer is actually printed only after a newline. Try fflush(stdout); to print the buffer contents immediately.
Besides, if you use Linux or another Unix-like system, for pauses there is a system call sleep. Try the man 3 sleep command to see more info.
I have a very rudimentary understanding of C (though I do understand programming concepts in general). I have an assignment to create a buffer overflow that yields something (like access to unauthorized area, free money, etc.) and not just crash the program.
I've tried different sized buffers and can always "crash" the program but I can't get it to launch any code (i.e., /bin/su). Am I approaching this incorrectly?
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <limits.h>
#include <string.h>
#define BUFSIZE 20
int main() {
int month=12;
int day=31;
int year=2016;
int confirm = 0;
double dollars = 5.00;
char *sitenum="97871";
char acctnum[BUFSIZE];
printf("Welcome to the Acme AP-AR System. This is the Accounts Receivable module. \n");
/* Gathering date information */
printf("Please enter the month of transaction as an integer value (2 digits). \n");
printf("For example, July would be 07, December would be 12. Please input the month: ");
for (;;) { /* Start of month input validation loop */
scanf("%d", &month);
if(month>=1 && month<=12) {
printf("Validated. \n");
break;
}
else {
printf("Please enter a value between 1 and 12! \n");
continue;
}
} /* End of month input validation loop */
printf("\nPlease enter the day of transaction as an integer value (2 digits). \n");
printf("For example, the 3rd would be 03, the 25th would be 25. Please input the day: ");
for (;;) { /* Start of day input validation loop */
scanf("%d", &day);
if(day>=1 && day<=31) {
printf("Validated. \n");
break;
}
else {
printf("Please enter a value between 1 and 31! \n");
continue;
}
} /* End of day input validation loop */
/* Gathering sender account number */
printf("\nPlease enter the sender Account Number: ");
scanf("%s", acctnum);
/* Gathering transaction amount */
printf("\nPlease enter the USD amount (including cents) received: $ ");
scanf("%lf", &dollars);
/* Confirming data entry */
printf("\nTransaction information.\n Date: %d-%d-%d \n", month,day,year);
printf("Account: %s-%s \n", sitenum, acctnum);
printf(" Amount: $ %.2lf \n", dollars);
printf("\nProcess transaction information? (Yes=1/No=0) ");
for (;;) { /* Start of confirmation validation loop */
scanf("%d", &confirm);
if(confirm==1) {
printf("Transaction processed. \n");
break;
}
else {
printf("Transaction voided! \n");
break;
}
} /* End of confirmation validation loop */
return (EXIT_SUCCESS);
}
When executing, if you enter 25 characters for the day of month, the program will continue until the end. Only after the last input does it terminate with the stack smashing error. I'm afraid I'm trying to do something that can't be done, but a day (literally, the past 8 hours) of Google searches hasn't yielded an example that I've been able to use.
Can someone push me in a different direction that will get me close to what I'm trying to achieve? Thanks.
You will need an in-depth understanding of the target architecture (x86, x86-64, etc.) to accomplish that. A typical approach would involve carefully constructing the contents of the buffer overflow so that it 1) contains the code you wish to run when the input data is reinterpreted as machine instructions, and 2) overwrites the return address of the stack frame so that it jumps into your code instead of returning to the calling function.
I don't feel comfortable providing code that actually does this, but it's certainly possible to do.
EDIT: By the way, I don't think the assignment was intended to require actually running arbitrary code. I'm guessing based on the code you posted that you're supposed to just overwrite part of the stack so that it looks like you're accessing a different "sitenum". That's definitely possible since the sitenum pointer is going to be stored after acctnum in the stack (at least typically). So if you craft your buffer overrun carefully, you can change the sitenum pointer to point somewhere else. For example, (assuming the sitenum pointer is immediately after acctnum in the stack), you could input 1 extra character into the acctnum, and the null terminating character will overwrite the least significant byte of the sitenum pointer, which most likely will point to a different location then.
In my view, it's a terrible assignment though, because 1) the stack can be arranged differently based on a large number of factors, and 2) most modern development environments will default to adding runtime checks to prevent this kind of stack corruption. For example, in MS Visual C++, you would have to go out of your way to disable the Basic Runtime Checks and Buffer Security Check features to avoid an exception.
Anyway, hope that helps.
Here's a simple example of overwriting the return address on the stack to execute another function(will then promptly crash). Works in Windows VS2015 on x86.
#include "stdafx.h"
void hello()
{
printf("hello world!\n");
}
void run(int a)
{
int * ret = &a;
--ret; // stack grows downward on x86
*ret = (int)hello;
}
int main()
{
int a = 42;
run(a);
printf("this won't print\n");
}
Here's another simple example(VS2015/x86) that saves the return address first, and then after hello() is executed, will put the return address to main() back on the stack. Notice it starts first with a local variable declared in run() and not one passed in as an argument. It comes down to understanding what order the return address, arguments passed, the direction the stack goes, and where the current stack frame starts. You'll probably get notification of failing a run time check in your debugger environment after execution, but you should see this printed to the console:
hello world
main
#include "stdafx.h"
int saveret;
void hello()
{
int a = 43;
printf("hello world!\n");
// put saved return address to main() back on stack
int * ret = &a;
ret += 4;
*ret = saveret;
}
void run()
{
int a = 42;
int * ret = &a;
ret += 4; // stack grows downward on x86
saveret = (int)*ret;
*ret = (int)hello;
}
int main()
{
run();
printf("main\n");
}