Last active
May 17, 2016 16:37
-
-
Save singe/f433c54f134a9390214e to your computer and use it in GitHub Desktop.
A scanner for new POODLE (affecting TLS versions). These are mods to Adam Langley's (@agl__) work.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff -r f60b128afd41 src/crypto/tls/common.go | |
--- a/src/crypto/tls/common.go Tue Nov 04 10:20:35 2014 -0800 | |
+++ b/src/crypto/tls/common.go Mon Dec 08 14:56:25 2014 -0800 | |
@@ -343,6 +343,8 @@ | |
// be used. | |
CurvePreferences []CurveID | |
+ BreakCBCPadding bool | |
+ | |
serverInitOnce sync.Once // guards calling (*Config).serverInit | |
} | |
diff -r f60b128afd41 src/crypto/tls/conn.go | |
--- a/src/crypto/tls/conn.go Tue Nov 04 10:20:35 2014 -0800 | |
+++ b/src/crypto/tls/conn.go Mon Dec 08 14:56:25 2014 -0800 | |
@@ -109,6 +109,8 @@ | |
// used to save allocating a new buffer for each MAC. | |
inDigestBuf, outDigestBuf []byte | |
+ | |
+ brokenCBC bool | |
} | |
func (hc *halfConn) setErrorLocked(err error) error { | |
@@ -125,10 +127,11 @@ | |
// prepareCipherSpec sets the encryption and MAC states | |
// that a subsequent changeCipherSpec will use. | |
-func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) { | |
+func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction, brokenCBC bool) { | |
hc.version = version | |
hc.nextCipher = cipher | |
hc.nextMac = mac | |
+ hc.brokenCBC = brokenCBC | |
} | |
// changeCipherSpec changes the encryption and MAC states | |
@@ -339,14 +342,21 @@ | |
// block of payload. finalBlock is a fresh slice which contains the contents of | |
// any suffix of payload as well as the needed padding to make finalBlock a | |
// full block. | |
-func padToBlockSize(payload []byte, blockSize int) (prefix, finalBlock []byte) { | |
+func padToBlockSize(payload []byte, blockSize int, broken bool) (prefix, finalBlock []byte) { | |
overrun := len(payload) % blockSize | |
paddingLen := blockSize - overrun | |
prefix = payload[:len(payload)-overrun] | |
finalBlock = make([]byte, blockSize) | |
copy(finalBlock, payload[len(payload)-overrun:]) | |
- for i := overrun; i < blockSize; i++ { | |
- finalBlock[i] = byte(paddingLen - 1) | |
+ if !broken { | |
+ for i := overrun; i < blockSize; i++ { | |
+ finalBlock[i] = byte(paddingLen - 1) | |
+ } | |
+ } else { | |
+ for i := overrun; i < blockSize; i++ { | |
+ finalBlock[i] = byte(66-i) | |
+ } | |
+ finalBlock[blockSize-1] = byte(paddingLen-1) | |
} | |
return | |
} | |
@@ -390,7 +400,7 @@ | |
c.SetIV(payload[:explicitIVLen]) | |
payload = payload[explicitIVLen:] | |
} | |
- prefix, finalBlock := padToBlockSize(payload, blockSize) | |
+ prefix, finalBlock := padToBlockSize(payload, blockSize, hc.brokenCBC) | |
b.resize(recordHeaderLen + explicitIVLen + len(prefix) + len(finalBlock)) | |
c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen:], prefix) | |
c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen+len(prefix):], finalBlock) | |
diff -r f60b128afd41 src/crypto/tls/handshake_client.go | |
--- a/src/crypto/tls/handshake_client.go Tue Nov 04 10:20:35 2014 -0800 | |
+++ b/src/crypto/tls/handshake_client.go Mon Dec 08 14:56:25 2014 -0800 | |
@@ -478,8 +478,8 @@ | |
serverCipher = hs.suite.aead(serverKey, serverIV) | |
} | |
- c.in.prepareCipherSpec(c.vers, serverCipher, serverHash) | |
- c.out.prepareCipherSpec(c.vers, clientCipher, clientHash) | |
+ c.in.prepareCipherSpec(c.vers, serverCipher, serverHash, c.config.BreakCBCPadding) | |
+ c.out.prepareCipherSpec(c.vers, clientCipher, clientHash, c.config.BreakCBCPadding) | |
return nil | |
} | |
diff -r f60b128afd41 src/crypto/tls/handshake_server.go | |
--- a/src/crypto/tls/handshake_server.go Tue Nov 04 10:20:35 2014 -0800 | |
+++ b/src/crypto/tls/handshake_server.go Mon Dec 08 14:56:25 2014 -0800 | |
@@ -464,8 +464,8 @@ | |
serverCipher = hs.suite.aead(serverKey, serverIV) | |
} | |
- c.in.prepareCipherSpec(c.vers, clientCipher, clientHash) | |
- c.out.prepareCipherSpec(c.vers, serverCipher, serverHash) | |
+ c.in.prepareCipherSpec(c.vers, clientCipher, clientHash, false) | |
+ c.out.prepareCipherSpec(c.vers, serverCipher, serverHash, false) | |
return nil | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This is a very simple tool for checking for POODLE issues in TLS servers. | |
// See https://www.imperialviolet.org/2014/12/08/poodleagain.html | |
// Some quick hacks addedd by @singe @sensepost | |
package main | |
import ( | |
"bufio" | |
"crypto/tls" | |
"errors" | |
"flag" | |
"fmt" | |
"net" | |
"os" | |
"strings" | |
"sync" | |
"time" | |
) | |
var ( | |
hostsFile *string = flag.String("hosts", "", "Filename containing hosts to query") | |
onlyAffected *bool = flag.Bool("only-affected", false, "Only show output for affected sites") | |
tlsDetails *bool = flag.Bool("tls-details", false, "Show TLS cipher and protocol negotiated") | |
debug *bool = flag.Bool("debug", false, "Show full server response") | |
) | |
func scanHost(hostname string) error { | |
dialer := net.Dialer{ | |
Timeout: 15 * time.Second, | |
} | |
if !strings.Contains(hostname, ":") { | |
hostname = hostname + ":443" | |
} | |
conn, err := tls.DialWithDialer(&dialer, "tcp", hostname, &tls.Config{ | |
InsecureSkipVerify: true, | |
BreakCBCPadding: true, | |
CipherSuites: []uint16{ | |
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, | |
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, | |
tls.TLS_RSA_WITH_AES_128_CBC_SHA, | |
tls.TLS_RSA_WITH_AES_256_CBC_SHA, | |
tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA, | |
}, | |
}) | |
if err != nil { | |
return err | |
} | |
defer conn.Close() | |
if *tlsDetails { | |
version := conn.ConnectionState().Version | |
if version == tls.VersionSSL30 { | |
return errors.New(hostname+" SSLv3 negotiated\n") | |
} else if version == tls.VersionTLS10 { | |
fmt.Printf(hostname+" TLSv1.0 negotiated\n") | |
} else if version == tls.VersionTLS11 { | |
fmt.Printf(hostname+" TLSv1.1 negotiated\n") | |
} else if version == tls.VersionTLS12 { | |
fmt.Printf(hostname+" TLSv1.2 negotiated\n") | |
} | |
cipher := conn.ConnectionState().CipherSuite | |
if cipher == tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA { | |
fmt.Printf(hostname+" TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA negotiated\n") | |
} else if cipher == tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA { | |
fmt.Printf(hostname+" TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA negotiated\n") | |
} else if cipher == tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA { | |
fmt.Printf(hostname+" TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA negotiated\n") | |
} else if cipher == tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA { | |
fmt.Printf(hostname+" TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA negotiated\n") | |
} else if cipher == tls.TLS_RSA_WITH_AES_128_CBC_SHA { | |
fmt.Printf(hostname+" TLS_RSA_WITH_AES_128_CBC_SHA negotiated\n") | |
} else if cipher == tls.TLS_RSA_WITH_AES_256_CBC_SHA { | |
fmt.Printf(hostname+" TLS_RSA_WITH_AES_256_CBC_SHA negotiated\n") | |
} else if cipher == tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA { | |
fmt.Printf(hostname+" TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA negotiated\n") | |
} else if cipher == tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA { | |
fmt.Printf(hostname+" TLS_RSA_WITH_3DES_EDE_CBC_SHA negotiated\n") | |
} | |
} | |
conn.Write([]byte("HEAD / HTTP/1.1\r\nHost: "+hostname+"\r\n\r\n")) | |
var buf [512]byte | |
n, err := conn.Read(buf[:]) | |
if err != nil { | |
return err | |
} | |
if *debug { | |
fmt.Printf(hostname+" %d: %s\n", n, buf[:n]) | |
} | |
return nil | |
} | |
func worker(hosts <-chan string, done *sync.WaitGroup) { | |
defer done.Done() | |
for hostname := range hosts { | |
if strings.Contains(hostname, "-hosts=hosts") { | |
continue | |
} | |
err := scanHost(hostname) | |
if err != nil { | |
if !*onlyAffected { | |
fmt.Fprintf(os.Stderr, "NOT VULNERABLE: %s: %s\n", hostname, err) | |
} | |
continue | |
} | |
fmt.Printf("VULNERABLE: %s\n", hostname) | |
} | |
} | |
func main() { | |
flag.Parse() | |
var wg sync.WaitGroup | |
const numWorkers = 512 | |
hostnames := make(chan string, numWorkers) | |
for i := 0; i < numWorkers; i++ { | |
wg.Add(1) | |
go worker(hostnames, &wg) | |
} | |
/*for _, hostname := range os.Args[1:] { | |
hostnames <- hostname | |
}*/ | |
if len(*hostsFile) > 0 { | |
hosts, err := os.Open(*hostsFile) | |
if err != nil { | |
panic(err) | |
} | |
defer hosts.Close() | |
inHosts := bufio.NewScanner(hosts) | |
for inHosts.Scan() { | |
hostnames <- inHosts.Text() | |
} | |
if err := inHosts.Err(); err != nil { | |
panic(err) | |
} | |
} | |
close(hostnames) | |
wg.Wait() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment