src/config.c
)src/pki_container*.c
)src/knownhosts.c
)https://www.libssh.org/development/security-process/
Server: examples/ssh_server_fork.c
Client: examples/ssh_client.c
See tests/fuzz
https://github.com/google/oss-fuzz/tree/master/projects/libssh
Currently only the first state of the state machine after connect is fuzzed. We miss inputs (starting points) for oss-fuzz.
For this libssh would need to be extened that in src/socket.c the packets are also written to a file (client and server).
https://gitlab.com/libssh/libssh-mirror/merge_requests/59
We need a client and server similar to the fuzzer so we can create traces.
Example:
https://gitlab.com/gnutls/gnutls/blob/master/fuzz/README-adding-traces.md
Those traces should be feeded into American Fuzzy Loop so it creates variation of those inputs (needs to run for 2 days).
IRC: #libssh-pentest @ Freenode
People to talk to:
Possibly CW39 & CW40
The state machine is not implemented in a single file, but it is scattered in the code, which makes it hard to find the exact global state. It is basically a composition of various state machines.
The global state is composed by the session state (session->session_state
) and the states of the other contexts (session->socket_state
, session->dh_handshake_state
, session->auth.state
, session->global_req_state
, channel->state
, etc.).
When a state machine is started, the callbacks and an initial state are set. These callbacks usually change the session->pending_call_state
to the current operation being performed, which is expected to be called again in non-blocking sessions. Then a message is sent to the server and a reaction from the server is expected. The packets from the server are captured by the socket polling, which calls the appropriate callbacks for each message type (see packet.c
). These callbacks change the global state by changing the session state or the state of one of the other contexts.
The incoming packets are filtered (in ssh_packet_incoming_filter()
in packet.c
) by the expected global state before being processed (by ssh_packet_process()
). Although not complete, it is possible to see the majority of the expected transitions made by the callbacks, documented in comments. In the beginning of the packet.c
file, it is possible to see the default callbacks called for each message type.
If the session is non-blocking, it is expected the API to be called many times, while the return is SSH_AGAIN
. If the session is blocking, the call will block in a loop.
For example to connect to a host as a client:
ssh_connect()
, which sets the callback as ssh_client_connection_callback
, the session state to SSH_SESSION_STATE_CONNECTING
, and pending_call_state to PENDING_CALL_CONNECT
ssh_handle_packets()
, which will poll the socket and call the appropriate callbacks for each packet arrivingSSH_SESSION_STATE_SOCKET_CONNECTED
when the socket connection is stablishedcallback_receive_banner()
setting the state to SSH_SESSION_BANNER_RECEIVED
SSH_SESSION_STATE_INITIAL_KEX
SSH_SESSION_STATE_KEXINIT_RECEIVED
SSH_SESSION_STATE_DH
, and starts the key exchange (a.k.a DH) state machine by calling dh_handshake()
session->dh_handshake_state
SSH_SESSION_AUTHENTICATING
.
session->session_state
to SSH_SESSION_AUTHENTICATED
or SSH_SESSION_STATE_ERROR
Now the key exchange is finished and the user can use one of the authentication methods to authenticate.
libssh