I am learning golang and wanted to build a TCP port scanner with SOCKS5 proxies as a relay for mass scanning.
Although all of the S5 proxies are being checked for every target scan, sometimes there are some False positives - and I cannot find the reason why.
Preparing proxyDialer:
func create_socks5_tcp_dialer(socks5_addr string) proxy.Dialer {
//socks5_dialer_tcp, err := proxy.SOCKS5("tcp", socks5_addr, nil, proxy.Direct)
socks5_dialer_tcp, err := proxy.SOCKS5("tcp", socks5_addr, nil, &net.Dialer{Timeout: 5 * time.Second, KeepAlive: 5 * time.Second})
if err != nil {
fmt.Println("Error connecting to proxy:", err)
}
return socks5_dialer_tcp
}
Validating socks5 address:
func socks5_validator(socks5_addr, vps_opened, vps_closed string) (bool, string) {
/* Check if SOCKS5 proxy is valid.
1. Connect to the open port on the server under my control using proxy.
2. Connect to the closed port on the server under my control using proxy.
- If both checks are true then, SOCKS5 proxy is considered as valid.
- If one of the check is false, SOCKS5 proxy is considered as invalid.
3. Returns true/false and s5_addr.
*/
// Create SOCKS5 dialer
socks5_dialer_tcp := create_socks5_tcp_dialer(socks5_addr)
// Make connection using SOCKS5 proxy to the opened port on the vps.
conn_1, err := socks5_dialer_tcp.Dial("tcp", vps_opened)
// If it was successful and not generate any error then check1 is passed.
if err == nil {
//fmt.Println("CHECK 1: PASSED")
conn_1.Close()
// If error was generated then check is not passed and do not make check2.
} else {
//fmt.Println("CHECK 1: NOT PASSED")
return false, socks5_addr
}
// Make connection using SOCKS5 proxy to the closed port on the vps.
conn_2, err := socks5_dialer_tcp.Dial("tcp", vps_closed)
// If it was unsuccessful and error was generated then check2 is passed.
if err != nil {
//fmt.Println("CHECK 2: PASSED")
// If both checks were passed then return false.
return true, socks5_addr
// If error was not generated then check2 is not passed.
} else {
//fmt.Println("CHECK 2: NOT PASSED")
conn_2.Close()
return false, socks5_addr
}
}
Port scanning
s5_dialer_tcp := create_socks5_tcp_dialer(socks5_addr)
// Scan target using s5
conn, err := s5_dialer_tcp.Dial("tcp", target)
if err != nil {
//open
} else {
//closed
}
My question is:
Do I correctly scan TCP services through the SOCKS5 proxy and do I validate this proxy properly?
Link to the full code:
https://github.com/Karmaz95/crimson_prober
I don't think that these are actual false positives. Instead you are having the wrong assumptions of how these proxies will work: You assume that if the single check for a specific port open (connect success) and a specific port closed (connect failure) on a specific server at a specific time succeeds, then the proxy can be used to reliably check many arbitrary ports on arbitrary servers at arbitrary times.
This assumption is likely not valid, especially given that you seem to use proxies which are outside of your control.
A common behavior of such proxies is that they provide only restricted access, i.e. common ports like HTTP and HTTPS will work while other ports will be blocked. Proxies might also employ rate limiting, so they will simply deny access through the proxy after a while. And free proxies available in some lists often cease to work after a while.
Related
I deployed DgraphAlpha and DgraphZero in docker. I am connecting to Dgraph as described in the documentation.
func newClient() *dgo.Dgraph {
d, err := grpc.Dial("localhost:9080", grpc.WithInsecure())
if err != nil {
log.Fatal(err)
}
return dgo.NewDgraphClient(
api.NewDgraphClient(d),
)
}
And the client is created successfully, but when I try to search
txn := i.dgraphClient.NewReadOnlyTxn()
defer txn.Discard(context.Background())
dgraphQuery := "search here"
response, err := txn.Query(context.Background(), dgraphQuery)
if err != nil {
// error here
}
I get an error:
rpc error: code = Unavailable desc = connection closed before server preface received
This error does not always occur, at unexpected moments, and because of this it is difficult for me to determine its root. Has anyone encountered something similar? What could be the problem?
Beside other transitory causes, a common cause of this error is the server running with TLS enabled and the client attempting to connect without TLS.
Make sure you correctly configured TLS options on the client:
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{myCertificate},
RootCAs: myCAPool,
}
tlsOpt := grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig))
conn, err := grpc.DialContext(ctx, "<connection_string>", tlsOpt)
Make also sure you are actually using client certificates on the client connection.
It may be some issue with timing. This may happens more often in the first requests? Do you have any log on the Dgraph side?
Consider:
Use dial option WithBlock() to ensure you have a connection
Use DialContext and use a context with timeout to avoid wait a lot
Be aware that Insecure dial option is deprecated
Deprecated: use WithTransportCredentials and insecure.NewCredentials() instead.
About the error:
https://grpc.github.io/grpc/core/md_doc_statuscodes.html
Status code 14
This seems a transient error.
You may retry after some time. There are some retriers that can be used on this case like:
https://pkg.go.dev/github.com/eapache/go-resiliency/retrier
I'd like to intercept ALPN selection and select the one I want instead of the first common one between the client and the server.
Code:
// we have some ALPN protocols and certificates for TLS/SSL
tlsConfig := &tls.Config {
Certificates: serverCertificates,
NextProtos : serverALPN,
}
// a simple TCP server
server, err := net.Listen("tcp", serverHost+":"+serverPort)
...
for {
// we accept a connection
conn, err := ln.Accept()
...
// wrap it in TLS
tlsConn := tls.Server(conn, &tlsConfig)
// and pass it to the handler
go handleConnection(tlsConn)
}
So far we didn't do any TLS handshaking, so the connection is idle, pure. In func handleConnection(conn *tls.Conn) we would err := conn.Handshake() to perform the handshaking automatically for us, but how to do it manually? I didn't seem to find any info on that in tls module documentation. I'd like to do something like this:
// we communicate with client until he's told us all the ALPNs they support
state := conn.HandshakeUntilALPN()
// we got the list, now we use some algorithm to choose the ALPN
ALPN := myALPNAlgorithm(state.listOfALPNsFromClient)
// after that we tell the client which algo we've chosen
conn.SendALPN(ALPN)
// and we continue the handshake
conn.ContinueHandshake()
...
Of course it's silly pseudo-pseudo code, but hopefully you get the idea :)
Ideally, I'd like to know that for both the Server and the Client, if it's possible at all.
the answer is in the crypto library:
https://pkg.go.dev/crypto/tls
these papers might be useful:
https://developpaper.com/the-principle-of-https-and-golang-specifies-the-https-cipher-suite/
and
https://eli.thegreenplace.net/2021/go-https-servers-with-tls/
You will need to build your own server and client. TLSlistenandserve is an abstraction. you will have to build your own listenandserve.
I'm trying to find a standard way to close a connection between a client and server in a UDP connection.
Currently, I came up with the following solution, however, I'm not sure whether this is an idiomatic way or not?
Basically what I'm doing here on the server-side (handleClient function) is to conn.WriteTo(nil, Addr) which write nil to the UDP address. on the client side I check if the read() function retrieved any data or not, in case the number of the reading byte is zero, the client gives up on reading.
if n ==0 || err != nil {
break
}
Here is my simplified Server.go file:
func handleClient(conn *net.UDPConn) {
b := make([]byte, 1024)
n, Addr, err := conn.ReadFrom(b[0:])
if err != nil {
panic(err)
}
fmt.Println("read: ", n, " bytes", Addr.String())
// write the data back to the client, just for debug purpose
conn.WriteTo(b[0:n], Addr)
// let the client know that server has no more data
conn.WriteTo(nil, Addr)
}
And this is my client.go file
conn, err := net.Dial("udp", ":14000")
if err != nil {
panic(err)
}
defer conn.Close()
conn.Write([]byte("I'm client "))
for {
b := make([]byte, 512)
n, err := conn.Read(b)
if n ==0 || err != nil {
fmt.Println(">", n, err)
break
}
fmt.Println(string(b))
}
fmt.Println("finished.")
There is no standard way to do this. UDP is a stateless protocol so there is no "connection" like you would have with a TCP connection. DNS for example has no concept of a state, a client sends a request and the server will respond, no state is maintained, this is usually the selling point of UDP.
The applications are responsible for maintain state, so if you want a stateful protocol on top of UDP you also have to handle closing such a connection yourself. You might take inspiration from FTP or TFTP on how to implement this. Or consider using a stateful transport layer protocol like TCP or QUIC to handle stateful connections for you.
I need to send a UDPv6 datagram being able to track this message by a local receiver (or via tcpdump).
daddr, err = net.ResolveUDPAddr("udp6", "[address]:port")
if err != nil {
return err
}
conn, err := net.DialUDP("udp6", nil, daddr)
if err != nil {
return err
}
defer conn.Close()
conn.Write(...)
Unlike IPv4 this code doesn't work with IPv6. For example, when I try to send a datagram to a multicast address, e.g. to [FF01::DB8:0:0]:5000, I get connect: invalid argument. The same happens when I try to send it to [fe80::20c:29ff:fee1:d66]:5000 (my IPv6 address according to ifconfig).
In both cases (link-local and interface-local multicast) you have forgotten to specify the scope ID. Without this, it is impossible to determine which interface to use, and you get an Invalid argument error from the operating system.
net.UDPAddr uses the Zone field to store the scope ID. You need to ensure that you have provided one, either by setting Zone explicitly or by using the percent-suffix notation.
I'm trying to create (and later close) a simple TCP port forward over SSH with Go. I'm new to Golang and statically typed languages. (Coming from Ruby.)
In a terminal I would simply run ssh -L 9000:localhost:9999 user#server.com and this accomplishes what I need. I want to do the same, programmatically with Go.
I have tried using this example as a starting point and this recent test to try to understand what to do, but now I have a pile of confusing jumbled code when it seems like this is actually a very simple thing to do.
Any help would be very much appreciated! :-)
I finally figured out how to do this, I got hints from schmichael in an IRC channel. Thanks to all!
EDIT: A little explanation:
A big part of the problem I was having was that I did not realize a local net.Listener (not just a local net.Conn) needed setup to receive a local request and create the net.Conn before forwarding the bytes.
Also, there exist both port forwards and reverse port forwards and I hadn't previously thought in detail about the fact that a regular port forward also sends bytes back, so copying the remote reader to local writer was not something I had implemented, yet it's very much needed.
Here is an attempt to relate the essence of what this code does:
Listen on local port 9000.
Upon attempted read from local port 9000: (listener.Accept()),
Accept connection and return a local io.Reader and io.Writer and,
Connect to remote server and,
Connect to remote port 9999 returning a io.Reader and io.Writer.
Continually copy local io.Reader bytes to remote io.Writer,
Continually copy remote io.Reader bytes to local io.Writer.
Here is the code:
package main
// Forward from local port 9000 to remote port 9999
import (
"io"
"log"
"net"
"golang.org/x/crypto/ssh"
)
var (
username = "root"
password = "password"
serverAddrString = "192.168.1.100:22"
localAddrString = "localhost:9000"
remoteAddrString = "localhost:9999"
)
func forward(localConn net.Conn, config *ssh.ClientConfig) {
// Setup sshClientConn (type *ssh.ClientConn)
sshClientConn, err := ssh.Dial("tcp", serverAddrString, config)
if err != nil {
log.Fatalf("ssh.Dial failed: %s", err)
}
// Setup sshConn (type net.Conn)
sshConn, err := sshClientConn.Dial("tcp", remoteAddrString)
// Copy localConn.Reader to sshConn.Writer
go func() {
_, err = io.Copy(sshConn, localConn)
if err != nil {
log.Fatalf("io.Copy failed: %v", err)
}
}()
// Copy sshConn.Reader to localConn.Writer
go func() {
_, err = io.Copy(localConn, sshConn)
if err != nil {
log.Fatalf("io.Copy failed: %v", err)
}
}()
}
func main() {
// Setup SSH config (type *ssh.ClientConfig)
config := &ssh.ClientConfig{
User: username,
Auth: []ssh.AuthMethod{
ssh.Password(password),
},
}
// Setup localListener (type net.Listener)
localListener, err := net.Listen("tcp", localAddrString)
if err != nil {
log.Fatalf("net.Listen failed: %v", err)
}
for {
// Setup localConn (type net.Conn)
localConn, err := localListener.Accept()
if err != nil {
log.Fatalf("listen.Accept failed: %v", err)
}
go forward(localConn, config)
}
}
I have used your (damick) example code to build a tiny open source tool: SSHTunnel
https://github.com/SommerEngineering/SSHTunnel
Therefore, the code is freely available at GitHub for anyone: Please feel free to use it for learning purposes or for anything else :) I have mentioned your nickname and also linked to this question.
Best regards,
Thorsten.
I'v finished a simple SSH port forward tool called mallory.
It provides HTTP proxy instead of SOCKS proxy, which is really similar to ssh -D.
The core code is similar to damick's answer.
Create ClientConfig
ssh.Dial to remote SSH server with the config and return Client
Now you can use Client.Dial to forward anything you like.
Dial initiates a connection to the addr from the remote host. The resulting connection has a zero LocalAddr() and RemoteAddr().
If you want to serve a SOCKS proxy server, use Client.Dial to connect to the remote server.
I Wrote a tool,Called gosshtool,with this tool,you can easy to create a simple TCP port forward over SSH with Go.https://github.com/scottkiss/gosshtool
I use this tool implemented a port forward server example project:
https://github.com/scottkiss/gooverssh