Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
phillip-stephens authored Jan 27, 2025
2 parents e70804e + ef21a75 commit 99c9e76
Show file tree
Hide file tree
Showing 9 changed files with 275 additions and 2 deletions.
3 changes: 3 additions & 0 deletions integration_tests/pptp/chap-secrets
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Secrets for authentication using PAP
# client server secret acceptable local IP addresses
username * password *
9 changes: 9 additions & 0 deletions integration_tests/pptp/cleanup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash

set +e

echo "pptp/cleanup: Tests cleanup for pptp"

CONTAINER_NAME=zgrab_pptp

docker stop $CONTAINER_NAME
26 changes: 26 additions & 0 deletions integration_tests/pptp/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env bash

echo "pptp/setup: Tests setup for pptp"

CONTAINER_TAG="mobtitude/vpn-pptp"
CONTAINER_NAME="zgrab_pptp"

# If the container is already running, use it.
if docker ps --filter "name=$CONTAINER_NAME" | grep -q $CONTAINER_NAME; then
echo "pptp/setup: Container $CONTAINER_NAME already running -- nothing to setup"
exit 0
fi

DOCKER_RUN_FLAGS="--rm --privileged --name $CONTAINER_NAME -td -v ./chap-secrets:/etc/ppp/chap-secrets"

# If it is not running, try launching it -- on success, use that.
echo "pptp/setup: Trying to launch $CONTAINER_NAME..."
if ! docker run $DOCKER_RUN_FLAGS $CONTAINER_TAG; then
echo "failed"
# echo "pptp/setup: Building docker image $CONTAINER_TAG..."
# # If it fails, build it from ./container/Dockerfile
# docker build -t $CONTAINER_TAG ./container
# # Try again
# echo "pptp/setup: Launching $CONTAINER_NAME..."
# docker run $DOCKER_RUN_FLAGS $CONTAINER_TAG
fi
23 changes: 23 additions & 0 deletions integration_tests/pptp/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env bash

set -e
MODULE_DIR=$(dirname $0)
ZGRAB_ROOT=$(git rev-parse --show-toplevel)
ZGRAB_OUTPUT=$ZGRAB_ROOT/zgrab-output

mkdir -p $ZGRAB_OUTPUT/pptp

CONTAINER_NAME=zgrab_pptp

OUTPUT_FILE=$ZGRAB_OUTPUT/pptp/pptp.json

echo "pptp/test: Tests runner for pptp"
# TODO FIXME: Add any necessary flags or additional tests
CONTAINER_NAME=$CONTAINER_NAME $ZGRAB_ROOT/docker-runner/docker-run.sh pptp > $OUTPUT_FILE

# Dump the docker logs
echo "pptp/test: BEGIN docker logs from $CONTAINER_NAME [{("
docker logs --tail all $CONTAINER_NAME
echo ")}] END docker logs from $CONTAINER_NAME"

# TODO: If there are any other relevant log files, dump those to stdout here.
4 changes: 2 additions & 2 deletions modules/http/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -570,15 +570,15 @@ func (scan *scan) Grab() *zgrab2.ScanError {
}

// Application-specific logic for retrying HTTP as HTTPS; if condition matches, return protocol error
if scan.scanner.config.FailHTTPToHTTPS && scan.results.Response.StatusCode == 400 && readLen < 1024 && readLen > 24 {
bodyTextLen := int64(len(bodyText))
if scan.scanner.config.FailHTTPToHTTPS && scan.results.Response.StatusCode == 400 && bodyTextLen < 1024 && bodyTextLen > 24 {
// Apache: "You're speaking plain HTTP to an SSL-enabled server port"
// NGINX: "The plain HTTP request was sent to HTTPS port"
var sliceLen int64 = 128
if readLen < sliceLen {
sliceLen = readLen
}

bodyTextLen := int64(len(bodyText))
if bodyTextLen < sliceLen {
sliceLen = bodyTextLen
}
Expand Down
7 changes: 7 additions & 0 deletions modules/pptp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package modules

import "github.com/zmap/zgrab2/modules/pptp"

func init() {
pptp.RegisterModule()
}
179 changes: 179 additions & 0 deletions modules/pptp/scanner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// Package pptp contains the zgrab2 Module implementation for PPTP.
package pptp

import (
"encoding/binary"
"fmt"
"net"
"time"

log "github.com/sirupsen/logrus"
"github.com/zmap/zgrab2"
)

// ScanResults is the output of the scan.
type ScanResults struct {
// Banner is the initial data banner sent by the server.
Banner string `json:"banner,omitempty"`

// ControlMessage is the received PPTP control message.
ControlMessage string `json:"control_message,omitempty"`
}

// Flags are the PPTP-specific command-line flags.
type Flags struct {
zgrab2.BaseFlags
Verbose bool `long:"verbose" description:"More verbose logging, include debug fields in the scan results"`
}

// Module implements the zgrab2.Module interface.
type Module struct {
}

// Scanner implements the zgrab2.Scanner interface, and holds the state
// for a single scan.
type Scanner struct {
config *Flags
}

// RegisterModule registers the pptp zgrab2 module.
func RegisterModule() {
var module Module
_, err := zgrab2.AddCommand("pptp", "PPTP", module.Description(), 1723, &module)
if err != nil {
log.Fatal(err)
}
}

// NewFlags returns the default flags object to be filled in with the
// command-line arguments.
func (m *Module) NewFlags() interface{} {
return new(Flags)
}

// NewScanner returns a new Scanner instance.
func (m *Module) NewScanner() zgrab2.Scanner {
return new(Scanner)
}

// Description returns an overview of this module.
func (m *Module) Description() string {
return "Scan for PPTP"
}

// Validate flags
func (f *Flags) Validate(args []string) (err error) {
return
}

// Help returns this module's help string.
func (f *Flags) Help() string {
return ""
}

// Protocol returns the protocol identifier for the scanner.
func (s *Scanner) Protocol() string {
return "pptp"
}

// Init initializes the Scanner instance with the flags from the command line.
func (s *Scanner) Init(flags zgrab2.ScanFlags) error {
f, _ := flags.(*Flags)
s.config = f
return nil
}

// InitPerSender does nothing in this module.
func (s *Scanner) InitPerSender(senderID int) error {
return nil
}

// GetName returns the configured name for the Scanner.
func (s *Scanner) GetName() string {
return s.config.Name
}

// GetTrigger returns the Trigger defined in the Flags.
func (scanner *Scanner) GetTrigger() string {
return scanner.config.Trigger
}

// PPTP Start-Control-Connection-Request message constants
const (
PPTP_MAGIC_COOKIE = 0x1A2B3C4D
PPTP_CONTROL_MESSAGE = 1
PPTP_START_CONN_REQUEST = 1
PPTP_PROTOCOL_VERSION = 0x0100 // Split into two 16-bit values for binary.BigEndian.PutUint16
)

// Connection holds the state for a single connection to the PPTP server.
type Connection struct {
config *Flags
results ScanResults
conn net.Conn
}

// Create the Start-Control-Connection-Request message
func createSCCRMessage() []byte {
message := make([]byte, 156)
binary.BigEndian.PutUint16(message[0:2], 156) // Length
binary.BigEndian.PutUint16(message[2:4], PPTP_CONTROL_MESSAGE) // PPTP Message Type
binary.BigEndian.PutUint32(message[4:8], PPTP_MAGIC_COOKIE) // Magic Cookie
binary.BigEndian.PutUint16(message[8:10], PPTP_START_CONN_REQUEST) // Control Message Type
binary.BigEndian.PutUint16(message[10:12], uint16(PPTP_PROTOCOL_VERSION>>16)) // Protocol Version (high 16 bits)
binary.BigEndian.PutUint16(message[12:14], uint16(PPTP_PROTOCOL_VERSION&0xFFFF)) // Protocol Version (low 16 bits)
binary.BigEndian.PutUint32(message[14:18], 0) // Framing Capabilities
binary.BigEndian.PutUint32(message[18:22], 0) // Bearer Capabilities
binary.BigEndian.PutUint16(message[22:24], 0) // Maximum Channels
binary.BigEndian.PutUint16(message[24:26], 0) // Firmware Revision
copy(message[26:90], "ZGRAB2-SCANNER") // Host Name
copy(message[90:], "ZGRAB2") // Vendor Name
return message
}

// Read response from the PPTP server
func (pptp *Connection) readResponse() (string, error) {
buffer := make([]byte, 1024)
pptp.conn.SetReadDeadline(time.Now().Add(5 * time.Second))
n, err := pptp.conn.Read(buffer)
if err != nil {
return "", err
}
return string(buffer[:n]), nil
}

// Scan performs the configured scan on the PPTP server
func (s *Scanner) Scan(t zgrab2.ScanTarget) (status zgrab2.ScanStatus, result interface{}, thrown error) {
var err error
conn, err := t.Open(&s.config.BaseFlags)
if err != nil {
return zgrab2.TryGetScanStatus(err), nil, fmt.Errorf("error opening connection: %w", err)
}
cn := conn
defer func() {
cn.Close()
}()

results := ScanResults{}

pptp := Connection{conn: cn, config: s.config, results: results}

// Send Start-Control-Connection-Request message
request := createSCCRMessage()
_, err = pptp.conn.Write(request)
if err != nil {
return zgrab2.TryGetScanStatus(err), &pptp.results, fmt.Errorf("error sending PPTP SCCR message: %w", err)
}

// Read the response
response, err := pptp.readResponse()
if err != nil {
return zgrab2.TryGetScanStatus(err), &pptp.results, fmt.Errorf("error reading PPTP response: %w", err)
}

// Store the banner and control message
pptp.results.Banner = string(request)
pptp.results.ControlMessage = response

return zgrab2.SCAN_SUCCESS, &pptp.results, nil
}
1 change: 1 addition & 0 deletions zgrab2_schemas/zgrab2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@
from . import banner
from . import amqp091
from . import mqtt
from . import pptp
25 changes: 25 additions & 0 deletions zgrab2_schemas/zgrab2/pptp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# zschema sub-schema for zgrab2's PPTP module
# Registers zgrab2-pptp globally, and pptp with the main zgrab2 schema.
from zschema.leaves import *
from zschema.compounds import *
import zschema.registry

from . import zgrab2

# Schema for ScanResults struct
pptp_scan_response = SubRecord(
{
"banner": String(),
"control_message": String(),
}
)

pptp_scan = SubRecord(
{
"result": pptp_scan_response,
},
extends=zgrab2.base_scan_response,
)

zschema.registry.register_schema("zgrab2-pptp", pptp_scan)
zgrab2.register_scan_response_type("pptp", pptp_scan)

0 comments on commit 99c9e76

Please sign in to comment.