Пользовательский PAM для SSHD на C

Я пытаюсь понять, как работает PAM, создавая бэкдор SSH. Следуя этому примеру https://github.com/beatgammit/simple-pam, я уже знаю, как чтобы сделать функциональный модуль PAM, но я хочу прочитать токен жесткого кода из CIN. Я пробовал следующее:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>

/* expected hook */
PAM_EXTERN int pam_sm_setcred( pam_handle_t *pamh, int flags, int argc, const char **argv ) {
    return PAM_SUCCESS;
}

PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) {
    printf("Acct mgmt\n");
    return PAM_SUCCESS;
}

/* expected hook, this is where custom stuff happens */
PAM_EXTERN int pam_sm_authenticate( pam_handle_t *pamh, int flags,int argc, const char **argv ) {
    int retval;

    const char* pUsername;
    retval = pam_get_user(pamh, &pUsername, "Username: ");

    printf("Welcome %s\n", pUsername);

    if (retval != PAM_SUCCESS) {
        return retval;
    }

    if (strcmp(pUsername, "luciannitescu") != 0) {
        return PAM_AUTH_ERR;
    }

    char securetoken[8] = "aaaaaaa";
    char password[8];
    printf("Enter your secure token:\n");
    scanf(password);

    if (strcmp(password, securetoken) != 0)
    {
        return PAM_AUTH_ERR;
    }
    return PAM_SUCCESS;
}

При выполнении аутентификации ssh я получаю сообщение об отказе в разрешении, и если я удаляю следующие строки кода, все работает:

char securetoken[8] = "aaaaaaa";
    char password[8];
    printf("Enter your secure token:\n");
    scanf(password);

    if (strcmp(password, securetoken) != 0)
    {
        return PAM_AUTH_ERR;
    }

Неудачная аутентификация:

ssh [email protected] -v
OpenSSH_7.6p1 Ubuntu-4, OpenSSL 1.0.2n  7 Dec 2017
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug1: Connecting to 127.0.0.1 [127.0.0.1] port 22.
debug1: Connection established.
debug1: identity file /home/lucian/.ssh/id_rsa type 0
debug1: key_load_public: No such file or directory
debug1: identity file /home/lucian/.ssh/id_rsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/lucian/.ssh/id_dsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/lucian/.ssh/id_dsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/lucian/.ssh/id_ecdsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/lucian/.ssh/id_ecdsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/lucian/.ssh/id_ed25519 type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/lucian/.ssh/id_ed25519-cert type -1
debug1: Local version string SSH-2.0-OpenSSH_7.6p1 Ubuntu-4
debug1: Remote protocol version 2.0, remote software version OpenSSH_7.2p2 Ubuntu-4ubuntu2.4
debug1: match: OpenSSH_7.2p2 Ubuntu-4ubuntu2.4 pat OpenSSH* compat 0x04000000
debug1: Authenticating to 127.0.0.1:22 as 'luciannitescu'
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: algorithm: [email protected]
debug1: kex: host key algorithm: ecdsa-sha2-nistp256
debug1: kex: server->client cipher: [email protected] MAC: <implicit> compression: none
debug1: kex: client->server cipher: [email protected] MAC: <implicit> compression: none
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug1: Server host key: ecdsa-sha2-nistp256 SHA256:...
debug1: Host '127.0.0.1' is known and matches the ECDSA host key.
debug1: Found key in /home/lucian/.ssh/known_hosts:22
debug1: rekey after 134217728 blocks
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: rekey after 134217728 blocks
debug1: SSH2_MSG_EXT_INFO received
debug1: kex_input_ext_info: server-sig-algs=<rsa-sha2-256,rsa-sha2-512>
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey
debug1: Offering public key: RSA SHA256:... /home/lucian/.ssh/id_rsa
debug1: Authentications that can continue: publickey,password
debug1: Trying private key: /home/lucian/.ssh/id_dsa
debug1: Trying private key: /home/lucian/.ssh/id_ecdsa
debug1: Trying private key: /home/lucian/.ssh/id_ed25519
debug1: Next authentication method: password
[email protected]'s password: 
debug1: Authentications that can continue: publickey,password
Permission denied, please try again.
[email protected]'s password: 
debug1: Authentications that can continue: publickey,password
Permission denied, please try again.
[email protected]'s password: 
debug1: Authentications that can continue: publickey,password
debug1: No more authentication methods to try.
[email protected]: Permission denied (publickey,password).

Позднее редактирование:

После изменения кода на следующее:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>

/* expected hook */
PAM_EXTERN int pam_sm_setcred( pam_handle_t *pamh, int flags, int argc, const char **argv ) {
    return PAM_SUCCESS;
}

PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) {
    printf("Acct mgmt\n");

    return PAM_SUCCESS;
}

/* expected hook, this is where custom stuff happens */
PAM_EXTERN int pam_sm_authenticate( pam_handle_t *pamh, int flags,int argc, const char **argv ) {
    struct pam_message msg[1];
    struct pam_response *resp = NULL;
    struct pam_conv *conv;

    pam_get_item (pamh, PAM_CONV, (const void **) &conv);
    msg[0].msg = "Enter your secret token: ";
    msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
    conv->conv(1, &msg, &resp, conv->appdata_ptr);
    // Token is now in resp->resp;

    int retval;

    const char* pUsername;
    retval = pam_get_user(pamh, &pUsername, "Username: ");

    printf("Welcome %s\n", pUsername);

    if (retval != PAM_SUCCESS) {
        return retval;
    }

    if (strcmp(pUsername, "luciannitescu") != 0) {
        return PAM_AUTH_ERR;
    }



    return PAM_SUCCESS;
}

Я не могу установить SSH-соединение:

lucian@local:~$ ssh [email protected]
[email protected]'s password: 
Connection closed by 127.0.0.1 port 22

Отладка сервера:

debug3: mm_request_send entering: type 23
debug2: userauth_pubkey: authenticated 0 pkalg rsa-sha2-512 [preauth]
debug3: userauth_finish: failure partial=0 next methods="publickey,password" [preauth]
debug3: send packet: type 51 [preauth]
debug3: receive packet: type 50 [preauth]
debug1: userauth-request for user luciannitescu service ssh-connection method password [preauth]
debug1: attempt 2 failures 1 [preauth]
debug2: input_userauth_request: try method password [preauth]
debug3: mm_auth_password entering [preauth]
debug3: mm_request_send entering: type 12 [preauth]
debug3: mm_auth_password: waiting for MONITOR_ANS_AUTHPASSWORD [preauth]
debug3: mm_request_receive_expect entering: type 13 [preauth]
debug3: mm_request_receive entering [preauth]
debug3: mm_request_receive entering
debug3: monitor_read: checking request 12
debug3: PAM: sshpam_passwd_conv called with 1 messages
mm_log_handler: write: Broken pipe
debug1: do_cleanup
debug3: PAM: sshpam_thread_cleanup entering
Segmentation fault (core dumped)

person Nitescu Lucian    schedule 18.10.2018    source источник


Ответы (1)


Вы не можете использовать scanf() для чтения значения от пользователя, так как стандартный ввод не передается пользователю. Вы должны использовать ssh клавиатурно-интерактивную аутентификацию с соответствующими функциями. Это поддерживается функциями pam_conv (диалог PAM).

Страница руководства _man 3 pam_conv_ описывает интерфейс. Это работает в основном следующим образом:

PAM_EXTERN int
pam_sm_authenticate (pam_handle_t * pamh,
                 int flags, int argc, const char **argv)
{
    struct pam_message msg[1];
    struct pam_response *resp = NULL;
    struct pam_conv *conv;

    pam_get_item (pamh, PAM_CONV, (const void **) &conv);
    msg[0].msg = "Enter your secret token: ";
    msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
    conv->conv(1, &msg, &resp, conv->appdata_ptr);
    // Token is now in resp->resp;
    ....
}

Вы можете использовать это как начало для вашей пользовательской функции аутентификации.

person Ctx    schedule 18.10.2018
comment
почему у меня закрывается соединение на порту 22? - person Nitescu Lucian; 18.10.2018
comment
@NitescuLucian Если у вас есть дополнительные проблемы, подробно опишите их в своем вопросе. - person Ctx; 18.10.2018
comment
@NitescuLucian 1) Всегда выполняйте проверку ошибок (pam_get_item()/conv-›conv()) и т. д. Я опустил это для краткости. Кроме того, вы можете запустить свой сервер с sshd -dddDp 222 и подключиться к порту 222 и посмотреть, что происходит на стороне сервера. - person Ctx; 18.10.2018
comment
не могли бы вы помочь мне? - person Nitescu Lucian; 18.10.2018