Created
December 12, 2023 02:25
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.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