Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions cmd/integration-test/javascript.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ var jsTestcases = []TestCaseInfo{
{Path: "protocols/javascript/mysql-connect.yaml", TestCase: &javascriptMySQLConnect{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }},
{Path: "protocols/javascript/multi-ports.yaml", TestCase: &javascriptMultiPortsSSH{}},
{Path: "protocols/javascript/no-port-args.yaml", TestCase: &javascriptNoPortArgs{}},
{Path: "protocols/javascript/telnet-auth-test.yaml", TestCase: &javascriptTelnetAuthTest{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }},
}

var (
redisResource *dockertest.Resource
sshResource *dockertest.Resource
oracleResource *dockertest.Resource
vncResource *dockertest.Resource
telnetResource *dockertest.Resource
postgresResource *dockertest.Resource
mysqlResource *dockertest.Resource
rsyncResource *dockertest.Resource
Expand Down Expand Up @@ -292,6 +294,38 @@ func (j *javascriptRsyncTest) Execute(filePath string) error {
return multierr.Combine(errs...)
}

type javascriptTelnetAuthTest struct{}

func (j *javascriptTelnetAuthTest) Execute(filePath string) error {
if telnetResource == nil || pool == nil {
// skip test as telnet is not running
return nil
}
tempPort := telnetResource.GetPort("23/tcp")
finalURL := "localhost:" + tempPort
defer purge(telnetResource)
errs := []error{}
for i := 0; i < defaultRetry; i++ {
results := []string{}
var err error
_ = pool.Retry(func() error {
//let telnet server start
time.Sleep(3 * time.Second)
results, err = testutils.RunNucleiTemplateAndGetResults(filePath, finalURL, debug)
return nil
})
if err != nil {
return err
}
if err := expectResultsCount(results, 1); err == nil {
return nil
} else {
errs = append(errs, err)
}
}
return multierr.Combine(errs...)
}

// purge any given resource if it is not nil
func purge(resource *dockertest.Resource) {
if resource != nil && pool != nil {
Expand Down Expand Up @@ -447,4 +481,22 @@ func init() {
if err := rsyncResource.Expire(30); err != nil {
log.Printf("Could not expire Rsync resource: %s", err)
}

// setup a temporary telnet server
// username: dev
// password: mysecret
telnetResource, err = pool.RunWithOptions(&dockertest.RunOptions{
Repository: "alpine",
Tag: "latest",
Cmd: []string{"sh", "-c", "apk add --no-cache busybox-extras shadow && useradd -m dev && echo 'dev:mysecret' | chpasswd && exec /usr/sbin/telnetd -F -p 23 -l /bin/login"},
Platform: "linux/amd64",
})
if err != nil {
log.Printf("Could not start Telnet resource: %s", err)
return
}
// by default expire after 30 sec
if err := telnetResource.Expire(30); err != nil {
log.Printf("Could not expire Telnet resource: %s", err)
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ require (
code.gitea.io/sdk/gitea v0.17.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0
github.com/Azure/go-ntlmssp v0.1.0
github.com/DataDog/gostackparse v0.7.0
github.com/Masterminds/semver/v3 v3.2.1
github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057
Expand Down Expand Up @@ -138,7 +139,6 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0 h1:nVocQV40OQne5613E
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0/go.mod h1:7QJP7dr2wznCMeqIrhMgWGf7XpAQnVrJqDm9nvV3Cu4=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/Azure/go-ntlmssp v0.1.0 h1:DjFo6YtWzNqNvQdrwEyr/e4nhU3vRiwenz5QX7sFz+A=
github.com/Azure/go-ntlmssp v0.1.0/go.mod h1:NYqdhxd/8aAct/s4qSYZEerdPuH1liG2/X9DiVTbhpk=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs=
Expand Down
28 changes: 28 additions & 0 deletions integration_tests/protocols/javascript/telnet-auth-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
id: telnet-auth-test

info:
name: Telnet Authentication Test
author: pdteam
severity: info
metadata:
shodan-query: port:23


javascript:
- code: |
var m = require("nuclei/telnet");
var c = m.TelnetClient();
c.Connect(Host, Port, User, Password);

args:
Host: "{{Host}}"
Port: "23"
User: "dev"
Password: "mysecret"

matchers:
- type: dsl
dsl:
- "response == true"
- "success == true"
condition: and
6 changes: 5 additions & 1 deletion pkg/js/generated/go/libtelnet/telnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package telnet

import (
lib_telnet "github.com/projectdiscovery/nuclei/v3/pkg/js/libs/telnet"
telnetmini "github.com/projectdiscovery/nuclei/v3/pkg/utils/telnetmini"

"github.com/Mzack9999/goja"
"github.com/projectdiscovery/nuclei/v3/pkg/js/gojs"
Expand All @@ -20,7 +21,10 @@ func init() {
// Var and consts

// Objects / Classes
"IsTelnetResponse": gojs.GetClassConstructor[lib_telnet.IsTelnetResponse](&lib_telnet.IsTelnetResponse{}),
"TelnetClient": gojs.GetClassConstructor[lib_telnet.TelnetClient](&lib_telnet.TelnetClient{}),
"IsTelnetResponse": gojs.GetClassConstructor[lib_telnet.IsTelnetResponse](&lib_telnet.IsTelnetResponse{}),
"TelnetInfoResponse": gojs.GetClassConstructor[lib_telnet.TelnetInfoResponse](&lib_telnet.TelnetInfoResponse{}),
"NTLMInfoResponse": gojs.GetClassConstructor[telnetmini.NTLMInfoResponse](&telnetmini.NTLMInfoResponse{}),
},
).Register()
}
Expand Down
131 changes: 131 additions & 0 deletions pkg/js/generated/ts/telnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,65 @@ export function IsTelnet(host: string, port: number): IsTelnetResponse | null {
return null;
}

/**
* TelnetClient is a client for Telnet servers.
* @example
* ```javascript
* const telnet = require('nuclei/telnet');
* const client = new telnet.TelnetClient();
* ```
*/
export class TelnetClient {

/**
* Connect tries to connect to provided host and port with telnet.
* Optionally provides username and password for authentication.
* Returns state of connection. If the connection is successful,
* the function will return true, otherwise false.
* @example
* ```javascript
* const telnet = require('nuclei/telnet');
* const client = new telnet.TelnetClient();
* const connected = client.Connect('acme.com', 23, 'username', 'password');
* ```
*/
public Connect(host: string, port: number, username: string, password: string): boolean {
return false;
}

/**
* Info gathers information about the telnet server including encryption support.
* Uses the telnetmini library's DetectEncryption helper function.
* WARNING: The connection used for detection becomes unusable after this call.
* @example
* ```javascript
* const telnet = require('nuclei/telnet');
* const client = new telnet.TelnetClient();
* const info = client.Info('acme.com', 23);
* log(toJSON(info));
* ```
*/
public Info(host: string, port: number): TelnetInfoResponse | null {
return null;
}

/**
* GetTelnetNTLMInfo implements the Nmap telnet-ntlm-info.nse script functionality.
* This function uses the telnetmini library and SMB packet crafting functions to send
* MS-TNAP NTLM authentication requests with null credentials. It might work only on
* Microsoft Telnet servers.
* @example
* ```javascript
* const telnet = require('nuclei/telnet');
* const client = new telnet.TelnetClient();
* const ntlmInfo = client.GetTelnetNTLMInfo('acme.com', 23);
* log(toJSON(ntlmInfo));
* ```
*/
public GetTelnetNTLMInfo(host: string, port: number): NTLMInfoResponse | null {
return null;
}
}

/**
* IsTelnetResponse is the response from the IsTelnet function.
Expand All @@ -32,3 +90,76 @@ export interface IsTelnetResponse {
Banner?: string,
}

/**
* TelnetInfoResponse is the response from the Info function.
* @example
* ```javascript
* const telnet = require('nuclei/telnet');
* const client = new telnet.TelnetClient();
* const info = client.Info('acme.com', 23);
* log(toJSON(info));
* ```
*/
export interface TelnetInfoResponse {

SupportsEncryption?: boolean,

Banner?: string,

Options?: { [key: number]: number[] },
}

/**
* NTLMInfoResponse represents the response from NTLM information gathering.
* This matches exactly the output structure from the Nmap telnet-ntlm-info.nse script.
* @example
* ```javascript
* const telnet = require('nuclei/telnet');
* const client = new telnet.TelnetClient();
* const ntlmInfo = client.GetTelnetNTLMInfo('acme.com', 23);
* log(toJSON(ntlmInfo));
* ```
*/
export interface NTLMInfoResponse {

/**
* Target_Name from script (target_realm in script)
*/
TargetName?: string,

/**
* NetBIOS_Domain_Name from script
*/
NetBIOSDomainName?: string,

/**
* NetBIOS_Computer_Name from script
*/
NetBIOSComputerName?: string,

/**
* DNS_Domain_Name from script
*/
DNSDomainName?: string,

/**
* DNS_Computer_Name from script (fqdn in script)
*/
DNSComputerName?: string,

/**
* DNS_Tree_Name from script (dns_forest_name in script)
*/
DNSTreeName?: string,

/**
* Product_Version from script
*/
ProductVersion?: string,

/**
* Raw timestamp for skew calculation
*/
Timestamp?: number,
}

Loading
Loading