Skip to content

Commit

Permalink
Add my pwn.college web server notes
Browse files Browse the repository at this point in the history
  • Loading branch information
rprouse committed May 17, 2024
1 parent d012998 commit e23fe19
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 0 deletions.
10 changes: 10 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,13 @@ indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.py]
indent_size = 4

[*.{s,asm}]
indent_size = 4

[Makefile]
indent_style = tab
indent_size = 4
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Linux object files
*.o

4 changes: 4 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ This repo has a folder icon set in `desktop.ini`. To enable it, you must set the
- [Format the oneline output](./git/format-output.md)
- [Git Shallow Clone](./git/shallow-clone.md)

### 👨‍💻 Hacking / Cybersecurity

- [pwn.college](./pwn.college/Readme.md) notes and code from working through the course.

### 🐧 Linux

- [Switch to Virtual Consoles (TTYs)](./linux/switch-tty.md)
Expand Down
11 changes: 11 additions & 0 deletions pwn.college/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# pwn.college

Learning to hack!

[pwn.college](https://pwn.college/) is an education platform by the University of Arizona for students (and other interested parties) to learn about, and practice, core cybersecurity concepts in a hands-on fashion. In martial arts terms, it is designed to take a “white belt” in cybersecurity to becoming a “blue belt”, able to approach (simple) cybersecurity competitions (CTFs) and wargames. Our philosophy is “practice makes perfect”.

![Wax on, wax off](https://media4.giphy.com/media/J2xkAW1E8kvyE/giphy-downsized-medium.gif)

## Intro to Cybersecurity

- [Building a Web Server](./webserver/Readme.md)
12 changes: 12 additions & 0 deletions pwn.college/webserver/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.DEFAULT_GOAL := default

default: run

run: server
/challenge/run ./server

server: server.o
ld -o server server.o

server.o: server.s
as -o server.o server.s
17 changes: 17 additions & 0 deletions pwn.college/webserver/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Building a Web Server

## Intro to Cybersecurity

Develop the skills needed to build a web server from scratch, starting with a simple program and progressing to handling multiple HTTP GET and POST requests. The server is written in assembly using the [GNU Assembler](https://sourceware.org/binutils/docs/as/) using Intel Syntax.

## Code

- [Makefile](./Makefile)
- [server.s](./server.s)

## Useful links

- pwn.college [Building a Web Server](https://pwn.college/intro-to-cybersecurity/building-a-web-server/) module
- [x86 and amd64 instruction reference](https://www.felixcloutier.com/x86/)
- [x64 syscalls](https://x64.syscall.sh/)
- [x86 Assembly](https://en.wikibooks.org/wiki/X86_Assembly) wikibook
189 changes: 189 additions & 0 deletions pwn.college/webserver/server.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
.intel_syntax noprefix
.globl _start

.section .text

_start:
# Open then network socket
# int socket(int domain, int type, int protocol)
mov rdi, 2 # AF_INET
mov rsi, 1 # SOCK_STREAM
mov rdx, 0 # IPPROTO_IP
mov rax, 0x29
syscall
mov [sockfd], rax # Save the return value

# Bind the socket to the address
# int bind(int sockfd, struct sockaddr *addr, socklen_t addrlen)
mov rdi, [sockfd] # Return value from socket()
lea rsi, [rip+sockaddr_in]
mov rdx, 16
mov rax, 0x31
syscall

# Listen on the socket
# int listen(int sockfd, int backlog)
mov rdi, [sockfd]
mov rsi, 0
mov rax, 0x32
syscall

accept:
# Accept a connection
# int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
mov rdi, [sockfd]
mov rsi, 0
mov rdx, 0
mov rax, 0x2B
syscall
mov [reqfd], rax

# Fork a child process to handle the request
# int fork()
mov rax, 0x39
syscall

# If we are the child process, continue processing the request
cmp rax, 0
je process_request

# If we are the parent process, loop back to accept the next connection
# Close the socket and go back to accept
mov rdi, [reqfd]
mov rax, 0x03
syscall

jmp accept

process_request:
# Close the socket in the child process
mov rdi, [sockfd]
mov rax, 0x03
syscall

# Read the request
# ssize_t read(int fd, void *buf, size_t count)
mov rdi, [reqfd]
lea rsi, buff
mov rdx, buff_end-buff-1
mov rax, 0x00
syscall

# Parse out the requested filename from the request
lea rdi, [rip+buff] # Load the address of the request string buffer
call find_space # Call the find_space function
mov rsi, rdi # Save the address of the filename
call find_space # Call the find_space function again to find the end of the filename

# Open the requested file
# int open(const char *pathname, int flags, mode_t mode)
mov rdi, rsi # Filename
mov rsi, 0 # O_RDONLY
mov rdx, 0 # No mode
mov rax, 0x02
syscall
mov [filefd], rax

# Read the file into a buffer
mov rdi, [filefd]
lea rsi, file_buff
mov rdx, file_buff_end-file_buff-1
mov rax, 0x00
syscall
mov [file_len], rax # Save the return value, bytes read

# Close the file
mov rdi, [filefd]
mov rax, 0x03
syscall

# Write the response header to the socket
# ssize_t write(int fd, const void *buf, size_t count);
mov rdi, [reqfd]
lea rsi, response
mov rdx, response_end-response-1
mov rax, 0x01
syscall

# Write the file buffer to the socket
mov rdi, [reqfd]
lea rsi, file_buff
mov rdx, [file_len]
mov rax, 0x01
syscall

# Close the socket
# int close(int fd)
mov rdi, [reqfd]
mov rax, 0x03
syscall

# Exit the program
# void exit(int error_code)
mov rdi, 0
mov rax, 0x3C
syscall

# Function to replace the first space in a string with a null byte
# Entry:
# rdi: Pointer to the string
# Exit:
# The first space in the string is replaced with a null byte
# rdi is incremented to the next character after the space
find_space:
mov al, [rdi] # Load the current character into al
cmp al, ' ' # Compare the character with space (' ')
je replace_space # If it is a space, jump to replace_space
cmp al, 0 # Compare the character with null byte ('\0')
je done # If it is null byte, we're done (no space found)
inc rdi # Move to the next character
jmp find_space # Repeat the loop

replace_space:
mov byte ptr [rdi], 0 # Replace the space with a null byte ('\0')
inc rdi # Move to the next character
done:
ret # Return to the caller

.section .data

# The socket returned from socket()
sockfd:
.8byte 00

# The file descriptor returned from accept()
reqfd:
.8byte 00

# The file descriptor for the requested file
filefd:
.8byte 00

# The file length read
file_len:
.8byte 00

# The address structure passed to bind()
sockaddr_in:
sin_family:
.2byte 02
sin_port:
.2byte 0x5000 # Port 80 big endian
sin_addr:
.4byte 0x00 # 0.0.0.0, 0x7F000001 is 127.0.0.1
pad:
.8byte 0

# Buffer for the read call
buff:
.dcb.b 2048
buff_end:

response:
.string "HTTP/1.0 200 OK\r\n\r\n"
response_end:

# Buffer for the file read and response
file_buff:
.dcb.b 2048
file_buff_end:

0 comments on commit e23fe19

Please sign in to comment.