Problem
This problem comes from pwn.college - Building a Web Server ⤴.
With your socket bound to an address, you now need to prepare it to accept incoming connections. The listen ⤴ syscall transforms your socket into a passive one that awaits client connection requests. It requires the socket’s file descriptor and a backlog parameter, which sets the maximum number of queued connections. This step is vital because without marking the socket as listening, your server wouldn’t be able to receive any connection attempts.
Solution
Goal
Running /challenge/run server (using the program compiled in bind) prints to the console
===== Expected: Parent Process =====
[ ] execve(<execve_args>) = 0
[ ] socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3
[ ] bind(3, {sa_family=AF_INET, sin_port=htons(<bind_port>), sin_addr=inet_addr("<bind_address>")}, 16) = 0
- Bind to port 80
- Bind to address 0.0.0.0
[ ] listen(3, 0) = 0
[ ] exit(0) = ?
Which, uh, doesn’t say very much. But it does appear that the listen function is quite simple, so let’s look at that.
Listen Function
The listen function has the following function definition
int listen(int sockfd, int backlog)
It is quite simple! It takes two parameters
sockfd, being the socket file descriptor that we got from calling thesocketfunction.backlog, which defines the maximum queue length for awaiting connections. Looking at the console output in the Goal section, we’ll only be handling one connection at a time for this challenge, which means0backlog.
The listen function returns an int with either a 0 on success or -1 on failure. See the listen man page ⤴ for more details.
Code
I’ve made a few changes to the code compared to the previous section
- Function calls are now labels instead of comments. It looks cleaner to me and shows the flow of the program more clearly.
sockfdis saved torbxsince we needraxfor other things.
.intel_syntax noprefix
.global _start
.section .data
sock_in: # struct sockaddr_in
.word 2 # AF_INET (IPv4)
.word 0x5000 # Port 80 in hex
.long 0 # IP address of 0.0.0.0
.byte 0 # Padding
.section .text
_start:
Socket:
mov rdi, 2 # AF_INET = 2, for IPv4
mov rsi, 1 # SOCK_STREAM = 1, for TCP
xor rdx, rdx # 0 for protocol
mov rax, 41 # socket syscall number: 41
syscall
mov rbx, rax # Save sockfd
Bind:
mov rdi, rax # Send file descriptor to sockfd
lea rsi, [sock_in] # Pointer to struct sockaddr
mov rdx, 16 # 16 bytes expected
mov rax, 49 # bind syscall number: 49
syscall
Listen:
mov rdi, rbx # Send file descriptor to sockfd
mov rsi, 0 # Expected backlog/queue length
mov rax, 50 # listen syscall number: 50
syscall
Exit:
mov rdi, 0
mov rax, 60 # exit syscall number: 60
syscall