Skip to content

Instantly share code, notes, and snippets.

@Elijah-Bodden
Created December 12, 2023 02:25
Show Gist options
  • Save Elijah-Bodden/88416ba6671bae09a467b10ab208499c to your computer and use it in GitHub Desktop.
Save Elijah-Bodden/88416ba6671bae09a467b10ab208499c to your computer and use it in GitHub Desktop.
Web POST/GET http server written in intel x86 asm (pwn.college webserver course final solution)
.intel_syntax noprefix
.globl _start
.section .text
_start:
# Open socket
mov rdi, 2
mov rsi, 1
mov rdx, 0
mov rax, 41
syscall
# Store socket fd in rbx
mov rbx, rax
# Bind socket to address
mov rdi, rbx
lea rsi, sa_family_t
mov rdx, 16
mov rax, 49
syscall
# Listen on socket
mov rdi, rbx
mov rsi, 0
mov rax, 50
syscall
accept_jump:
# Accept a connection
mov rdi, rbx
mov rsi, 0
mov rdx, 0
mov rax, 43
syscall
# Save new fd for bound connection in r12
mov r12, rax
# Fork the process and let the child do the serving
mov rax, 57
syscall
cmp rax, 0
je serve_connection
# Close the connection if parent
mov rdi, r12
mov rax, 3
syscall
# Then go back to listening
jmp accept_jump
serve_connection:
# Close listening socket
mov rdi, rbx
mov rax, 3
syscall
# Read from the connection
mov rdi, r12
lea rsi, read_buffer
mov rdx, [read_packet_length]
mov rax, 0
syscall
# Figure out what file was requested
lea rdi, read_buffer
mov rsi, 1
lea rdx, space
call get_nth_substr
mov r13, rax
lea rdi, read_buffer
mov rsi, 2
call get_nth_substr
mov r14, rax
sub r14, 1
# r13 = start (exclusive), r14 = end (inclusive)
mov rdi, r13
mov rsi, r14
lea rdx, file_name_buffer
call write_to_buf
# Filename is now stored in file_name_buffer
# Check request type
mov dil, [read_buffer]
# Compare to "G"
cmp dil, 0x47
# Continue (GET process) if G, otherwise do POST
jne POST
GET:
# Open that file
lea rdi, file_name_buffer
mov rsi, 0
mov rdx, 0
mov rax, 2
syscall
mov r13, rax
# Read file contents
mov rdi, r13
lea rsi, file_read_buffer
mov rdx, 1024
mov rax, 0
syscall
# Close the file
mov rdi, r13
mov rax, 3
syscall
# Write status to connection
mov rdi, r12
lea rsi, write_static
mov rdx, 19
mov rax, 1
syscall
# Write file contents to connection
lea rdi, file_read_buffer
call get_len
mov rdx, rax
sub rdx, 1
mov rdi, r12
lea rsi, file_read_buffer
mov rax, 1
syscall
jmp exit
POST:
# Open that file
lea rdi, file_name_buffer
mov rsi, 0x41 # O_CREAT, O_WRONLY
mov rdx, 0777
mov rax, 2
syscall
mov r13, rax
# Get the POST content
lea rdi, read_buffer
mov rsi, 1
lea rdx, double_cr_lf
call get_nth_substr
mov rsi, rax
add rsi, 1
# Get write length
mov rdi, rsi
call get_len
mov rdx, rax
# Get rid of the pesky null byte
sub rdx, 1
# Write to file
mov rdi, r13
mov rax, 1
syscall
# Close the file
mov rdi, r13
mov rax, 3
syscall
# Write status to connection
mov rdi, r12
lea rsi, write_static
mov rdx, 19
mov rax, 1
syscall
exit:
# Close the connection
mov rdi, r12
mov rax, 3
syscall
# Sys exit
mov rdi, 0
mov rax, 60
syscall
# Get the length of a null-terminated string (including the first null byte)
# Args:
# rdi - buffer we're checking the length of
# rax - length
get_len:
mov rax, 0
get_len_loop:
# See if rdi + rax-th byte is null
mov r10, rdi
add r10, rax
mov r10, [r10]
add rax, 1
cmp r10, 0x00
jne get_len_loop
ret
# Copy the bytes spanning rdi to rsi to the buffer rdx
# rdx MUST BE LONGER THAN rsi - rdi BYTES, rdi MUST BE LESS THAN rsi
# Args:
# rdi - start (exclusive) of the string we're copying
# rsi - end (inclusive) of the string we're copying
# rdx - buffer we're copying to
# rax - unchanged
write_to_buf:
write_to_buf_loop:
add rdi, 1
mov r9, [rdi]
mov [rdx], r9
add rdx, 1
cmp rdi, rsi
jne write_to_buf_loop
mov byte ptr [rdx], 0x00
ret
# Get address of the (last byte of) the nth occurence of substring in string (occurences must be non-overlapping)
# ONLY GUARANTEED TO WORK ON NULL-TERMINATED STRINGS
# Args:
# rdi - target string address
# rsi - n
# rdx - substring
# rax - address of nth character
get_nth_substr:
# Set rcx (ocurrence counter)
mov rcx, 0
# Set r10 (to traverse substring)
mov r10, rdx
check_character_loop:
# r9b = character at position
mov r9b, [rdi]
# If string's terminated, obviously the substring doesn't occur enough times
cmp r9b, 0x00
je not_enough_occurrences
# Step through substring iff r9b = current byte
cmp r9b, byte ptr [r10]
jne character_not_equal
add r10, 1
# If we've reached the end of the substring, increment counter and reset r10
cmp byte ptr [r10], 0x00
jne after_comparison
mov r10, rdx
add rcx, 1
jmp after_comparison
character_not_equal:
# Reset r10 without adding to count
mov r10, rdx
after_comparison:
# Return address if we've got the nth ocurrence
cmp rcx, rsi
je match
# Otherwise increment and continue
add rdi, 1
jmp check_character_loop
match:
mov rax, rdi
ret
not_enough_occurrences:
mov rax, -1
ret
.section .data
# sockaddr_in struct
sa_family_t: .word 2
bind_port: .word 0x5000
bind_address: .double 0x00000000
pad: .byte 0,0,0,0,0,0,0,0
# Make empty buffers to read to
read_buffer: .space 1024
file_name_buffer: .space 1024
file_read_buffer: .space 1024
# Constants
# Yes it's dumb to use a quad word for this, but it simplifies copying it to the register
read_packet_length: .quad 0x0000000000000400
write_static: .string "HTTP/1.0 200 OK\r\n\r\n"
space: .string " "
double_cr_lf: .string "\r\n\r\n"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment