π°οΈ Assembly Web Server
You can do the task with solving the challenge in module Building a web server in dojo Computing 101 in pwn.college. The original code is here i think.
Quick reminder: Linux syscalls return values in
rax. On success it’s non-negative. On error the kernel returns-errno(a negative value). In assembly you usually testraxand jump if negative. Think: the kernel is passive-aggressively telling you what went wrong β you must check.
π How to βunderstandβ each syscall better
- Your syscalls companion is x64.syscall.sh then use the rule number two
man 2 <SYSCALL> man 2 socket/man 2 bind/man 2 listen/man 2 acceptβ kernel API manpages; start here.
π§ Syscall patterns
In your server most syscalls are used without robust error checks. Hereβs a standard pattern to check result and branch on error (pseudo-assembly):
| |
js jumps if the result is negative (since kernel uses negative errno). Another common check:
| |
Use these around socket, bind, listen, accept, open, read, write, fork, etc.
π§© Socket creation
Assembly in your code:
| |
C equivalent (using libc wrapper):
| |
Explain some jargons:
AF_INETmeans IPv4. other options likeAF_INET6(IPv6) andAF_UNIX(local sockets).- Bluetooth would be
AF_BLUETOOTH, but thatβs a different story.
- Bluetooth would be
SOCK_STREAMmeans TCP (not UDP)protocol = 0means default protocol for TCP (which is IP). Other protocols exist, but we donβt care.
Think of it like asking the kernel: βGive me a magic telephone line to the internet.β
And the kernel hands back a file descriptor like: βHere, donβt lose it.β
You can find more at man 2 socket.
π Bind β crafting sockaddr
You already build the sockaddr_in on the stack. After syscall:
| |
C equivalent:
| |
Tip:
htons(80)andhtonl(INADDR_ANY)are used to convert to network byte order. In assembly the bytes were written as0x5000which ishtons(80)for little-endian machines β neat trick.htons(80)is just making the bytes order with least significant byte first (little-endian). Forhtonsthat work for unsigned short int (word)0x0050to be0x5000.htonl(INADDR_ANY)is0in network byte order, so writing0directly works.
For another address like127.0.0.1for the localhost, youβd write0x7F000001in little-endian withhtonl(works for unsigned int which is DWORD) as0x0100007F.
π£οΈ Listen
Assembly:
| |
The backlog argument defines the maximum length to which the queue of pending connections for sockfd may grow. If a connection request arrives when the queue is full, the client may receive an error with an indication of ECONNREFUSED or, if the underlying protocol supports retransmission, the request may be ignored so that a later reattempt at connection succeeds.
man 2 listen for details.
π€ Accept
Assembly:
| |
This waits for an incoming connection and returns a new socket fd for that client.
π¨βπ©βπ§βπ¦ Forking
Your server calls fork() per connection:
Assembly:
| |
- The Parent goes back to accept more connections.
- The Child should now handle the client request.
π Read / Parse request
Reading the request to the stack
Assembly:
| |
Parsing the path from the HTTP request
| |
Parsing the method (GET/POST)
| |
Parsing notes:
- You search for spaces to isolate method/path β ok for simple requests, but HTTP can be trickier (long headers, chunked encoding).
- For production: use a robust HTTP parser (e.g.,
http-parser,llhttp) or implement stronger stateful parsing.
π Open, write, close (file I/O)
GET flow:
open(path, O_RDONLY)read(fd, buffer, size)write(client, buffer, bytes)close(fd)
C snippet:
| |
Assembly code:
| |
POST path (your code writes uploaded body to file):
- Consider
open(path, O_CREAT|O_WRONLY|O_TRUNC, 0644)β create or truncate and set permissions. - Use
writeloop:while (left) { ssize_t w = write(...); handle partial writes }
You can read the POST part from the source code it’s similar idea but with addition to reading the body of the request it’s a tough part to implement correctly so you can enjoy understanding it urself :)
π‘οΈ Security caveats (must mention)
- You currently trust the request path directly β can be path traversal (
../etc/passwd). Always sanitize paths. - No checks on
Content-Lengthvs buffer sizes β could be abused. - No TLS β everything is plaintext.
- No limits on uploaded file size β put caps (max size) and quota.
π§ͺ Debugging & inspection tools
strace -f ./yourserverβ see syscalls and arguments. Amazing for syscall-level debugging.ltraceβ library calls.gdbβ step assembly, inspect registers.