How to get the hostname of mac os in C - c

I 'm trying to get the hostname of my school mac os. I can't use gethostname() as it's in section 3 of the man pages of my school macs, instead of section 2. Is there another way of getting the hostname, without using gethostname()? I'm only allowed to use libc functions in man 2 section.

gethostname is just a sysctl, and sysctl is just a syscall.
And syscalls are (per definition) in section 2 of the manual.
So grab your favourite disassembler (or otool -tV if you have none), nm the libraries in /usr/lib/system to find out which ones export _gethostname and _sysctl, and get to work (or look up the source :P).
Below I re-implemented gethostname using sysctl, and sysctl using syscall:
#include <sys/syscall.h> // SYS_sysctl
#include <sys/sysctl.h> // CTL_KERN, KERN_HOSTNAME
#include <unistd.h> // syscall
int sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen)
{
return syscall(SYS_sysctl, name, namelen, oldp, oldlenp, newp, newlen);
}
int gethostname(char *buf, size_t buflen)
{
int name[] = { CTL_KERN, KERN_HOSTNAME };
size_t namelen = 2;
return sysctl(name, namelen, buf, &buflen, NULL, 0);
}
int puts(const char *s)
{
// left as an exercise to the reader ;)
}
int main(void)
{
#define BUFSIZE 256
char buf[BUFSIZE];
size_t buflen = BUFSIZE;
if(gethostname(buf, buflen) == 0)
{
puts(buf);
}
return 0;
}
The implementation of sysctl isn't too complicated; you really just slap SYS_sysctl (from sys/syscall.h) in front of the other arguments and pass them all on to syscall.
To understand the implementation of gethostname, you have to know how sysctl works:
oldp is where the queried value will be stored.
newp is where the new value will be read from. Since we're not setting any new value, this is NULL here.
name is more or less the actual list of arguments to sysctl, and its contents depend on the actual sysctl being queried.
CTL_KERN denotes that we want something from the kernel.
KERN_HOSTNAME denotes that we'd like to retrieve the hostname.
And since KERN_HOSTNAME doesn't take any arguments, that's all there is to it.
Just for demonstration, had you called KERN_PROCARGS, name would require an additional argument, namely the process ID of which the arguments should be retrieved.
In that case, name would look like this:
int name[] = { CTL_KERN, KERN_PROCARGS, pid };
and namelen would have to be set to 3 accordingly.
Now in the above implementation I've made use of puts, which you're obviously not allowed to do, but I trust you can figure out how to re-implement strlen and use the write syscall with that. ;)

Related

How am I supposed to successfully achieve buffer overflow?

I am currently tackling on an assignment, where I need to upload exploit.c and target.c onto a ubuntu server, and successfully achieve a buffer overflow attack with exploit onto target. I was provided a shellcode. Now, target.c is not to be altered, just exploit.c. I had to use GDB on exploit.c to force an external breakpoint on foo() from target.c, to figure out the return addresses using info frame.
I was provided with the working shellcode, and minimal instructions.
I am pretty sure I was able to successfully pull the return addresses, but my issue is that I cannot figure out what code to put into exploit.c to have it successfully perform a buffer overflow attack. I was also instructed that one of the return addresses must be input into the exploit code for it to function properly.
I understand that the exploit is trying to call back to the return address, to then push itself into the buffer, so I can obtain access to the shell.
Here is exploit.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "shellcode.h"
// replace this define environment to have the correct path of your own target code
#define TARGET "/*******************"
int main(void)
{
char *args[3];
char *env[2];
char *tmp = NULL;
// Creating an input buffer that can cause buffer overflow in strcpy function in the target.c executable code
int buffSize = 1000;
char buff[buffSize];
// Intialize buffer elements to 0x01
int i;
for (i=0; i < buffSize; i++) buff[i] = 0x01;
// write your code below to fill the 22 bytes shellcode into the buff variable, and
// at the correct location overwrite the return address correctly in order to achieve stack overflow
// Your own code starts here:
strcpy (buff[buffSize-22], shellcode);
// Your code ends here.
// prepare command line input to execute target code
args[0] = TARGET; // you must have already compiled and generated the target executable code first
args[1] = buff; // the first input parameter to the target code (artfully crafted buffer overflow string)
args[2] = NULL;
env[0] = "FOO=bar";
env[1] = NULL;
if (0 > execve(TARGET, args, env))
fprintf(stderr, "execve failed.\n");
return 0;
}
Here is the target.c code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int foo(char* arg)
{
char localBuf[240];
short len = 240;
float var1=2.4;
int *ptr = NULL;
strcpy(localBuf, arg);
printf("foo() finishes normally.\n");
return 0;
}
int kbhit(void)
{
struct timeval tv;
fd_set read_fd;
tv.tv_sec=0; tv.tv_usec=0;
FD_ZERO(&read_fd); FD_SET(0,&read_fd);
if(select(1, &read_fd, NULL, NULL, &tv) == -1)
return 0;
if(FD_ISSET(0,&read_fd))
return 1;
return 0;
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "target: argc != 2\n");
exit(EXIT_FAILURE);
}
printf("Press any key to call foo function...\n");
while(!kbhit())
;
foo(argv[1]);
return 0;
}
I compiled both target and exploit. Then I ran GDB on exploit, and formed a breakpoint using "break target.c:10". Using Info Frame I was able to obtain the return addresses.
I used strcpy, because it is essentially the only line of code we were taught for this section involving overflow attacks, even though it clearly states in the document "Fill the shell executable code (in the string array shellcode[]) byte-by-
byte into the buff for your modified return address to execute, do not
use strcpy() because shellcode[] is not an ASCII string (and not
copying NULL byte, too)."
Exploit compiles fine, and it runs fine, but it does not give me access to a shell. I was instructed that I would know if it worked, if I was presented with two dollar signs ($$) instead of one ($).
I am a network engineer, and I am not entirely savvy with C, or attacking vulnerabilities in programs, any help would be appreciated. The entire lesson revolves around "stack overflow", but this assignment is called "buffer overflow attack".

Writing to proc file / give parameter by calling kernel module

I'm supposed to change a configuration parameter of the kernel by using a kernel module. The kernel module should create a proc file and then I should be able to change the parameter by using the cat command, e.g. cat "foobar" > /proc/prompt is supposed to set the parameter to "foobar", where prompt is the name of the proc file that was created in the module.
Furthermore I should be able to initialize the parameter by passing it as an argument when calling the module.
These two articles were basically the only relevant sources that I have found:
http://www.tldp.org/LDP/lkmpg/2.6/html/x769.html for writing to a proc file and http://www.tldp.org/LDP/lkmpg/2.6/html/x323.html for initializing the parameter from the command line.
Now I have a couple of questions, first of all this is the module thus far:
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include "sar_main.h"
#define PROCFS_NAME "sarlkm"
char procfs_buffer[PROCFS_MAX_SIZE];
static unsigned long procfs_buffer_size = 0
struct proc_dir_entry *proc_file_entry;
int procfile_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *eof, void *data){
int ret;
printk(KERN_INFO "procfile_read (/proc/%s) aufgerufen \n", PROCFS_NAME);
if (offset > 0){
ret = 0;
}
else{
memcpy(buffer, procfs_buffer, procfs_buffer_size);
ret = procfs_buffer_size;
}
return ret;
}
int procfile_write(struct file *file, const char *buffer, unsigned long count, void *data){
procfs_buffer_size = count;
if (procfs_buffer_size > PROCFS_MAX_SIZE){
procfs_buffer_size = PROCFS_MAX_SIZE;
}
if ( copy_from_user(procfs_buffer, buffer, procfs_buffer)){
return -EFAULT;
}
return procfs_buffer_size;
}
static int __init sar_init(void)
{
prompt_proc = create_proc_entry(PROCFS_NAME, 0644, NULL);
if (prompt_proc = NULL){
remove_proc_entry(PROCFS_NAME, &proc_root);
printk(KERN_ALERT "Error: Konnte proc file nicht kreieren")
return -ENOMEM;
}
prompt_proc->read_proc = procfile_read;
prompt_proc->write_proc = procfile_write;
printk(KERN_INFO "proc/%s wurde erfolgreich kreiert", PROCFS_NAME);
return 0;
}
static void __exit sar_cleanup(void)
{
remove_proc_entry(PROCFS_NAME, &proc_root);
printk(KERN_INFO "proc/%s gelöscht", PROCFS_NAME);
}
module_init(sar_init);
module_exit(sar_cleanup);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
I think I should say that I don't really understand why the read and write functions are supposed to work when using the cat command.
My main question is where exactly is the configuration parameter stored in the proc file? If I would write "foobar" to the proc file using cat and then use cat proc/prompt to read the parameter, how does the read function actually get the new value of the parameter, i.e. where is "foobar" stored in the procfile?
If I would try to initialize the parameter using a command line argument I would have to use a global variable in which to store the value of the parameter, but then how could I use that global variable in the read function, so that cat proc/prompt actually gives out the value that was given to the module from the command line?
The cat command internally calls the read() system call to read data from a file (see man strace).
read() passes the arguments to the VFS and the VFS finally calls your custom procfile_read() routine with the passed arguments (and some additional ones passed by the VFS code). If you want to know more about this, look at the fs directory in kernel sources, especially file read_write.c.
Your particular reading function copies, if some conditions are met, the parameter value (which is stored in procfs_buffer to answer one of your questions) into the user-supplied buffer allocated by cat, which is called buffer in your particular code. It is the same one as passed by the read() system call like in:
read(proc_fd, userspace_buf, 10); /* userspace_buf is buffer! */
Error checking omitted for clearness's sake.
To pass the value to the proc file you have two options:
Use module_param() and write it to your buffer; can only be done once because the module is only loadable once (or unload/reload it every time you want to change the parameter but that sounds inconvenient)
Invoke write() from userspace (like in cat) and modify the buffer as often as you want to (this is currently used by your code)
BTW, I really think your reading function should check the pointer to the user data, i.e. use copy_to_user(), not memcpy().
For further information, read Linux Device Drivers. There's only an old edition available at the moment but an updated one is being written.
you can treat xxx_write or xxx_read in driver just as a interface implement,
when you call write or read in user space,
the kernel will invoke xxx_write or xxx_read in kernel space.
so you need to store it yourself when write call,
and fetch them back when read call,
in xxx_write xxx_read

C Delete last n characters from file

I need to delete the last n characters from a file using C code. At fist I was trying to use '\b', but it returns a Segmentation Fault. I have seen interesting answers to similar questions here and here, but I would prefer to use mmap function to do this, if it's possible. I know it could be simpler to truncate the file by creating a temp file, and writing chars to temp until some offset of the original file. The problem is I don't seem to understand how to use mmap function to do this, can't see what parameters I need to pass to that function, specially address, length and offset. From what I've read, I should use MAP_SHARED in flags and PROT_READ|PROT_WRITE in protect.
The function definition says:
void * mmap (void *address, size_t length, int protect, int flags, int filedes, off_t offset)
Here is my main:
int main(int argc, char * argv[])
{
FILE * InputFile;
off_t position;
int charsToDelete;
if ((InputFile = fopen(argv[1],"r+")) == NULL)
{
printf("tdes: file not found: %s\n",argv[1]);
}
else
{
charsToDelete = 5;
fseeko(InputFile,-charsToDelete,SEEK_END);
position = ftello(InputFile);
printf("Pos: %d\n",(int)position);
int i;
//for(i = 0;i < charsToDelete;i++)
//{
// putc(InputFile,'\b');
//}
}
fclose(InputFile);
return 0;
}
Why not use:
#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);
like for instance:
charsToDelete = 5;
fseeko(InputFile,-charsToDelete,SEEK_END);
position = ftello(InputFile);
ftruncate(fileno(InputFile), position);
Read all but n bytes from the file and write to a temporary file, close the original file, rename temporary file as original file.
Or use e.g. truncate or similar function if you have it.
Also, failure to open the file doesn't have to be that it can't be found, You should check errno on failure to see what the error is. Use e.g. strerror to get a printable string from the error code.
Unfortunately, mmap does not allow you to change size of underlying file object.
Instead, I would recommend to simply truncate your file, use something like this:
truncate(filename, new_length);

Why can't my program save a large amount (>2GB) to a file?

I am having trouble trying to figure out why my program cannot save more than 2GB of data to a file. I cannot tell if this is a programming or environment (OS) problem. Here is my source code:
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS 64
#include <math.h>
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*-------------------------------------*/
//for file mapping in Linux
#include<fcntl.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/time.h>
#include<sys/mman.h>
#include<sys/types.h>
/*-------------------------------------*/
#define PERMS 0600
#define NEW(type) (type *) malloc(sizeof(type))
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
void write_result(char *filename, char *data, long long length){
int fd, fq;
fd = open(filename, O_RDWR|O_CREAT|O_LARGEFILE, 0644);
if (fd < 0) {
perror(filename);
return -1;
}
if (ftruncate(fd, length) < 0)
{
printf("[%d]-ftruncate64 error: %s/n", errno, strerror(errno));
close(fd);
return 0;
}
fq = write (fd, data,length);
close(fd);
return;
}
main()
{
long long offset = 3000000000; // 3GB
char * ttt;
ttt = (char *)malloc(sizeof(char) *offset);
printf("length->%lld\n",strlen(ttt)); // length=0
memset (ttt,1,offset);
printf("length->%lld\n",strlen(ttt)); // length=3GB
write_result("test.big",ttt,offset);
return 1;
}
According to my test, the program can generate a file large than 2GB and can allocate such large memory as well.
The weird thing happened when I tried to write data into the file. I checked the file and it is empty, which is supposed to be filled with 1.
Can any one be kind and help me with this?
You need to read a little more about C strings and what malloc and calloc do.
In your original main ttt pointed to whatever garbage was in memory when malloc was called. This means a nul terminator (the end marker of a C String, which is binary 0) could be anywhere in the garbage returned by malloc.
Also, since malloc does not touch every byte of the allocated memory (and you're asking for a lot) you could get sparse memory which means the memory is not actually physically available until it is read or written.
calloc allocates and fills the allocated memory with 0. It is a little more prone to fail because of this (it touches every byte allocated, so if the OS left the allocation sparse it will not be sparse after calloc fills it.)
Here's your code with fixes for the above issues.
You should also always check the return value from write and react accordingly. I'll leave that to you...
main()
{
long long offset = 3000000000; // 3GB
char * ttt;
//ttt = (char *)malloc(sizeof(char) *offset);
ttt = (char *)calloc( sizeof( char ), offset ); // instead of malloc( ... )
if( !ttt )
{
puts( "calloc failed, bye bye now!" );
exit( 87 );
}
printf("length->%lld\n",strlen(ttt)); // length=0 (This now works as expected if calloc does not fail)
memset( ttt, 1, offset );
ttt[offset - 1] = 0; // Now it's nul terminated and the printf below will work
printf("length->%lld\n",strlen(ttt)); // length=3GB
write_result("test.big",ttt,offset);
return 1;
}
Note to Linux gurus... I know sparse may not be the correct term. Please correct me if I'm wrong as it's been a while since I've been buried in Linux minutiae. :)
Looks like you're hitting the internal file system's limitation for the iDevice: ios - Enterprise app with more than resource files of size 2GB
2Gb+ files are simply not possible. If you need to store such amount of data you should consider using some other tools or write the file chunk manager.
I'm going to go out on a limb here and say that your problem may lay in memset().
The best thing to do here is, I think, after memset() ing it,
for (unsigned long i = 0; i < 3000000000; i++) {
if (ttt[i] != 1) { printf("error in data at location %d", i); break; }
}
Once you've validated that the data you're trying to write is correct, then you should look into writing a smaller file such as 1GB and see if you have the same problems. Eliminate each and every possible variable and you will find the answer.

How can I make the system call write() print to the screen?

For my OS class I'm supposed to implement Linux's cat using only system calls (no printf)
Reading this reference I found it being used to print to a file. I guess I should manipulate ofstream.
In the example appears: ofstream outfile ("new.txt",ofstream::binary);
How can I make it write to the screen?
EDIT: I realized this write() is part of iostream library, is this the same as the int write (int fd, char *buf , int size) system call?
A system call is a service provided by Linux kernel. In C programming, functions are defined in libc which provide a wrapper for many system calls. The function call write() is one of these system calls.
The first argument passed to write() is the file descriptor to write to. The symbolic constants STDERR_FILENO, STDIN_FILENO, and STDOUT_FILENO are respectively defined to 2, 0, and 1 in unidtd.h. You want to write to either STDOUT_FILENO or STDERR_FILENO.
const char msg[] = "Hello World!";
write(STDOUT_FILENO, msg, sizeof(msg)-1);
You can alternatively use the syscall() function to perform an indirrect system call by specifying the function number defined in syscall.h or unistd.h. Using this method, you can guarantee that you are only using system calls. You may find The Linux System Call Quick Refernence (PDF Link) to be helpful.
/* 4 is the system call number for write() */
const char msg[] = "Hello World!";
syscall(4, STDOUT_FILENO, msg, sizeof(msg)-1);
No, std::ostream::write is not the same as the write system call. It does (almost certainly) use the write system call, at least on a system like Linux that has such a thing, and it normally does pretty similar things, but it's still a separate thing of its own.
Linux will, however, pre-open standard input, standard output and standard error streams for your process. To write to the screen, you'd normally use write (i.e., the one that is a system call) to write to stream number 1 or stream number 2 (which are standard output and standard error respectively).
If you need to write to the screen even if those are re-directed, you'd normally open a stream to /dev/tty and (again) use write to write to it:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main() {
char msg[] = "hello\n";
int fd = open("/dev/tty", O_WRONLY);
write(fd, msg, sizeof(msg));
return 0;
}
#include <unistd.h>
/* ... */
const char msg[] = "Hello world";
write( STDOUT_FILENO, msg, sizeof( msg ) - 1 );
First argument is the file descriptor for STDOUT (usually 1), the second is the buffer to write from, third is the size of the text in the buffer (-1 is to not print zero terminator).
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <unistd.h> // For open, close, read, write, fsync
#include <sys/syscall.h> //For SYSCALL id __NR_xxx
//Method 1 : API
write(1,"Writing via API\n",\
strlen("Writing via API\n") );
fsync(1);
//Method 2 : Via syscall id
const char msg[] = "Hello World! via Syscall\n";
syscall(__NR_write, STDOUT_FILENO, msg, sizeof(msg)-1);
syscall(__NR_fsync, STDOUT_FILENO ); // fsync(STDOUT_FILENO);
Your reference is incorrect. It's part of C++ and has nothing to do with your assignment. The correct reference is http://www.opengroup.org/onlinepubs/9699919799/functions/write.html

Resources