Bonjour, voici mon dernier tool, fini qui permet de surveiller en permanence (enfin presque) un répertoire.
La première étape est de faire une sauvegarde du md5sum de tous les fichiers du répertoire (et des sous répertoires), puis vous pourrez ensuite lancer une comparaison des md5sum des fichiers avant ceux sauvegardés précédemment.
Si un fichier est supprimé, ou rajouté, alors le reste est décalé et donc la détection se fait également.
La prévention se fait par mail, mais ayant rencontré des difficulté à faire fonctionner le protocole SMTP avec celui de google, j'ai opté pour une solution autre.
L'alerte fait une simple requete HTTP vers une page PHP qui elle, envoi le mail à l'adresse désirée.
La partie sur les sockets n'était pas le but de mon exercice ici, elle est donc probablement loin d'être parfait et est fait de plusieurs bouts de codes trouvés à gauche à droite (je ne maitrise pas les socket en C/C++).
Il faut installer le paquet : libcrypto++ pour que la compilation fonctionne correctement.
Voici le code :
Code :
#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
#define USERAGENT "HTMLGET 1.0"
#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <fstream>
#include <dirent.h>
#include <sys/socket.h>
#include <cryptopp/md5.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
/*
* Use ./tool d to create a md5sum of all the directory's files
* Use ./tool s to scan all the directory's files and check with the previous
* You can change the socket part to use a SMTP and send a mail, but I use a request
* to a php file which send a mail (more easy).
* Compilation : sudo g++ crypt.cpp -o crypt -lcryptopp
*/
using namespace std;
using namespace CryptoPP;
string md5sum(string directory, string filename); // Return the md5sum of a file
int dumpFile(string directory, ofstream& output); // Make a new backup of all the files md5sum
int scanFile(string directory, ifstream& input); // Check the file and compare to the backup
void mail(); // Send a mail
char *get_ip(char *host); // Get ip from domaine
int create_tcp_socket(); // Create a socket
char *build_get_query(char *host, char *page); // Create the query
void usage(char *name); // Show the usage
int scan(0);
int main(int argc, char *argv[]){
mail();
string directory = "/home/user/Desktop";
if(argc == 2){
if(argv[1][0] == 'd'){ // Make a backup of the md5sum
ofstream output("dumpMd5", ios::out | ios::trunc);
dumpFile(directory, output);
}else if(argv[1][0] == 's'){ // Scan the file and check them
ifstream input("dumpMd5", ios::in);
scanFile(directory, input);
cout << scan << endl;
if(scan)
mail();
}
}else
usage(argv[0]);
return 0;
}
/* Send a mail if there are detected files */
void mail(){
struct sockaddr_in *remote;
char *host = "site.com", *page = "mail.php?id=password", *ip, *get, *htmlcontent;
char buf[BUFSIZ+1];
int sock, tmpres, sent(0), htmlstart(0);
sock = create_tcp_socket();
ip = get_ip(host);
remote = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in *));
remote->sin_family = AF_INET;
tmpres = inet_pton(AF_INET, ip, (void *)(&(remote->sin_addr.s_addr)));
remote->sin_port = htons(80);
if(connect(sock, (struct sockaddr *)remote, sizeof(struct sockaddr)) < 0){
perror("Could not connect");
exit(1);
}
get = build_get_query(host, page);
while(sent < strlen(get))
{
tmpres = send(sock, get+sent, strlen(get)-sent, 0);
if(tmpres == -1){
perror("Can't send query");
exit(1);
}
sent += tmpres;
}
memset(buf, 0, sizeof(buf));
while((tmpres = recv(sock, buf, BUFSIZ, 0)) > 0){
if(htmlstart == 0)
{
htmlcontent = strstr(buf, "\r\n\r\n");
if(htmlcontent != NULL){
htmlstart = 1;
htmlcontent += 4;
}
}else{
htmlcontent = buf;
}
memset(buf, 0, tmpres);
}
free(get);
free(remote);
free(ip);
close(sock);
}
int create_tcp_socket(){
int sock;
if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
perror("Can't create TCP socket");
exit(1);
}
return sock;
}
char *get_ip(char *host){
struct hostent *hent;
int iplen = 15;
char *ip = (char *)malloc(iplen+1);
memset(ip, 0, iplen+1);
if((hent = gethostbyname(host)) == NULL){ // Get the IP from de NDD
herror("Can't get IP");
exit(1);
}
if(inet_ntop(AF_INET, (void *)hent->h_addr_list[0], ip, iplen) == NULL){
perror("Can't resolve host");
exit(1);
}
return ip;
}
char *build_get_query(char *host, char *page){
char *query;
char *getpage = page;
char *tpl = "GET /%s HTTP/1.0\r\nHost: %s\r\nUser-Agent: %s\r\n\r\n"; // We send a GET request on the server
if(getpage[0] == '/')
getpage = getpage + 1;
query = (char *)malloc(strlen(host)+strlen(getpage)+strlen(USERAGENT)+strlen(tpl)-5);
sprintf(query, tpl, getpage, host, USERAGENT);
return query;
}
string md5sum(string directory, string filename){
std::ostringstream oss;
std::ifstream file;
Weak1::MD5 hash;
byte md5[Weak1::MD5::DIGESTSIZE];
int length = 0;
char *buffer;
if(directory[directory.length()-1] != '/')
directory.append("/");
directory.append(filename);
file.open(directory.c_str(), std::ios::binary);
file.seekg(0, std::ios::end);
length = file.tellg();
file.seekg(0, std::ios::beg);
buffer = new char[length];
file.read(buffer, length); // Read the file
file.close();
hash.CalculateDigest(md5, (unsigned char *)buffer, length);
for(int i=0; i<Weak1::MD5::DIGESTSIZE; i++){
oss<< std::hex << std::setfill('0') << std::setw(2) << (unsigned short)(md5[i]); // Add the hex value to OSS
}
delete [] buffer;
return oss.str();
}
int dumpFile(string directory, ofstream& output){
string path="";
DIR *dir = NULL;
struct dirent *file = NULL;
if((dir = opendir(directory.c_str())) == NULL){
return 1;
}
while((file = readdir(dir)) != NULL){
if(strcmp(file->d_name, ".") && strcmp(file->d_name, "..")){
if(file->d_type == DT_DIR || file->d_type == DT_LNK){
path= "";
dumpFile(path.append(directory).append("/").append(file->d_name), output);
}else{
output << file->d_name << endl << md5sum(directory, file->d_name) << endl; // Write the result on 2 lines (first the name, then de md5
}
}
}
closedir(dir);
return 0;
}
int scanFile(string directory, ifstream& input){
string fichier, md5, path("");
DIR *dir = NULL;
struct dirent *file = NULL;
if((dir = opendir(directory.c_str())) == NULL){
return 1;
}
while((file = readdir(dir)) != NULL){
if(strcmp(file->d_name, ".") && strcmp(file->d_name, "..")){
if(file->d_type == DT_DIR || file->d_type == DT_LNK){
path = "";
scanFile(path.append(directory).append("/").append(file->d_name), input);
}else{
getline(input,fichier); // Store the filename
getline(input,md5); // Store de file's md5sum
if(strcmp(file->d_name, fichier.c_str()) || strcmp(md5sum(directory, file->d_name).c_str(),md5.c_str())){
scan++;
return 0;
}
}
}
}
closedir(dir);
return 0;
}
void usage(char *name){
cout << "#######################" << endl;
cout << " Md5Sum checker " << endl << endl;
cout << " To make a dump: " << endl;
cout << " "<< name << " d"<< endl;
cout << " To lauch the scan: " << endl;
cout << " "<< name << " s" << endl << endl;
cout << "#######################" << endl;
}
Et un code php correspondant
Code :
<?php
if($_GET['id'] == "password")
mail("email@email.com","Subjet","Ceci est un message de prévention car une intrusion a été détectée sur votre site","");
?>
Quelques améliorations possibles :
Le programme de fait qu'un seul scan, ce qui n'est pas pratique, le mieux serait de l'intégré à un système de daemon, ou alors un système de boucle infini (avec un sleep par exemple) pour que la detection se fasse en continu.
Necromoine