‏הצגת רשומות עם תוויות security. הצג את כל הרשומות
‏הצגת רשומות עם תוויות security. הצג את כל הרשומות

יום שני, 13 ביולי 2015

MySql Proxy



מסדי נתונים חשופים להמון סוגים של התקפות וזליגת מידע, דרך לטפל בבעיה היא בעזרת Proxy שיושב בין מי שמבקש ולמסד עצמו ומאפשר לנתח את הבקשות והתשובות לפני שהן חוזרות בחזרה ללקוח, נניח שמשהו הצליח לבצע הזרקה של קוד זדוני שמחזיר את כל כרטיסי האשראי בטבלה, הפרוקסי יכול לתפוס את הבקשה ולהפיל אותה, או לעשות מיסוך על כרטיסי האשראי בצורה שלא יהיה ניתן לעשות איתם שימוש.

דרישות:

שימו לב!
  • המאמר נכתב על Windows 7 64 Bit
לפני שנתחיל לצלול פנימה יש להוריד את ולפרוס את קבצי MySql Proxy באיזה מקום שתרצו על השרת, לאחר מכן יש להוריד ולהתקין את Lua, שפת סקריפטים מאוד מהירה, היא פופלרית בעיקר ב Embedded ומשחקי מחשב, היה בה שימוש רחב ב World Of Warcraft.

לצורך הדוגמה ניצור טבלה שתכיל מספרי אשראי ונעמיס עליה נתונים,נבצע שאילתה פשוטה:

בקשה ישירה למסד הנתונים

התוצאות מכילות כרטיסי אשראי שניתן לראות אותם בבירור בתשובה שחוזרת, כמובן שהדרך המסורתית היא להצפין את המידע אבל הכלים שה Proxy נותן מאפשרים לך שליטה על כל נקודה מרגע ההתממשקות עד להחזרת התוצאות ללקוח כפי שנראה בהמשך.

Proxy

פעולת ה Proxy היא ברורה מאוד וכבר הספקתי לכתוב עליה בעבר, אבל במבט מהיר אפשר לראות שהמשתמשים לא באמת מגיעים למסד נתונים אלא לתחנת בניים שתחליט מה לעשות עם הבקשה והתשובה שחוזרת, בשונה מ Proxy "רגיל" שמעביר דרכו בקשות ומשנה אותם באופן בסיסי, ה MySql Proxy מאפשר לנתח את הפרוטוקול ולשנות אותו באופן פשוט למדי.


על מנת להפעיל את ה Proxy יש לכתוב את הפקודה הבאה:

C:\mySqlProxy\bin>mysql-proxy.exe --proxy-backend-addresses=127.0.0.1:3306 --proxy-address=127.0.0.1:4040 --proxy-lua-script=all-hooks.lua

הפקודה מחברת את שרת ה Proxy למסד הנתונים ובנוסף מוסיפים קריאה לקובץ סקריפט של Lua, מאותו רגע כל בקשה שתגיע לפורט 4040 תפעיל מספר פונקציות ונוכל לדוג אותן, לדוגמה ברגע שיבצעו שיאלתא, הפונקציה read_query תרוץ ונוכל להחליט אם להעביר את השאילתא או לא ובמקרה של תשובה מהשרת הפונקציה read_query_result תרוץ ובה נוכל לשנות את המידע שחוזר.

Hooks


-- all-hooks.lua
local access_ndx = 0

-- fired when client connect to server
function connect_server()
    print_access ('inside connect_server')
end

-- fired when starting the handshake
function read_handshake( auth )
    print_access ('inside read_handshake' )
end

-- fired when starting the authentication
function read_auth( auth )
    print_access ('inside read_auth ')
end

--fired when authentication finished
function read_auth_result( auth )
    print_access ('inside read_auth_result')
end

--fired when client disconnected
function disconnect_client()
    print_access('inside disconnect_client')
end

--fired when query requested
function read_query (packet)
proxy.queries:append(1, packet,{ resultset_is_needed = true })
return proxy.PROXY_SEND_QUERY
end

--fired when query result
function read_query_result (inj)

--create result set containes columns and rows
proxy.response.resultset = {fields = {}, rows = {}}

--checking if the query holding creditcard table name
if(string.match(inj.query,"creditcard")) then

for n = 1, #inj.resultset.fields do
-- insert column to table
table.insert(proxy.response.resultset.fields, {type
             =inj.resultset.fields[n].type,name = inj.resultset.fields[n].name})
end


for row in inj.resultset.rows do
if(row ~= nil) then
 for i,v in pairs(row) do
--looking for creditcard pattern
if string.match(v,'%d%d%d%d%-%d%d%d%d%
                                                                 -%d%d%d%d%-%d%d%d%d') then
print_access("found visa - column position: " .. i 
                                                                      .. " column value: " .. v)
row[i] = "mask credit card"
end
 end
table.insert(proxy.response.resultset.rows, row)
end
end

--overwrite results
proxy.response.type = proxy.MYSQLD_PACKET_OK
return proxy.PROXY_SEND_RESULT
end
end

-- simple print message
function print_access(msg)
    access_ndx = access_ndx + 1
    print( string.format('%3d %-30s',access_ndx,msg))
end



מייצרים טבלה ריקה, עוברים על הטבלה שחזרה מהמסד נתונים ושופכים אותה לטבלה שיצרנו, לפני שמכניסים שורה חדשה מחפשים אם יש ערך שתואם למבנה כרטיס אשראי ודורסים אותו.

התוצאות שחוזרות מה Proxy


סיכום

ראינו רק דרך פעולה אחת עם ה Proxy ש MySql  אבל אפשר להשתמש בו בתחומים נוספים כמו ניהול עומסים, שרידות ובקרה, בעזרתו ניתן להגדיל את הזמינות ואמינות המידע ולהדק את חגורת האבטחה סביב המידע שרגיש לכולנו.

לא תשתמש בו?

יום שבת, 1 בנובמבר 2014

Deep Packet Inspection With C



מערכות FireWall בדר"כ בוחנות את החבילות שעוברות דרכן רק על ידי אימות של כתובות ופורטים מול רשימת חוקים, אבל עם הזמן הבינו שזה לא מספיק טוב ויש לנתח את המידע עצמו שעובר בחבילה על מנת לזהות התקפות שמשפיעות על השירות עצמו, נדרשה חשיבה חדשה ועם הזמן צצו מערכות IDS \ IPS שבעזרתם ניתן לבצע בדיקות שמבוססות על תבניות ולחפש קוד זדוני בתוך החבילה, פרוייקט מאוד מפורסם ונמצא בשימוש רחב במערכות כאלו נקרא Snort שמכיל המון תבניות להתקפות מוכרות.

שימו לב!
  • המאמר נכתב על Fedora 13.
  • הקוד נערך ב Eclipse.
כל חבילה שמגיעה למכונה עוברת בדיקה מול החוקים שהוגדרו ב iptables שעובד מול ה NetFilter שיושב ב Kernel, אם החוקים מאפשרים להעביר את החבילה ליעד ה Netfilter יאשר את החבילה (NF_ACCEPT) אבל במקרה שהחוקים חוסמים אותה הוא יפיל את החבילה (NF_DROP), אלה 2 הפעולות הבסיסיות שנמצאות בכל Firewall אבל זה לא מספיק וצריך לחפור יותר פנימה, ניתן לרשום חוק שמפנה את המידע (NF_QUEUE) למחסנית שמאפשרת גישה לתוכניות מעולם ה UserSpace לנתח את החבילות ולחרוץ את גורלם.

התוכנית קובעת את גורל החבילה

לצורך הדוגמה החוק הבא מכניס את כל המידע שמגיע למחסנית במיקום 0 אבל במקרה של עבודה אינטנסיבית המחסנית תתמלא עוד לפני שנספיק לנקות אותה ולכן החוק הזה לא כלכך יעיל:

#: iptables -A INPUT  -j NFQUEUE --queue-num 0 --queue-balance

עבור ניתוח יעיל יותר צריכים לעבוד במקביל, ניתן לפצל חוק בין מספר מחסניות שונות כפי שניתן לראות בדוגמה:

#: iptables -A INPUT  -j NFQUEUE --queue-balance 0:3
#: iptables -A OUTPUT  -j NFQUEUE --queue-balance 4:8


Libnetfilter_queue Library

ספריה רשמית שמאפשרת לנהל את החבילות שנמצאות במחסניות בעזרת עבודה מול Netlink דרך Unix Domain Socket, היא מחליפה ספרייה ישנה יותר שנקראת ip_queue והיא נמצאת כמעט בכל Distribution של Linux, אבל בשביל לעבוד איתה יש להוריד את ה Headers ולהכין את ה Eclipse:

#: yum install libnetfilter_queue
#: yum install libnetfilter_queue-devel


נשלב את הספריות המתאימות ב Linker:





קוד

פונקצית Main מייצרת מערך של Threads שכל אחד מהם מתחבר ל Queue אחר, כאשר תגיע חבילה לאחת מהמחסניות, פונקציית packetHandler תרוץ ודרכה ננתח את המידע, לצורך הדוגמה כאשר נזהה את המילה facebook בתוכן החבילה נפיל אותה ונחסום את הגישה.

filterQueue.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <linux/types.h>
#include <string.h>

/* for ethernet header */
#include<net/ethernet.h>

/* for UDP header */
#include<linux/udp.h>

/* for TCP header */
#include<linux/tcp.h>

/* for IP header */
#include<linux/ip.h>

/*  -20 (maximum priority) */
#include <sys/time.h>
#include <sys/resource.h>

/* for NF_ACCEPT */
#include <linux/netfilter.h>

/* for Threads */
#include <pthread.h>

/* for Queue */
#include <libnetfilter_queue/libnetfilter_queue.h>

#define NUM_THREADS     15

pthread_t threads[NUM_THREADS];

void printTCP(unsigned char *buffer) {

unsigned short iphdrlen;

struct iphdr *iph = (struct iphdr *) (buffer + sizeof(struct ethhdr));
iphdrlen = iph->ihl * 4;

struct tcphdr *tcph = (struct tcphdr *) (buffer + iphdrlen
+ sizeof(struct ethhdr));

int header_size = sizeof(struct ethhdr) + iphdrlen + tcph->doff * 4;

printf("| Packet Type: TCP \n");
printf("|-Source Port      : %u\n", ntohs(tcph->source));
printf("|-Destination Port : %u\n", ntohs(tcph->dest));
printf("|-Sequence Number    : %u\n", ntohl(tcph->seq));
printf("|-Acknowledge Number : %u\n", ntohl(tcph->ack_seq));
printf("|-Header Length      : %d DWORDS or %d BYTES\n",
(unsigned int) tcph->doff, (unsigned int) tcph->doff * 4);
printf("|-CWR Flag : %d\n", (unsigned int) tcph->cwr);
printf("|-ECN Flag : %d\n", (unsigned int) tcph->ece);
printf("|-Urgent Flag          : %d\n", (unsigned int) tcph->urg);
printf("|-Acknowledgement Flag : %d\n", (unsigned int) tcph->ack);
printf("|-Push Flag            : %d\n", (unsigned int) tcph->psh);
printf("|-Reset Flag           : %d\n", (unsigned int) tcph->rst);
printf("|-Synchronise Flag     : %d\n", (unsigned int) tcph->syn);
printf("|-Finish Flag          : %d\n", (unsigned int) tcph->fin);
printf("|-Window         : %d\n", ntohs(tcph->window));
printf("|-Checksum       : %d\n", ntohs(tcph->check));
printf("|-Urgent Pointer : %d\n", tcph->urg_ptr);
}

void printUDP(unsigned char *buffer) {
unsigned short iphdrlen;

struct iphdr *iph = (struct iphdr *) (buffer + sizeof(struct ethhdr));
iphdrlen = iph->ihl * 4;

struct udphdr *udph = (struct udphdr*) (buffer + iphdrlen
+ sizeof(struct ethhdr));

int header_size = sizeof(struct ethhdr) + iphdrlen + sizeof udph;

printf("| Packet Type: UDP \n");
printf("|-Source Port      : %u\n", ntohs(udph->source));
printf("|-Destination Port : %u\n", ntohs(udph->dest));
printf("|-UDP Length : %u\n", ntohs(udph->len));
printf("|-UDP Checksum : %u\n", ntohs(udph->check));

}

char * getText(unsigned char * data, char Size) {

char * text = malloc(Size);
int i = 0;

for (i = 0; i < Size; i++) {
if (data[i] >= 32 && data[i] <= 128)
text[i] = (unsigned char) data[i];
else
text[i] = '.';
}
return text;

}

u_int32_t analyzePacket(struct nfq_data *tb, int *blockFlag) {

//packet id in the queue
int id = 0;

//the queue header
struct nfqnl_msg_packet_hdr *ph;

//the packet
char *data;

//packet size
int ret;

//extracting the queue header
ph = nfq_get_msg_packet_hdr(tb);

//getting the id of the packet in the queue
if (ph)
id = ntohl(ph->packet_id);

//getting the length and the payload of the packet
ret = nfq_get_payload(tb, &data);
if (ret >= 0) {

printf("Packet Received: %d \n", ret);

/* extracting the ipheader from packet */
struct sockaddr_in source, dest;
unsigned short iphdrlen;

struct iphdr *iph = ((struct iphdr *) data);
iphdrlen = iph->ihl * 4;

memset(&source, 0, sizeof(source));
source.sin_addr.s_addr = iph->saddr;

memset(&dest, 0, sizeof(dest));
dest.sin_addr.s_addr = iph->daddr;

printf("|-Source IP: %s\n", inet_ntoa(source.sin_addr));
printf("|-Destination IP: %s\n", inet_ntoa(dest.sin_addr));
printf("|-Checking for Protocol: \n");

if (iph->protocol == 6) {
printTCP(data);
} else if (iph->protocol == 17) {
printUDP(data);
}

printf("|-Extracting Payload: \n");

char * text = getText(data, ret);

//filtering requests for facebook
if (text && text[0] != '\0') {
printf("\n %s \n", text);
ret = strstr(text, "facebook");
if (ret == 0)
//not found in string
*blockFlag = 0;
else
//found in string
*blockFlag = 1;
}

//release the packet
free(text);


}
//return the queue id
return id;

}

int packetHandler(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa,
void *data) {

printf("entering callback \n");

//when to drop
int blockFlag = 0;

//analyze the packet and return the packet id in the queue
u_int32_t id = analyzePacket(nfa, &blockFlag);

//this is the point where we decide the destiny of the packet
if (blockFlag == 0)
return nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL);
else
return nfq_set_verdict(qh, id, NF_DROP, 0, NULL);



}

void *QueueThread(void *threadid) {

//thread id
long tid;
tid = (long) threadid;


struct nfq_handle *h;
struct nfq_q_handle *qh;
char buf[128000] __attribute__ ((aligned));

//pointers and descriptors
int fd;
int rv;
int ql;


printf("open handle to the netfilter_queue - > Thread: %d \n", tid);
h = nfq_open();
if (!h) {
fprintf(stderr, "cannot open nfq_open()\n");
return NULL;
}

//unbinding previous procfs
if (nfq_unbind_pf(h, AF_INET) < 0) {
fprintf(stderr, "error during nfq_unbind_pf()\n");
return NULL;
}

//binding the netlink procfs
if (nfq_bind_pf(h, AF_INET) < 0) {
fprintf(stderr, "error during nfq_bind_pf()\n");
return NULL;
}

//connet the thread for specific socket
printf("binding this socket to queue '%d'\n", tid);
qh = nfq_create_queue(h, tid, &packetHandler, NULL);
if (!qh) {
fprintf(stderr, "error during nfq_create_queue()\n");
return NULL;
}

//set queue length before start dropping packages
ql = nfq_set_queue_maxlen(qh, 100000);

//set the queue for copy mode
if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) {
fprintf(stderr, "can't set packet_copy mode\n");
return NULL;
}

//getting the file descriptor
fd = nfq_fd(h);

while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {
printf("pkt received in Thread: %d \n", tid);
nfq_handle_packet(h, buf, rv);
}

printf("unbinding from queue Thread: %d  \n", tid);
nfq_destroy_queue(qh);

printf("closing library handle\n");
nfq_close(h);

return NULL;

}

int main(int argc, char *argv[]) {

//set process priority
setpriority(PRIO_PROCESS, 0, -20);

int rc;
long balancerSocket;
for (balancerSocket = 0; balancerSocket < NUM_THREADS; balancerSocket++) {
printf("In main: creating thread %ld\n", balancerSocket);

//send the balancer socket for the queue
rc = pthread_create(&threads[balancerSocket], NULL, QueueThread,
(void *) balancerSocket);

if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}

while (1) {
sleep(10);
}

//destroy all threads
pthread_exit(NULL);
}

טיפ קטן

אם רוצים לעקוב אחרי העומסים במחסניות ניתן לקרוא את הקובץ nfnetlink_queue:

/proc/net/netfilter


סיכום

ניתוח המידע הוא הכרחי מאוד לאור כל הסיכונים שקיימים היום, היכולת לחרוץ את גורל החבילה מחוץ ל Kernel חוסך התעסקות מיותרת והופך את העסק לפשוט יותר, על הטריק הזה ניתן לבסס מוצרי רשת שונים כמו IDS,IPS,WAF ועוד.

הורדת התוכנית


מקורות



יום שישי, 22 בפברואר 2013

Proxy Server Guide



הרבה ארגונים אינם מאפשרים כניסה לאתרים מסויימים בשעות העבודה, שלא נדבר על ארגונים מאובטחים שאינם רוצים שמידע חסוי יצא החוצה, אחד הכלים שמאפשרים לנו לנתח תעבורה הם Proxies שמהווים נקודת מעבר למידע שעובר ברשת, לדוגמה ארגון שמנצל את ה Proxy על מנת לעקוב אחרי אנשים בארגון, או Proxy שמזהה פרסומות בדפי אינטרנט ומוריד אותם, מסנן אתרי פורנו וכו'.



קיימים 2 סוגים של Proxies:
  • Forward Proxies - מקבל בקשות ומעביר לאינטרנט.
  • Reverse Proxies - מקבל בקשות מהאינטרנט ומעביר לשרת.
בתחום אבטחת המידע ה Proxy מנצח גם בתחום ההתקפה וגם בתחום ההגנה, בעזרת Proxy ניתן לטשטש את העקבות בכך שנסתיר את הכתובת שלנו בעזרת הכתובת של ה Proxy (ראה Anonymous Proxy) ,  אבל גם מאפשר לנו לעקוב אחרי הבקשות ולסנן בקשות זדוניות כמו Sql Injection / Cross Side Scripting.

יאללה לקוד!

שימו לב! התוכנית עובדת על Sockets בלבד ולא תומכת ב  (Secure Socket Layer (SSL.

נקודת המוצא עבור התוכנית שהיא צריכה קודם כל להאזין לאיזה Port בעזרת אובייקט מסוג TcpListener השלב הבא הוא לתפוס את החבילה לנתח ולהעביר אותה ליעד, אומנם זה נשמע פשוט אבל כמו תמיד העסק נהפך למסובך יותר כאשר מספר חבילות מגיעות ביחד לדוגמה דף אינטרנט יכול להכיל בתוכו מספר קישורים משרתים שונים שזמני התגובה שלהם שונים לכן עלינו לייצר מחסנית שתכיל בתוכה את כל החיבורים ותנהל אותם וכמובן לעטוף כל חיבור עם Thread על מנת שנוכל לעבוד במקביל.

ProxyHandler.cs

המחלקה שמנהלת את החיבור של המשתמש לשרת המבוקש, בתוכה יש Socket שמייצג את המשתמש ו Thread שמריץ את הפונקציה ()handle שמעבירה את הבקשה לשרת ומהשרת למשתמש, זו הפונקציה החשובה ביותר ובתוכה ניתן לערוך את הבקשות והתגובות מהשרתים והמשתמשים ולממש את הסוג הרצוי של ה Proxy, קיימות פונקציות נוספות במחלקה שתומכות בתהליך ועורכות את הבקשות.

במקרה שלנו ה Proxy מעביר בקשות ממשתמשים לשרתי אינטרנט ב Port 80, משנה את הבקשות המקוריות לבקשות של ה Proxy ומחזיר את התשובות למשתמשים.


//**** Proxytype.blogspot.com ****

using System;
using System.Text;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Collections;
using System.Net;

namespace Proxy
{
    public enum TaskStaus
    {
        STANDBY,
        ACTIVE,
        DONE
    }

    public class ProxyHandler
    {
       
        public TaskStaus _taskStatus = new TaskStaus();
        Thread _thread;
        Socket _socket;

        public ProxyHandler(Socket socket)
        {
            _socket = socket;
        }

        public void run()
        {
           _taskStatus = TaskStaus.ACTIVE;

           _thread = new Thread(new ThreadStart(handle));
           _thread.Start();
        }

        public void handle()
        {

            try
            {

                //set request buffer as the size of the socket buffer
                byte[] _clientRequestBuffer = new byte[_socket.ReceiveBufferSize];
                if (_socket.Receive(_clientRequestBuffer, 0, _clientRequestBuffer.Length, SocketFlags.None) != 0)
                {
                    string request = Encoding.ASCII.GetString(_clientRequestBuffer);

                    //start spliting the request to rows
                    string[] _lineArray = split_packet(request);

                    //checking if splitting success
                    if (_lineArray.Length == 0)
                    {
                        _taskStatus = TaskStaus.DONE;
                        _socket.Close();
                        return;
                    }

                    //geting host from first request line
                    string hosturl = get_hostname(_lineArray[0]);
                    //geting the requsted page
                    string page = get_page(_lineArray[0], hosturl);

                    //drop ssl
                    if (hosturl.Contains("443"))
                    {
                        _taskStatus = TaskStaus.DONE;
                        _socket.Close();
                        return;
                    }

                    //replace original page with edit page by proxy
                    _lineArray[0] = page;
                    request = rebuild_pkt(_lineArray);

                    //using DNS to get the ip of the host
                    IPHostEntry IPHost = Dns.GetHostEntry(hosturl);

                    //create the remote socket for the proxy connect with.
                    Socket remote_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                    //make the connection on port 80
                    remote_socket.Connect(IPHost.AddressList[0], 80);

                    //sending the request
                    remote_socket.Send(ASCIIEncoding.ASCII.GetBytes(request));
                 
                    Console.WriteLine("SENDING REQUEST FROM:" + _socket.LocalEndPoint.ToString()+ " -TO-> " + ":" + hosturl);

                    //set response buffer as the size of the socket buffer
                    byte[] response = new byte[remote_socket.ReceiveBufferSize];

                    int bytesReceived = 1;

                    //check if connection is still alive after sending request
                    if (!remote_socket.Connected)
                    {
                        remote_socket.Close();
                       _socket.Close();
                        _taskStatus = TaskStaus.DONE;
                        return;
                    }

                    //set timeout for socket release socket faster
                    remote_socket.ReceiveTimeout = 2000;
                    _socket.SendTimeout = 2000;

                    //getting the first buffer of the response from the remote
                    bytesReceived = remote_socket.Receive(response, 0, response.Length, SocketFlags.None);

                    //running until end of response
                    while (bytesReceived > 0)
                    {
                        //release CPU time
                        Thread.Sleep(10);
                       
                        //sending packets from remote to the client
                        _socket.Send(response, bytesReceived, SocketFlags.None);
                       
                        //release CPU time
                        Thread.Sleep(10);

                        //reload the next buffer of the response
                        bytesReceived =remote_socket.Receive(response);

                        //release CPU time
                        Thread.Sleep(10);

                        Console.WriteLine("SENDING RESPONSE FROM:" + hosturl + " --TO--> " + _socket.RemoteEndPoint.ToString());
                       
                    }

                    //close response socket
                    remote_socket.Close();

                }

                //close the client socket
               _socket.Close();

                Thread.Sleep(100);

            }
            catch (Exception ex)
            {

                //close request socket
                _socket.Close();
            }
            finally
            {
                _socket.Close();
                _taskStatus = TaskStaus.DONE;
            }
      
        }


        /// <summary>
        /// return the host name from request
        /// removing unnecessary chars
        /// </summary>
        /// <param name="pkt_line">the first row in the request</param>
        /// <returns>host address</returns>
        private static string get_hostname(string pkt_line)
        {
            return pkt_line.Split(' ')[1].Replace("http://", "").Split('/')[0];
        }

        /// <summary>
        /// return the requested page from request
        /// fixing row as packet send from proxy
        /// remove the original hostname.
        /// </summary>
        /// <param name="pkt_line"></param>
        /// <param name="hostname"></param>
        /// <returns></returns>
        private string get_page(string pkt_line, string hostname)
        {
            return pkt_line.Replace("http://", "").Replace(hostname, "");
        }

        /// <summary>
        /// rebuild new request 
        /// </summary>
        /// <param name="_lines">edited request lines array</param>
        /// <returns>complete request string</returns>
        private static string rebuild_pkt(string[] _lines)
        {
            string _pkt = "";
            for (int i = 0; i < _lines.Length; i++)
            { _pkt = _pkt + _lines[i];}
            
            return _pkt;    
        }

       
        /// <summary>
        /// split the request to lines array
        /// </summary>
        /// <param name="pkt">complete request string</param>
        /// <returns>array of lines</returns>
        private string[] split_packet(string pkt)
        {
            string endLine = "\r\n";
            ArrayList _list = new ArrayList();

            string _line = "";
            for (int i = 0; i < pkt.Length; i++)
            {
                _line = _line + pkt[i];
                if (_line.EndsWith(endLine))
                {
                    _list.Add(_line);
                    _line = "";
                }
            }

            return (String[])_list.ToArray(typeof(string));
        }

        /// <summary>
        /// optinal write to log
        /// </summary>
        /// <param name="message">message to write</param>
        private  void writelog(string message)
        {
            FileStream _file = new FileStream(Environment.CurrentDirectory + "\\log.txt", FileMode.Append, FileAccess.Write);
            StreamWriter _writer = new StreamWriter(_file);
            _writer.WriteLine(message + "\n\r");
            _writer.Close();
            _file.Close();
            _writer.Dispose();
            _file.Dispose();

        }

    }
}

Program.cs

פונקציית Main מפעילה TcpListener של ה Proxy על פורט מסויים, ונכנסת ללואה אין סופית שה TcpListener מתחיל למלאות חיבורים במערך, לאחר מכן מופעלת הפונקציה ClearStack שמפעילה חיבורים ומנקה חיבורים שהושלמו.

using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.IO;
using System.Collections;
using System.Net;
using System.Threading;

namespace Proxy
{
    class Program
    {
     
        static TcpListener _listener;
        static ArrayList _arr = new ArrayList();

        static void Main(string[] args)
        {
            //set the proxy port
            _listener = new TcpListener(IPAddress.Any, 8666);
            _listener.Start();

            //infinity loop
            while (true)
            {
                if (!_listener.Pending())
                {
                    clearStack();
                    continue;
                }
             
                Socket D = _listener.AcceptSocket();
                ProxyHandler _handler = new ProxyHandler(D);
                _arr.Add(_handler);
            }

        }

     

        /// <summary>
        /// stack of socket active the handle routine
        /// remove close handlers
        /// </summary>
        static void clearStack()
        {
            for (int i = _arr.Count - 1; i > 0; i--)
            {
                ProxyHandler _tmp = (ProxyHandler)_arr[i];

                switch (_tmp._taskStatus)
                {
                    case TaskStaus.STANDBY:
                       _tmp.run();
                        break;
                 
                    case TaskStaus.DONE:
                       _arr.Remove(_tmp);
                        break;
                    default:
                        break;
                }

                //release CPU time
                Thread.Sleep(10);
            }
        }

    }
}




סיכום:

אפשר להגיד ש Proxy הוא סוג של סוכן כפול לטוב ולרע והשימוש בו הוא על הגבול של חדירה לפרטיות מצד שני הוא מאפשר לשמור על תכנים ולסנן בקשות חשודות לכן השימוש בו משתנה מצורך לצורך, אבל מדובר באחד הכלים החשובים בעולם הרשתות.

תשתמשו בו בחוכמה!

יום שבת, 26 בינואר 2013

Arduino Ethernet HoneyPot



ראינו איך ניתן לתקשר עם ה Arduino בצורה סיראלית וכמו שהבטחתי הגיע הזמן לשלב תקשורות נוספות, בסדרת המאמרים הקרובה נתמקד בתקשורות שונות בסביבת Arduino, התקשורת הראשונה שפותחת את הסדרה היא איך לא Ethernet , בעזרת ה Ethernet Shield ניתן לשלב את ה Arduino בכל רשת מבוססת LAN, ולבצע מגוון משימות כמו WebServer , DHCP וכדומה.

דרישות:
  • Arduino Uno
  • Ethernet Shield


Ethernet Shield


את שלי מצאתי באינטרנט במחיר של 20 דולר עם כניסת Micro SD וצ'יפ של Wizent, כל IDE של Arduino מגיע עם ספריית Ethernet עם המון דוגמאות שמתאימות ל Shield שרכשתי, אני לא אתמקד בדוגמאות הבסיסיות (יש מספיק) אלא במשהו קצת יותר מורכב שאפשר לנו להפוך את ה Arduino לכלי אבטחת מידע.

HoneyPot

אחד מהכלים המעניינים באבטחת מידע, נקודה ברשת שבעצם "מלכודת" שנועדה להתריע לנו כאשר מתבצעת תנועה לא לגיטימית ברשת, זו נקודה שאף אחד לא צריך להגיע אליה אבל במקרה שמגיעים נדע זאת מיד ,פה העסק נהפך למסובך, ספריית ה Ethernet שמגיעה עם ה IDE לא חושפת את כתובת ה Client כלומר נדע שנכנסו ל HoneyPot אבל לא נדע מי (כתובת IP) ולכן עלינו לחשוף אותה בעצמנו, כל הספריות החיצוניות של Arduino כתובות ב C++ ובעצם עושות את כל הקסם מאחורי הקלעים, מרבית ה Shields נעזרים בספריות שמגיעות עם ה IDE אבל לפעמים יש להוריד ספריות ייעדיות.

חשוב מאוד! - לגבות את תיקיית ה Ethernet בתיקיית Libraries בתיקיית השורש ב IDE שלכם.

יש לערוך את הקובץ Client.cpp בתיקיית ה Ethernet ולהוסיף את הפונקציה בסוף הקובץ:

uint8_t * Client::getip(uint8_t dstip[])
{
W5100.readSnDIPR(_sock, dstip);
return dstip;
}

יש לערוך את הקובץ Client.h ולהוסיף את החתימה של הפונקציה:

  uint8_t * getip(uint8_t dstip[]);


אחרי שעדכנו הספרייה נעבור לקוד ב Arduino, התוכנית מבוססת על הדוגמה של ה Web Server שמגיעה עם ה IDE , הרעיון מאוד פשוט, נאזין לפורט 80 וכאשר שמשהו יגיע נעביר הודעה בעזרת החיבור הסיראלי למנהל המערכת ובמקביל נציג דף אזהרה למי שנפל למלכודת.

קוד:


/*
  Web  Server

 A simple web server that shows the value of the analog input pins.
 using an Arduino Wiznet Ethernet shield. 

 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 * Analog inputs attached to pins A0 through A5 (optional)

 created 18 Dec 2009
 by David A. Mellis
 modified 4 Sep 2010
 by Tom Igoe

 */


#include <Client.h>
#include <Ethernet.h>
#include <Server.h>
#include <Udp.h>

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192,168,1, 177 };

// Initialize the Ethernet server library
// with the IP address and port you want to use 
// (port 80 is default for HTTP):
Server server(80);

void setup()
{
  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.begin(9600);
}

void loop()
{
  // listen for incoming clients
  Client client = server.available();
  if (client) {
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
         
         //create byte array for dstip
         byte dstip[] = {0,0,0,0 };
         //getting the ip from the upgraded library
         client.getip(dstip);
          
          client.print("<body style='background-color:black'>");
          client.print("<div style='color:red; font-family:arial;font-size:24px; font-weghit:bold'>Warning</div>");
         client.print("<div style='color:white'><b>");
         client.print(dstip[0],DEC);
         client.print(".");
         client.print(dstip[1],DEC);
         client.print(".");
         client.print(dstip[2],DEC);
         client.print(".");
         client.print(dstip[3],DEC);
         client.print("</b>");
         client.print(" You are not supposed to be in this parts of the network,  message send to the administrator");
         client.print("</div>");
         client.print("<br />");
         client.print("<div style='font-size:24px;color:#007eff'>DuinoPot v.1</div>");
         client.print("<div style='font-size:12px;color:white'>proxytype.blogspot.com</div>");
         client.print("</ body>");
         
         //send serial message to administrator
        Serial.print("CONNECTION FROM --> ");
        Serial.print(dstip[0],DEC);
        Serial.print(".");
        Serial.print(dstip[1],DEC);
        Serial.print(".");
        Serial.print(dstip[2],DEC);
        Serial.print(".");
        Serial.print(dstip[3],DEC);
        Serial.print("\n");
        
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } 
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
  }
}




אז כמו שאמרתי כאשר משהו נופל לפח מוצג לו הדף הבא:


במקביל נשלחת הודעה סיראלית למנהל המערכת, ניתן לשמור את המידע על הגבי ה Micro SD אבל נשאיר את זה לפעם אחרת.




סיכום:

עבודה עם תקשורת Ethernet מאפשרת להרחיב את הפרוייקטים לתחומים רחבים יותר כמו האינטרנט, ובעצם להוציא את ה Arduino לעולם הגדול.