Skip to content

Commit

Permalink
Merge pull request #7 from RUB-NDS/feat/json-output
Browse files Browse the repository at this point in the history
feat: Add JSON and colored output
  • Loading branch information
TrueSkrillor authored Dec 20, 2023
2 parents 5b35e76 + 26ee2a8 commit 412155c
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 20 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,15 @@ This will download, compile, and install the Go package for your local system. T
# The following command will listen for incoming connections on 127.0.0.1:2222
./Terrapin-Scanner --listen 2222
```

The scanner supports outputting the scan result as json. To do so, provide the `--json` flag when calling the scanner. The output is structured as follows:

```json
{
"Banner": "SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.5",
"SupportsChaCha20": true,
"SupportsCbcEtm": false,
"SupportsStrictKex": true,
"Vulnerable": false
}
```
8 changes: 8 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
module github.com/RUB-NDS/Terrapin-Scanner

go 1.21

require github.com/fatih/color v1.16.0

require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
golang.org/x/sys v0.14.0 // indirect
)
11 changes: 11 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
93 changes: 73 additions & 20 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package main
import (
"bufio"
"encoding/binary"
"encoding/json"
"flag"
"fmt"
"github.com/fatih/color"
"io"
"net"
"os"
Expand Down Expand Up @@ -62,6 +64,16 @@ func (report *TerrapinVulnerabilityReport) IsVulnerable() bool {
return (report.SupportsChaCha20 || report.SupportsCbcEtm) && !report.SupportsStrictKex
}

func (report *TerrapinVulnerabilityReport) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
TerrapinVulnerabilityReport
Vulnerable bool
}{
*report,
report.IsVulnerable(),
})
}

// Reads a single incoming, unencrypted binary packet from the provided connection.
// Does not support reading encrypted binary packets.
func readSinglePacket(connrw *bufio.ReadWriter) (*BinaryPacket, error) {
Expand Down Expand Up @@ -200,7 +212,7 @@ func performVulnerabilityScan(address string, scanMode ScanMode) (*TerrapinVulne
return nil, err
}
defer listener.Close()
fmt.Println("Listening for incoming client connection on", address)
fmt.Fprintln(os.Stderr, "Listening for incoming client connection on", address)

if conn, err = listener.Accept(); err != nil {
return nil, err
Expand Down Expand Up @@ -260,26 +272,54 @@ func formatAddress(address string, mode ScanMode) string {
return formatted
}

func printColoredBoolean(value bool, ifTrue color.Attribute, ifFalse color.Attribute) {
if value {
color.Set(ifTrue)
} else {
color.Set(ifFalse)
}
fmt.Printf("%t\n", value)
color.Unset()
}

// Prints the report to stdout
func printReport(report *TerrapinVulnerabilityReport) {
fmt.Println("================================================================================")
fmt.Println("==================================== Report ====================================")
fmt.Println("================================================================================")
fmt.Println()
fmt.Printf("Remote Banner: %s\n", report.Banner)
fmt.Println()
fmt.Printf("ChaCha20-Poly1305 support: %t\n", report.SupportsChaCha20)
fmt.Printf("CBC-EtM support: %t\n", report.SupportsCbcEtm)
fmt.Println()
fmt.Printf("Strict key exchange support: %t\n", report.SupportsStrictKex)
fmt.Println()
if report.IsVulnerable() {
fmt.Println("==> The scanned peer is VULNERABLE to Terrapin.")
func printReport(report *TerrapinVulnerabilityReport, outputJson bool) error {
if !outputJson {
color.Set(color.FgBlue)
fmt.Println("================================================================================")
fmt.Println("==================================== Report ====================================")
fmt.Println("================================================================================")
color.Unset()
fmt.Println()
fmt.Printf("Remote Banner: %s\n", report.Banner)
fmt.Println()
fmt.Print("ChaCha20-Poly1305 support: ")
printColoredBoolean(report.SupportsChaCha20, color.FgYellow, color.FgGreen)
fmt.Print("CBC-EtM support: ")
printColoredBoolean(report.SupportsCbcEtm, color.FgYellow, color.FgGreen)
fmt.Println()
fmt.Print("Strict key exchange support: ")
printColoredBoolean(report.SupportsStrictKex, color.FgGreen, color.FgRed)
fmt.Println()
if report.IsVulnerable() {
color.Set(color.FgRed)
fmt.Println("The scanned peer is VULNERABLE to Terrapin.")
color.Unset()
} else {
color.Set(color.FgGreen)
fmt.Println("The scanned peer supports Terrapin mitigations and can establish")
fmt.Println("connections that are NOT VULNERABLE to Terrapin. Glad to see this.")
fmt.Println("For strict key exchange to take effect, both peers must support it.")
color.Unset()
}
} else {
fmt.Println("==> The scanned peer supports Terrapin mitigations and can establish")
fmt.Println(" connections that are NOT VULNERABLE to Terrapin. Glad to see this.")
fmt.Println(" For strict key exchange to take effect, both peers must support it.")
marshalledReport, err := json.MarshalIndent(report, "", " ")
if err != nil {
return err
}
fmt.Println(string(marshalledReport))
}
return nil
}

// Prints a short disclaimer to stdout
Expand All @@ -303,11 +343,20 @@ func main() {
"listen",
"",
"Address to bind to for client-side scans. Format: [host:]<port>")
jsonPtr := flag.Bool(
"json",
false,
"Outputs the scan result as json. Can be useful when calling the scanner from a script.")
noColor := flag.Bool(
"no-color",
false,
"Disables colored output.")
helpPtr := flag.Bool(
"help",
false,
"Prints this usage help to the user.")
flag.Parse()
color.NoColor = *noColor
if (*connectPtr == "" && *listenPtr == "") || *helpPtr {
flag.Usage()
printDisclaimer()
Expand All @@ -330,6 +379,10 @@ func main() {
panic(err)
}
}
printReport(report)
printDisclaimer()
if err := printReport(report, *jsonPtr); err != nil {
panic(err)
}
if !*jsonPtr {
printDisclaimer()
}
}

0 comments on commit 412155c

Please # to comment.