Compare commits

...

19 commits

Author SHA1 Message Date
Augusto Dwenger J. b5c2560358 Replace deprecated ioutil.ReadFile with new func from os 2023-09-21 23:16:03 +02:00
Augusto Dwenger J. 61fc3ad141 Replace own ip extraction function with func from net package 2023-09-21 23:13:31 +02:00
Augusto Dwenger J. fd3e5530f9 Update crypto lib 2023-09-14 19:09:32 +02:00
Augusto Dwenger J. c12c77fb1d Update crypto lib 2022-09-24 17:05:36 +02:00
Augusto Dwenger J. fc116692a0 Increase project golang version to 1.19
Keep it up to date.
2022-08-11 18:16:32 +02:00
Augusto Dwenger J. 39a4ad47e1 Update crypto lib 2022-08-11 18:06:22 +02:00
Augusto Dwenger J. 7f421ecadb
Add a license section to the README 2022-05-21 16:15:44 +02:00
Augusto Dwenger J. ee5fd989b6
Update copyright holder information 2022-05-21 16:13:08 +02:00
Augusto Dwenger J. 1dc9ba16b5
Fix WaitGroup count on IPv4 only mode
It doesn't really matters, because we never mark them as done, but this
would make it easier if waiting for it would be required in the future.
2022-05-21 16:08:52 +02:00
Augusto Dwenger J. 8ebf7531e9
Move the ssh.ServerConfig creation to the main func
There is no need to create a config per request.
2022-05-21 16:08:32 +02:00
Augusto Dwenger J. f5a9473a9a
Extract previously inline PasswordCallback function into own function
I decided instead of defining the func inline in to a top level function
to reduce the nesting
2022-05-21 15:53:39 +02:00
Augusto Dwenger J. 52d38f1d36
Update go version in Dockerfile to 1.18 2022-05-21 15:51:57 +02:00
Augusto Dwenger J. 1a1119b9af
Increase project golang version 1.18
Keep it up to date.
2022-05-21 13:46:57 +02:00
Augusto Dwenger J. 9678d7ada2
Update crypto lib 2022-05-21 13:45:08 +02:00
Augusto Dwenger J. e11b8d9646 Update crypto lib 2022-03-16 11:47:28 +01:00
Augusto Dwenger J. b4a50e382f Fix variable naming inside the getKey function
This should fix golint.
2022-03-16 11:46:26 +01:00
Augusto Dwenger J. a1a5164061 Unexport PrintData function
There is no need to export the function.
2022-03-16 11:46:26 +01:00
Augusto Dwenger J. d20988a778 Update the crypto dependency 2022-01-17 19:46:54 +01:00
Augusto Dwenger J. fc61e9f469
Adjust README section titel heights 2021-09-02 12:58:57 +02:00
7 changed files with 56 additions and 82 deletions

View file

@ -1,4 +1,4 @@
FROM docker.io/golang:1.16.5 AS build
FROM docker.io/golang:1.19 AS build
WORKDIR /src
COPY go.* /src/

View file

@ -1,4 +1,4 @@
MIT License Copyright (c) 2021 Augusto Dwenger J.
MIT License Copyright (c) 2021-2022 Augusto Dwenger J.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -4,7 +4,7 @@ A small tool to log IPs, usernames and passwords from incoming ssh-auth requests
It opens a minimal SSH-Server and listens on IPv4 and IPv6 for auth requests.
The goal of this little tool is to log the requests coming from bots living inside the wild internet.
# Install
## Install
Make sure you have Golang installed and configured.
```shell
git clone https://git.sr.ht/~hamburghammer/sshlog
@ -13,7 +13,7 @@ go build
```
Now you should be able to execute the newly generated executable with `./sshlog`.
# Usage
## Usage
Start with:
```shell
sshlog -p 2222
@ -35,7 +35,7 @@ Output with `--json`:
{"date": "2021-09-02T12:44:21+02:00", "src": "127.0.0.1", "username": "test", "password": "fooof"}
```
## Options
### Options
```text
A small tool to log IPs, usernames and passwords from incoming ssh-auth requests.
@ -51,6 +51,8 @@ FLAGS:
-p, --port string Port to listen for incoming connections. (default "22"))
```
# Utils
## Utils
Inside the `util` directory you might find some additional information like how to create Systemd service for sshlog.
## License
This project is being licensed under the [MIT license](LICENSE).

6
go.mod
View file

@ -1,8 +1,10 @@
module git.sr.ht/~hamburghammer/sshlog
go 1.16
go 1.19
require (
github.com/spf13/pflag v1.0.5
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
golang.org/x/crypto v0.13.0
)
require golang.org/x/sys v0.12.0 // indirect

15
go.sum
View file

@ -1,12 +1,7 @@
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=

80
main.go
View file

@ -6,11 +6,9 @@ import (
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"log"
"net"
"os"
"strings"
"sync"
"time"
@ -49,6 +47,9 @@ func main() {
log.Fatal("Failed to parse private key")
}
serverConfig := ssh.ServerConfig{PasswordCallback: printConnectionData}
serverConfig.AddHostKey(hostKey)
log.Printf("Starting ssh logger on port %s...\n", port)
ipv4Listener, err := net.Listen("tcp", "0.0.0.0:"+port)
if err != nil {
@ -57,8 +58,8 @@ func main() {
defer ipv4Listener.Close()
wg := new(sync.WaitGroup)
wg.Add(2)
go startAccepting(ipv4Listener, hostKey)
wg.Add(1)
go startAccepting(ipv4Listener, serverConfig)
if !onlyIPv4 {
ipv6Listener, err := net.Listen("tcp", "[::1]:"+port)
@ -67,73 +68,77 @@ func main() {
}
defer ipv6Listener.Close()
go startAccepting(ipv6Listener, hostKey)
wg.Add(1)
go startAccepting(ipv6Listener, serverConfig)
}
wg.Wait() // Waits until it gets terminated
}
func startAccepting(listener net.Listener, hostKey ssh.Signer) {
func startAccepting(listener net.Listener, serverConfig ssh.ServerConfig) {
for {
con, err := listener.Accept()
if err != nil {
log.Println(err)
}
go PrintData(con, hostKey)
go connectionHandler(con, serverConfig)
}
}
func getKey(path string) []byte {
if path != "" {
privateBytes, err := ioutil.ReadFile(path)
privateBytes, err := os.ReadFile(path)
if err != nil {
log.Fatalf("Failed to load private key: %s", path)
}
return privateBytes
}
privatekey, err := rsa.GenerateKey(rand.Reader, 2048)
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Fatalf("Cannot generate RSA key\n")
}
privkey_bytes := x509.MarshalPKCS1PrivateKey(privatekey)
privkey_pem := pem.EncodeToMemory(
privateKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey)
privateKeyPem := pem.EncodeToMemory(
&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privkey_bytes,
Bytes: privateKeyBytes,
},
)
return privkey_pem
return privateKeyPem
}
func PrintData(con net.Conn, hostKey ssh.Signer) {
serverConfig := ssh.ServerConfig{PasswordCallback: func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
ip := getIPWithoutPort(conn.RemoteAddr().String())
if isJson {
fmt.Printf(
"{\"date\": \"%s\", \"src\": \"%s\", \"username\": \"%s\", \"password\": \"%s\"}\n",
time.Now().Format(time.RFC3339),
ip,
conn.User(),
string(password),
)
} else {
log.Printf("SRC=%s USERNAME=%s PASSWORD=%s\n", ip, conn.User(), string(password))
}
return nil, fmt.Errorf("password rejected for %s", conn.User())
}}
serverConfig.AddHostKey(hostKey)
func connectionHandler(con net.Conn, serverConfig ssh.ServerConfig) {
_, _, _, err := ssh.NewServerConn(con, &serverConfig)
if err != nil {
return
}
}
func printConnectionData(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
responseErr := fmt.Errorf("password rejected for %s", conn.User())
ip, _, err := net.SplitHostPort(conn.RemoteAddr().String())
if err != nil {
fmt.Println(err)
return nil, responseErr
}
if isJson {
fmt.Printf(
"{\"date\": \"%s\", \"src\": \"%s\", \"username\": \"%s\", \"password\": \"%s\"}\n",
time.Now().Format(time.RFC3339),
ip,
conn.User(),
string(password),
)
} else {
log.Printf("SRC=%s USERNAME=%s PASSWORD=%s\n", ip, conn.User(), string(password))
}
return nil, responseErr
}
func printHelp() {
fmt.Println(`A small tool to log IPs, usernames and passwords from incoming ssh-auth requests.
@ -143,10 +148,3 @@ USAGE:
FLAGS:`)
flags.PrintDefaults()
}
func getIPWithoutPort(address string) string {
if strings.Contains(address, "]") { // Is IPv6
return strings.ReplaceAll(strings.Split(address, "]")[0], "[", "")
}
return strings.Split(address, ":")[0]
}

View file

@ -1,23 +0,0 @@
package main
import "testing"
func TestGetIPWithoutPort(t *testing.T) {
t.Run("IPv6", func(t *testing.T) {
got := getIPWithoutPort("[::1]:2222")
want := "::1"
if want != got {
t.Fatalf("Want '%s' but got '%s'", want, got)
}
})
t.Run("IPv4", func(t *testing.T) {
got := getIPWithoutPort("127.0.0.1:2222")
want := "127.0.0.1"
if want != got {
t.Fatalf("Want '%s' but got '%s'", want, got)
}
})
}