Coding a SYN Scanner guide ( source included )
ithilgore
advent.cloud.strife at gmail.com
Fri Mar 30 00:58:11 EEST 2007
Giorgos Keramidas wrote:
> On 2007-03-29 05:13, - <advent.cloud.strife at gmail.com> wrote:
>
>> V13 wrote:
>>
>>> Epeisis, to na xrisimopoieis etsi ta structs mallon problimata tha
>>> soy dimioyrgisei logo alignment kai reordering. Des to
>>> __attribute__((packed)) toy gcc. P.x. gia to IP:
>>>
>>> ----
>>> struct pseudo_hdr {
>>> u_int32_t src; /* 32bit source ip address*/
>>> u_int32_t dst; /* 32bit destination ip address */
>>> u_char mbz; /* 8 reserved bits (all 0) */
>>> u_char proto; /* protocol field of ip header */
>>> u_int16_t len; /* tcp length (both header and data */
>>> } __attribute__((packed));
>>> ----
>>>
>>> Des tin eksodo apo to parakato programma:
>>> ----
>>> #include <stdio.h>
>>>
>>> struct A { int a; char b; int c;};
>>>
>>> struct B { int a; char b; int c; } __attribute__((packed));
>>>
>>> int main()
>>> {
>>> printf("%d\n%d\n", sizeof(struct A), sizeof(struct B));
>>> }
>>> ----
>>>
>>> v13 at hell:/tmp$ ./a
>>> 12
>>> 9
>>>
>>> Opos blepeis, logo alignment, to proto struct epiase 12 bytes giati
>>> to c egine align sta 32bit (4 byte), opote kai to c ksekinoyse apo to
>>> +2*4. Ayto mporeis na to deis kanontas compile me to -Wpadded:
>>>
>> thanx ! tetoiou eidous feedback perimenw.
>> implicit reordering mias struct den nomizw na ginetai kai sumfwna me
>> to C standard upo kanonikes sun8hkes den 8a prepei na ginetai
>>
>
> Σωστός.
>
>
>> Twra gia to packing ston sugekrimeno kwdika mono gia ka8ara
>> optimization skopus ( < size ) tha eixe isws nohma.
>>
>
> Αυτό όμως είναι λίγο λάθος. Έχει δίκιο ο Στέφανος (V13). Αν κάνεις
> malloc() 12 bytes για ένα object τύπου "struct A", μπορεί ο memory
> allocator να σου επιστρέψει τα παρακάτω bytes:
>
> A5 A5 A5 A5 A5 A5 A5 A5 A5 A5 A5 A5
> ___________ __ ___________
> a b c
>
> Αν εσύ διαβάσεις από 'raw data' ένα πακέτο που έχει τιμές:
>
> a = 0x12345678 (4 bytes)
> b = 0xCC (1 byte)
> c = 0x23456789 (4 bytes)
>
> χρησιμοποιώντας απλά read() για όλο το struct κι όχι read() για κάθε
> member ξεχωριστά, μπορεί να προσπαθήσεις να διαβάσεις περισσότερα bytes
> από ότι είναι διαθέσιμα στο packet stream.
>
> Αν από την άλλη, για κάποιο λόγο όντως προσπαθήσεις να διαβάσεις 9
> bytes, τα δεδομένα θα γραφτούν σε ένα struct A με τη μορφή:
>
> 12 34 56 78 CC 23 45 67 89 A5 A5 A5
> ___________ __ ___________
> a b c
>
> και δεν θα είναι πολύ σωστές οι τιμές των struct members.
>
>
>> To pseudo header allwste xrhsimopoieitai mono sto checksuming kai me ena
>> sizeof upologizetai pada swsta to mege8os.
>>
>
> Δηλαδή, ακριβώς λόγω των "padding bytes" μπορεί να κάνεις checksum σε
> λάθος δεδομένα (επειδή π.χ. δεν έκανες memset() σε μηδέν όλα τα bytes
> πριν από *κάθε* read() call).
>
> Δεν είναι πιο εύκολο να χρησιμοποιήσεις "packed structures"; :-
>
>
Καλη παρατηρηση γενικα και απο τους 2. Καταλαβα τι εννοειτε αλλα στον
συγκεκριμενο κωδικα συμβαινουν τα εξης:
α) Το pseudo header χρησιμοποιειται **μονο** για το datagram που
στελνουμε και **μονο** για τον υπολογισμο του
checksum : με αλλα λογια δεν χρησιμοποιειται πουθενα σε συνδυασμο με την
read( )
Να θυμισω λιγο τον κωδικα :
/* pseudo header for tcp checksum */
struct pseudo_hdr *phdr = (struct pseudo_hdr *) ( datagram +
sizeof(struct sniff_ip) + sizeof(struct
sniff_tcp) ) ;
phdr->src = iph->ip_src.s_addr;
phdr->dst = iph->ip_dst.s_addr;
phdr->mbz = 0;
phdr->proto = IPPROTO_TCP;
phdr->len = ntohs (0x14); /* in bytes the tcp segment
length */
/*- WhyTF is it network
byte saved by default ????*/
tcph->th_sum = htons ( checksum_comp ( (unsigned short *) tcph ,
sizeof(struct pseudo_hdr)+sizeof(struct sniff_tcp)));
.....
if (sendto (sockfd ,datagram, iph->ip_len , 0, (struct sockaddr
*) &sin, sizeof (sin)) < 0) {
fprintf ( stdout , "Error sending datagram for port %d\n",i);
break;
}
Επισης το ωραιο με αυτη τη struct ειναι οτι ειναι 12 (4+4+4(2+1+1))σε
μεγεθος. Παραθετω output του gdb :
80 /* pseudo header for tcp checksum */
81 struct pseudo_hdr *phdr = (struct pseudo_hdr *)
( datagram +
82 sizeof(struct sniff_ip) +
sizeof(struct sniff_tcp) ) ;
83 phdr->src = iph->ip_src.s_addr;
84 phdr->dst = iph->ip_dst.s_addr;
85 phdr->mbz = 0;
86 phdr->proto = IPPROTO_TCP;
87 phdr->len = ntohs (0x14); /* in bytes the
tcp segment length */
(gdb) list
88 /*- WhyTF is it
network byte saved by default ????*/
89
90
91 tcph->th_sum = htons ( checksum_comp ( (unsigned
short *) tcph ,
92 sizeof(struct
pseudo_hdr)+sizeof(struct sniff_tcp)));
93
94
95 //printf ( "sizeof: %d \n" , sizeof(struct
pseudo_hdr) ) ;
96 //printf ( "sizeof: %d \n" , sizeof( *(phdr) ) ) ;
97
(gdb) b 89
Breakpoint 1 at 0x8049d1c: file syn_scanning.c, line 89.
(gdb) run -h 10.0.0.2 -S
Starting program: /home/ithilgore/linux_programming/port_scan/creeper -h
10.0.0.2 -S
filter exp: src host 10.0.0.2
Local IP: 10.0.0.4
Initiating Syn Scanning against 10.0.0.2 [1024 ports]
Breakpoint 1, Syn_Scanning () at syn_scanning.c:91
91 tcph->th_sum = htons ( checksum_comp ( (unsigned
short *) tcph ,
(gdb) print phdr
$1 = (struct pseudo_hdr *) 0xbfffe378
(gdb) x /20x 0xbfffe378
0xbfffe378: 0x0400000a 0x0200000a 0x14000600 0x00000000
0xbfffe388: 0x00000000 0x00000000 0x00000000 0x00000000
0xbfffe398: 0x00000000 0x00000000 0x00000000 0x00000000
0xbfffe3a8: 0x00000000 0x00000000 0x00000000 0x00000000
0xbfffe3b8: 0x00000000 0x00000000 0x00000000 0x00000000
(gdb)
Μας αφορουν οι 0xbfffe378: 0x0400000a 0x0200000a 0x14000600
πχ εδω source ip = 10.0.0.4 dest ip = 10.0.0.2 , reserved bits =
00 , ipproto =06 , header length = 1400
αλλα οτι και να ηταν απο τη στιγμη που ΔΕΝ κανουμε read δεν μας απασχολει.
β ) Επισης το επομενο σημειο ειναι τα headers που διαβαζουμε. Εκει δεν
υπαρχει περιπτωση να διαβασουμε κατι παραπανω
καθως το ιδιο το *reading* το κανει η pcap με την dispatch οπου διαβαζει
*πακετα* οχι απλα ενα καθορισμενο αριθμο bytes
Οποτε σε αυτη την περιπτωση ειναι λιγο δυσκολο να βγουμε εκτος οριων.
c) Τελος στο διαβασμα απο μας του πακετου ( στην got_packet ) , κανουμε
access στο ιδιο το member της tcp struct ( tcp->th_flags ) .
Θα πει κανεις ομως αν δεν ειναι packed τοτε πως ξερεις οτι εχει σωστη
τιμη αυτο ? Αυτο με παρακινησατε (και καλα κανατε) να το δω
παλι στον gdb ) οπου ειχα την εξης εξοδο:
Breakpoint 2, got_packet (args=0x5 <Address 0x5 out of bounds>,
header=0xbfffe240,
packet=0x806a7d2 "") at packet_analysis.c:37
37 if ( ( (tcp->th_flags & 0x02) == TH_SYN) && (
tcp->th_flags & 0x10 ) == TH_ACK ) {
(gdb) print ip
$2 = (const struct sniff_ip *) 0x806a7e0
(gdb) print tcp
$3 = (const struct sniff_tcp *) 0x806a7f4
(gdb) x /20x 0x806a7f4
0x806a7f4: 0xd2040100 0x00000000 0x6c8b4567 0x00001450
0x806a804: 0x000046a4 0x00000000 0x65640000 0x67726f03
0x806a814: 0x00010000 0x000cc001 0x00010001 0x00e7c400
0x806a824: 0x1b463e04 0x0010c076 0x00010002 0x00e7c400
0x806a834: 0x736e0306 0xc010c032 0x00020010 0xc4000001
κοιταξτε την πρωτη γραμμη:
0x806a7f4: 0xd2040100 0x00000000 0x6c8b4567 0x00001450
Αν συνεβαινε αυτο που λετε , τοτε το ACK sequence θα πρεπε να ηταν σε
μια μη packed struct 0x00
και ομως ειναι 0x00000000
πραγμα απολυτως φυσιολογικο και καθωσπρεπει , αφου το ACK sequence ειναι
32 bit .
Συνεπως ακομα και χωρις packed structs ο gcc και η libpcap που διαβασε
στο data link layer μαλλον προνοησαν σωστα.
Αλλα θα μπορουσε να σκεφτει κανεις και το αλλο: Κοιταξτε τα
<netinet/ip.h> και γενικα τα επισημα headers.
Δεν τα εχει πουθενα ως packed. Αυτο που λεω ειναι οτι θα μπορουσε να
ειναι default συμπεριφορα ως attribute αλλα απο'τι
φαινεται δεν χρειαζεται στις περιπτωσεις αυτες.
Αυτα απο μενα. Καλη συζητηση παντως.
ithilgore
More information about the unix-admin-gr
mailing list