Simple TCP scan with Go - go

I am learning to use Golang to develop hacking tools through Blackhat-Go and port scan scanme.nmap.org on Windows and Linux while doing TCP scanning.Here's my code
package main
import (
"fmt"
"net"
"sort"
)
func worker(ports, result chan int) {
for port := range ports {
address := fmt.Sprintf("scanme.nmap.org:%d", port)
conn, err := net.Dial("tcp", address)
if err != nil {
result <- 0
continue
}
conn.Close()
result <- port
}
}
func main() {
ports := make(chan int, 100)
result := make(chan int)
var openport []int
for i := 0; i < cap(ports); i++ {
go worker(ports, result)
}
go func() {
for i := 0; i < 1024; i++ {
ports <- i
}
}()
for i := 0; i < 1024; i++ {
port := <-result
if port != 0 {
openport = append(openport, port)
}
}
close(ports)
close(result)
sort.Ints(openport)
for _, value := range openport {
fmt.Printf("%d open\n", value)
}
}
Running on Windows shows that port 25 is open.
22 open
25 open
80 open
110 open
However, port 25 is not detected on Linux.
22 open
80 open
110 open
I used NMAP to scan and found that the state of port 25 is Filtered.
25/tcp filtered smtp
Why is port 25 detected on Windows.
any help please.

Related

Goroutine is blocked in execution [duplicate]

This question already has answers here:
Deadlock after attempting to print values of channel using 'range'
(3 answers)
Deadlock in the program when using for range on buffered channel
(1 answer)
Waiting for a WaitGroup and ranging over a channel results in a "fatal error: all goroutines are asleep - deadlock!"
(2 answers)
go routine for range over channels
(5 answers)
golang concurrency sync issue
(1 answer)
Closed 26 days ago.
I try to work on a piece of code with goroutine to scan open port on a subnet.
Here is the code :
package main
import (
"fmt"
"log"
"net"
"time"
)
func is_445_open(ip string, ch chan string){
connexion, err := net.DialTimeout("tcp", ip + ":445", 3*time.Second )
if err != nil {
return
}
defer connexion.Close()
ch <- ip
}
func ip_suivante(ip net.IP) {
for j := len(ip) - 1; j >= 0; j-- {
ip[j]++
if ip[j] > 0 {
break
}
}
}
func main() {
ch := make(chan string)
ipv4Addr, ipv4Net, err := net.ParseCIDR("200.31.0.0/24")
if err != nil {
log.Fatal(err)
}
for ipv4Addr := ipv4Addr.Mask(ipv4Net.Mask); ipv4Net.Contains(ipv4Addr); ip_suivante(ipv4Addr) {
//fmt.Println(ipv4Addr.String())
go is_445_open(ipv4Addr.String(), ch)
}
for v := range ch{
fmt.Println(v)
}
fmt.Println("Done")
}
I use ParseCIDR to loop over every IP of the network range then i connect to the port 445 to test if it is open.
To speed up the process, i want to use goroutine and write the ip where 445 is open to a channel.
Then loop over it to print them on the console.
When i use the loop to print every IP on my console the program never end.
It print the ip correctly but never the "done" at the end.
I have tried to close the channel before looping but when i do, no more data is printed and the program only show "done".
Do you have any tips ?
EDIT :
Finally figured out. You MUST put the code which manage the waitgroup and the channel closing into another goroutine to make it work.
Cannot undestand why.
But here is the code modified accordingly :
package main
import (
"fmt"
"log"
"net"
"time"
"sync"
)
func is_445_open(ip string, ch chan string, wg *sync.WaitGroup){
connexion, err := net.DialTimeout("tcp", ip + ":445", 3*time.Second )
if err != nil {
wg.Done()
return
}
defer connexion.Close()
ch <- ip
wg.Done()
}
func ip_suivante(ip net.IP) {
for j := len(ip) - 1; j >= 0; j-- {
ip[j]++
if ip[j] > 0 {
break
}
}
}
func main() {
wg := &sync.WaitGroup{}
ch := make(chan string)
ipv4Addr, ipv4Net, err := net.ParseCIDR("192.168.1.0/24")
if err != nil {
log.Fatal(err)
}
for ipv4Addr := ipv4Addr.Mask(ipv4Net.Mask); ipv4Net.Contains(ipv4Addr); ip_suivante(ipv4Addr) {
//fmt.Println(ipv4Addr.String())
wg.Add(1)
go is_445_open(ipv4Addr.String(), ch, wg)
}
go func(cha chan string, wg *sync.WaitGroup){
wg.Wait()
close(cha)
}(ch,wg)
for v := range ch{
fmt.Println(v)
}
fmt.Println("Done")
}

Peer to Peer UDP Sockets in Golang

I have a distributed application which sends messages among a number of peers. I've been switching over from TCP to UDP. I've seen that UDP can send and receive using a single socket so I've attempted to implement the application with each server containing a single socket.
I've set up a little piece of code to test this out but it returns EHOSTUNREACH (65) when attempting to invoke WriteToUDP on UDPC
Id // assumed to be a unique for the server
PeerAddrList // assumed to be a slice of all server locations (addr:port strings)
N // assumed to be the number of servers
laddr, _ := net.ResolveUDPAddr("udp", PeerAddrList[Id])
UDPC, er := net.ListenUDP("udp", laddr)
if er != nil {
panic(er)
}
for i := 0; i < N; i++ {
if i == int(Id) {
continue
}
i := i
go func() {
var b [4]byte
bs := b[:4]
binary.LittleEndian.PutUint32(bs, uint32(Id))
radddr, _ := net.ResolveUDPAddr("udp", PeerAddrList[i])
if _, er := UDPC.WriteToUDP(bs, radddr); er != nil {
panic(er)
}
}()
}
for i := 0; i < N; i++ {
if i == int(Id) {
continue
}
var b [4]byte
bs := b[:4]
_, raddr, e := UDPC.ReadFromUDP(bs)
if e != nil {
panic(e)
}
// check if laddr == id
id := int32(binary.LittleEndian.Uint32(bs))
log.Printf("Got id %d from %s", id, raddr.String())
}
Any advice on why this behaviour is different from what I expected, or how to fix it, would be greatly appreciated.
I discovered that the reason why the problem existed is that I was testing on my loopback address but didn't specify the address in PeerAddrList, only ":PORT". When giving addresses as "127.0.0.1:PORT" SendTo on the UDP socket worked

Why my Golang pressure measuring tool and Apache Batch generate different number of ESTABLISHED links?

Apache Batch is a popular pressure measuring tool.
I write a tool with the same function in golang myself. Then I make some tests.
I find it works well.
But accidentally, I find a difference from my tool and Apache Batch:
When checking ESTABLISHED link number by the cmd netstat -na|grep ESTABLISHED|wc -l:
Use cmd ab -n 128000 -c 128 http://127.0.0.1:8000/, the cmd above returns a number near 128.
But use my own tool, the cmd returns near 256 (when set concurrency 128).
Why my own tool have twice the expected number of concurrencies?
My code:
func request(cli *http.Client, uri string) {
resp, err := cli.Get(uri)
if err != nil {
panic(err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
panic("return" + strconv.Itoa(resp.StatusCode))
}
}
func workRoutine(ch chan string, wg *sync.WaitGroup) {
cli := &http.Client{}
for uri := range ch {
request(cli, uri)
}
wg.Done()
}
func main() {
rnum := 128
tnum := 128000
url := "http://127.0.0.1:8000/"
ch := make(chan string)
var wg sync.WaitGroup
go func() {
for i := 0; i < tnum; i++ {
ch <- url
}
close(ch)
}()
wg.Add(rnum)
for i := 0; i < rnum; i++ {
go workRoutine(ch, &wg)
}
stime := time.Now()
wg.Wait()
dtime := time.Now().Sub(stime)
fmt.Println("Timecost", dtime)
fmt.Println("Throughputs", float64(tnum)/dtime.Seconds())
}

goroutines/channel - not exiting w/o ctlr-c

Please consider the following go code, which I wrote to scan a TCP port (os.Arg[2]) of hostnames from a given filename (os.Arg[1]). It reads each hostname, tries to connect. If the connect failed, it would append the failed hostname to outfile.
package main
import(
"fmt"
"os"
"log"
"bufio"
"time"
"net"
)
func main(){
argc := len(os.Args)
if argc < 3 {
fmt.Printf("Invalid usage")
log.Fatal("Invalid usage")
}
stamp := time.Now().UnixNano()
outfile := fmt.Sprintf("%s%d.txt", "/tmp/port_check", stamp)
filename := os.Args[1]
file, err := os.Open(filename)
checkerr(err)
f, err := os.OpenFile(outfile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
checkerr(err)
defer f.Close()
port := os.Args[2]
channel := make(chan string,17)
fscanner := bufio.NewScanner(file)
for fscanner.Scan(){
_line := fscanner.Text()
go check_sender(_line,port,f,channel)
}
_count := 0
for out := range channel{
fmt.Println("_count is:", _count, out)
_count += 1
}
close(channel)
}
func checkerr(err error){
if err != nil {
fmt.Println(err)
log.Fatal(err)
}
}
func check_sender(sender string, port string, f *os.File, channel chan string){
address_string := fmt.Sprintf("%s:%s", sender, port)
_, err := net.DialTimeout("tcp", address_string,4 * time.Second)
if err != nil {
write_this := fmt.Sprintf("%s\n", sender)
f.WriteString(write_this)
}
channel <- sender
}
Generate some content for it operate on:
$ for i in `seq 1 5`; do echo "someblog$RANDOM$RANDOM.blogspot.com"; done > /tmp/meh.txt
And when run as:
$ go run port_scan.go /tmp/meh.txt 80
_count is: 0 someblog50063432.blogspot.com
_count is: 1 someblog922816893.blogspot.com
_count is: 2 someblog622823698.blogspot.com
_count is: 3 someblog1074223783.blogspot.com
_count is: 4 someblog1876411881.blogspot.com
^Csignal: interrupt < ----------------------- this
It hangs after the last hostname, and does not exit until a ctlr-c is sent.
I would like it to exit by itself, what am I doing wrong here?
update 1:
channel := make(chan string,17)
fscanner := bufio.NewScanner(file)
+ spin := 0
for fscanner.Scan(){
_line := fscanner.Text()
go check_sender(_line,port,f,channel)
+ spin += 1
}
_count := 0
for out := range channel{
fmt.Println("_count is:", _count, out)
_count += 1
+ if _count == spin {
+ close(channel)
+ }
}
- close(channel)
}

How to properly loop through buffered channel in this case?

I am trying to play around with go to make some kind of port scanner using the stdlib. This is more of an exercise than anything else, so please don't comment on the logic involved.
Looking at the following code:
package main
import (
"flag"
"fmt"
"net"
"time"
"strings"
"strconv"
"log"
"sync"
)
var commonPorts = map[int]string {
21: "ftp",
22: "sftp",
80: "http",
110: "pop3",
143: "imap",
443: "https",
631: "ipp",
993: "imaps",
995: "pop3s",
}
type OP struct {
mu sync.Mutex
ports []string
}
func (o *OP) SafeAdd(port string) {
o.mu.Lock()
defer o.mu.Unlock()
o.ports = append(o.ports, port)
}
func worker(host string, port int) string {
address := fmt.Sprintf("%s:%d", host, port)
conn, err := net.DialTimeout("tcp", address, time.Second * 3)
if err != nil {
return ""; // is offline, cannot connect
}
conn.Close()
stringI := strconv.Itoa(port)
if name, ok := commonPorts[port]; ok {
stringI += fmt.Sprintf("(%s)", name)
}
return stringI
}
func processWithChannels(host string) <-chan string{
openPort := make(chan string, 1000)
var wg sync.WaitGroup
for i := 1; i <= 65535; i++ {
wg.Add(1)
go func(openPort chan string, host string, i int) {
defer wg.Done()
port := worker(host, i)
if port != "" {
openPort <- port
}
}(openPort, host, i)
}
wg.Wait()
close(openPort)
return openPort
}
func main() {
var host = flag.String("host", "127.0.0.1", "please insert the host")
var pType = flag.Int("type", 2, "please insert the type")
flag.Parse()
fmt.Printf("Scanning: %s...\n", *host)
if _, err := net.LookupHost(*host); err != nil {
log.Fatal(err)
}
openPorts := &OP{ports: []string{}};
if *pType == 1 {
ports := processWithChannels(*host);
for port := range ports {
openPorts.SafeAdd(port)
}
} else {
var wg sync.WaitGroup
for i := 1; i <= 65535; i++ {
wg.Add(1)
go func(o *OP, host string, i int){
defer wg.Done()
if port := worker(host, i); port != "" {
o.SafeAdd(port)
}
}(openPorts, *host, i)
}
wg.Wait()
}
if len(openPorts.ports) > 0 {
fmt.Printf("Following ports are opened: %s\n", strings.Join(openPorts.ports, ", "))
} else {
fmt.Printf("No open port on the host: %s!\n", *host)
}
}
There are two ways of starting a scan, either by using a buffered channel or by using sync.GroupWait and bail out once all the scans are done.
It seems to me that in this case, using sync.GroupWait makes more sense than using a buffered channel and loop through it till it's empty. However, using a buffered channel here, i don't see a way to detect that there's nothing else on the channel and that i should bail out from the for loop, except by using another sync.WaitGroup block.
I think my question is, in case i want to use the buffered channel solution only, how do i implement it properly so that i know when the processing is done so that i can proceed with the rest of the code? (don't suggest timeouts please).
Here's also a small benchmark with the two types, in case anyone interested:
MacBook-Pro:PortScanner c$ time ./PortScanner -host yahoo.com -type 1
Scanning: yahoo.com...
Following ports are opened: 80(http), 143(imap), 110(pop3), 995(pop3s), 993(imaps)
real 0m4.620s
user 0m1.193s
sys 0m1.284s
MacBook-Pro:PortScanner c$ time ./PortScanner -host yahoo.com -type 2
Scanning: yahoo.com...
Following ports are opened: 110(pop3), 80(http), 143(imap), 995(pop3s), 993(imaps)
real 0m4.055s
user 0m1.051s
sys 0m0.946s
The call to processWithChannels will hang if you need to put more than 1000 items into the channel. If you're going to use a buffered channel to hold all values until processing, there has to be enough capacity to accept all values.
If you are going to collect all values into a single slice, then there's no reason to use a channel, and your second solution is just fine.
If you want to "stream" the ports back as soon as possible, then you need something in between the two solutions
ports := make(chan string)
var wg sync.WaitGroup
for i := 1; i <= 65535; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
if port := worker(*host, i); port != "" {
ports <- port
}
}(i)
}
go func() {
wg.Wait()
close(ports)
}()
for port := range ports {
fmt.Println("PORT:", port)
}
This however is likely to run into problems, like missing open ports when you dial all 65535 ports at the same time. Here is one possible pattern to use a pool of workers to dial concurrently:
ports := make(chan string)
toScan := make(chan int)
var wg sync.WaitGroup
// make 100 workers for dialing
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for p := range toScan {
ports <- worker(*host, p)
}
}()
}
// close our receiving ports channel once all workers are done
go func() {
wg.Wait()
close(ports)
}()
// feed the ports to the worker pool
go func() {
for i := 1; i <= 65535; i++ {
toScan <- i
}
// signal the workers to stop
close(toScan)
}()
for port := range ports {
if port != "" {
fmt.Println("PORT:", port)
}
}

Resources