Final results

August 16th, 2008 by snagg

Hi all, it has been a long time since my last post. Due to some problems I didn’t have the chance to update this blog. Anyhow before the end of the soc, I’m here to speak about what I did in this period.First of all my auditpipe patch changed a bit: it supports only pid-based subscription to events due to internal decision taken by me and other developers. How to use it then?
fd = open(“/dev/auditpipe”, O_RDONLY);
if (fd < 0)
err(-1, “/dev/auditpipe”);

entry = malloc(sizeof(struct auditpipe_ioctl_preselect_proc));
if(entry == NULL)
err(-1, “MALLOC”);

value = AUDITPIPE_PRESELECT_MODE_PROC;
if (ioctl(fd, AUDITPIPE_SET_PRESELECT_MODE, &value) aipp_pid = pid;

if (ioctl(fd, AUDITPIPE_SET_PRESELECT_PROC, entry) < 0)
err(-1, “AUDITPIPE_SET_PRESELECT_EVENTS”);

What it does is to open auditpipe, change the preselection mode to AUDITPIPE_PRESELECT_MODE_PROC and set up an entry with a specific pid. From there on auditpipe will trace that specific pid. Clean and concise:P   Now the second half of the project. I ought to write a regression test framework. After several unsuccessful attempts, I figured out how to make it works with a bit of shared memory. The general idea is to have a testing function/process which communicates with a parent process and exchange runtime information in order to run the test.  The testing function will take read records from auditpipe and compare them with runtime information collected before. If some inconsistencies are found they are reported. More in details, here is a sample testing module:
/*-
* Copyright (c) 2008 Vincenzo Iozzo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS “AS IS” AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/

#include “audit_pipe_regression_test_utils.h”

struct sysctl_record
{
int mib[6];
char err_val[256];
int ret;
int index;
struct sysctl_record *next;
};

struct sysctl_record *
add_field(struct sysctl_record *head, struct sysctl_record *new)
{
struct sysctl_record *tmp;

tmp = head;
if(tmp == NULL) {
new->next = NULL;
return (new);
}

/* Reach the last element of the list*/
for(; tmp->next != NULL;tmp = tmp->next);

new->index = tmp->index +1;
tmp->next= new;
new->next = NULL;

return (head);
}

void test_sysctl()
{
int mib[2];
int ret, val;

init_channel_primary();

mib[0] = CTL_KERN;
mib[1] = KERN_SECURELVL;
val = 2;
ret = sysctl(&mib, 2, NULL, NULL, &val, sizeof(int));

write_int(mib[0], “arg”);
write_int(mib[1], “arg1″);
write_int(ret, “ret”);
if (ret == -1)
write_string(strerror(errno), “ret_val”);
else
write_string(“success”, “ret_val”);
write_end();

val = 1;
ret = sysctl(&mib, 2, NULL, NULL, &val, sizeof(int));
write_int(mib[0], “arg”);
write_int(mib[1], “arg1″);
write_int(ret, “ret”);
if (ret == -1)
write_string(strerror(errno), “ret_val”);
else
write_string(“success”, “ret_val”);
write_end();

end_channel();

/* Let auditsysctl flush all data */
sleep(5);
return;
}

void validate(FILE *f, struct sysctl_record *head, char *path, pid_t pid)
{
int i, ret, reclen, bytesread, to_parse, arg_counter;
struct sysctl_record *tmp, *elem;
int err = -1;
tokenstr_t tok;
u_char *buf;
u_char type = 0;
FILE *fp;
long control_flag;

to_parse = WAITING;
arg_counter = 0;
control_flag = 0;

fp = fopen(path, “r”);
if(fp == NULL)
return;

tmp = head;
if(tmp == NULL)
return;

while(1) {

to_parse = WAITING;
if(!err || reclen == -1)
break;

/* Record must begin with a header token. */
do {
type = fgetc(fp);
} while(type != AU_HEADER_32_TOKEN);
ungetc(type, fp);

while ((reclen = au_read_rec(fp, &buf)) != -1) {
bytesread = 0;
while (bytesread mib[0]);
else
ret = check_arg(tok.tt.arg32, tmp->mib[1]);

if(!ret)
report_error(tok, f);
break;

case AUT_RETURN32:
TOKEN_FLAG_SET(control_flag, TOKEN_RETURN);
ret = check_ret(tok.tt.ret32, tmp->ret, tmp->err_val);
if(!ret)
report_error(tok, f);
break;

case AUT_TRAILER:
to_parse = WAITING;
if(!TOKEN_FLAG_ISSET(control_flag, TOKEN_SUBJECT))
report_error_string(“Missing Subject token”, f);
if (!TOKEN_FLAG_ISSET(control_flag, TOKEN_ARG) || arg_counter != 2)
report_error_string(“Missing Argument token”, f);
if(!TOKEN_FLAG_ISSET(control_flag, TOKEN_RETURN))
report_error_string(“Missing Return token”, f);
control_flag = 0;
arg_counter = 0;
if(tmp->next != NULL)
tmp = tmp->next;
break;

default:
break;
}
}
}
}
}

free(buf);
fclose(fp);
}

int
main(int argc, char *argv[])
{
int i, quit, fd, value, index, fdout, count;
char *shared_string, *descr, path[512];
pid_t pid;
struct sysctl_record *head, *elem;
FILE *f;

index = 0;
head = NULL;

init_channel();

pid = fork();
if(!pid) {
sleep(15);
test_sysctl();
} else {
fd = setup_auditpipe(pid);
snprintf(path, 512, “/tmp/audit-%d”, pid);

fdout = open(path, O_RDWR | O_CREAT);
if(fdout == -1)
err(-1, “OPEN”);

quit = 0;
while (!waitpid(pid, &quit, WNOHANG)) {

/* Audit pipe input. */
read_auditpipe(fd, fdout);

/*
* See whether is there anything on the shared-memory,
* if so build a structure
*/
sem_getvalue(mutex, &count);
if(count) {
shared_string = read_string();
elem = malloc(sizeof(struct sysctl_record));
if(elem == NULL)
err(-1, “MALLOC”);

while((count = parse_string(shared_string)) != -1) {
descr = get_descr(shared_string);
if(count == INT_TYPE) {
if(!strncmp(descr, “arg1″, 4))
elem->mib[1] = get_int(shared_string);
else if (!strncmp(descr, “arg”, 3))
elem->mib[0] = get_int(shared_string);
else
elem->ret = get_int(shared_string);
}
else if ( count == STRING_TYPE) {
snprintf(elem->err_val, sizeof(elem->err_val) >
strlen(shared_string) +1 ?
strlen(shared_string) +1 :
sizeof(elem->err_val), “%s”,
shared_string);
}
shared_string = read_string();
}
head = add_field(head, elem);
if(head == NULL)
err(-1, “List error”);
}
}
}
close_auditpipe(fd, fdout);
end_channel();
f = init_log(pid);
validate(f, head, path, pid);
fclose(f);
return (0);
}

As you might see, the validate() function will compare records against collected data, whereas the test_sysctl() will send  to the parent, using shared memory, information regarding the events. You might see a sort of  ”API” here, those functions were provided in order to ease tests writing. They are somehow commented, so you might find useful to take a look at the code. I wrote tests for 20 events, but theoretically they are 500+, so we need your help. As usual if you have any kind of suggestions or comments feel free to contact me. Here: http://www1.autistici.org/snagg/final.zip you can find the whole code.  Cheers,Snagg 

Some results

June 1st, 2008 by snagg

I was a bit talkish in the last days but still I didn’t provide anything practical to my “two” readers.
So here we go:
I’ve decided to let auditpipe trace a small program:

int main(){
gid_t *gid;
int i;

gid = malloc(25);
memset(gid, 15*4, 0x41);
setgroups(15, gid);

printf("%s\n", strerror(errno));
return 0;
}

The code needed was just:

value = 4;
if(ioctl(fd, AUDITPIPE_SET_PRESELECT_MODE, &value) < 0)
err(-1, "AUDITPIPE_SET_PRESELECT_MODE");


entry->app_pid = pid;
entry->app_event_len = 0;
if(ioctl(fd, AUDITPIPE_SET_PRESELECT_EVENTS) < 0)
err(-1, "AUDITPIPE_SET_PRESELECT_EVENTS");

After that I just needed to read from /dev/auditpipe.
The results (in a xml-readable form).
As you can see the whole execution flow for a given pid (823) was traced.
So you don’t have to use some complex regex to take out from a very huge auditd log file the record you’re interested in.
Hope it will help you.
Snagg

Patch Published

May 30th, 2008 by snagg

Here you can find my patch for auditpipe. If you ever have the chance to try it, please let me know. Feel free to  mail me for comments, suggestions and bug-fixes. 

Kernel part finished

May 28th, 2008 by snagg

Hi,I’ve just finished with the kernel part of my project. I’ve introduced some new features to auditpipe. Specifically, it’s now possibile to set up a trail which will trace by pid or by an events’ list associated to a specific pid. To specify which of the tracing capability you’d like to have in your trail you just have to select it with ioctl. Now it’s also possible to retrieve information about pid and events for a specific trail. To manage the events array I’ve used qsort to sort in ascending order the array and binary search to performe searches for specific events. If you like to see the code you’ll find it in my perforce repository.From now on I will mainly focus on regression tests. When I have something done, I’ll leave a post here. 

Some news

May 12th, 2008 by snagg

I’ve just finished to upload the code onto my perforce branch. At the moment the whole code is ready for testing, which means that, now, should be possibile to audit events one-by-one. Specifically I’ve added some functionalities to audit_pipe_ioctl which allow to do the same operation done before but on events list instead of audit classes. Also all the functions needed to manage the events list were made up. The audit_pipe_preselect structure was modified, adding a pid field and a dynamic array of structs which hold the events’ list.  The KPI now has two new prototype for audit_pipe_preselect and audit_pipe_submit in order to allow event matching by pid. As soon as the testing period is finished maybe new features will be added. All the code could be found on my perforce branch. I’d really appreciate if anyone willing to help will test the code and give me some feedback. Also please note that the whole code is in a really alpha-stage.That’s all folks,Snagg 

First post, me and my project

May 1st, 2008 by snagg

Hi all,I’m Vincenzo Iozzo, currently I’m studying computer engineering at the Politecnico di Milano. I also work for Secure Network srl. And in the spare time I do some research for my university. I’m mainly involved in IT Security.   Now, after this brief presentation, I’d like to spend a few words on my project for this Summer Of Code.  I will modify the FreeBSD auditpipe support in order to provide more granularity while auditing syscalls. In fact, at the present time, your choice on what to audit is limited to default classes. With my patch it would be possible to select every syscall by its own. The second half of the project will consist of creating a framework for testing the correct behavior of the auditing system and, if needed, patching it.Finally the whole auditing system will be checked in order to see whether or not is vulnerable at some anti-forensics techiniques.  Here you can find a detailed description of the first part of the project.Snagg