c - 为 go 编译的程序禁用堆栈保护

标签 c security go compilation

我想为我的 Go 程序禁用堆栈保护。我正在尝试模拟一个易受攻击的 C 库,并希望从那里转向 Go 代码。但是,我似乎找不到合适的标志来禁用堆栈粉碎检测。

这是我的代码:

package main

import "os"
import "fmt"

/*
#include "test.h"
*/
import "C"

func main() {
    if (len(os.Args) >= 2){
    argsWithoutProg := os.Args[1:]
        if (argsWithoutProg[0] == "admin") {
            secret();
        }
    } else {
        regular()
    }
}

func regular() {
    fmt.Println("Go: BORING")
    C.hackme()
}

func secret() {
    fmt.Println("Go: SECRET FUNC")
}

这是我的 C 库代码:

// #cgo CFLAGS: -g -O3 -fno-stack-protector
#include <stdint.h>
#include <stdio.h>

void hackme();

// this function is vulnerable and is used as an entrypoint to the go part
void hackme() {
    char buf[3];
    int r;
    r = read(0, buf, 300);
    printf("C: %d bytes read. Content: %s!\n", r, buf);
    return;
}

我用 go build -a poc.go 编译。

如您所见,我已经在我的 C 库的开头添加了一些 CFLAGS 指令,但它们似乎没有帮助。以前我尝试通过编译命令中的 -gcflags 开关添加它们,但这也没有结果。每次我尝试用 300*A 字符串攻击我的程序时,它都会被检测到:

Go: BORING
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
C: 300 bytes read. Content: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!
*** stack smashing detected ***: <unknown> terminated
SIGABRT: abort
PC=0x7fd263dcee97 m=0 sigcode=18446744073709551610

goroutine 0 [idle]:
runtime: unknown pc 0x7fd263dcee97
stack: frame={sp:0x7ffda3507600, fp:0x0} stack=[0x7ffda2d08ad0,0x7ffda3507b00)
00007ffda3507500:  00007fd200000008  00007fd200000000
00007ffda3507510:  00007ffda3507610  0000000000000003 
[...]

用 GDB 检查文件也告诉我这个选项仍然有效.. 能否请您指出一些关于我做错了什么或我应该使用什么标志来禁用此功能的提示?

非常感谢!

最佳答案

从 Go cgo 命令文档开始。

Command cgo

Using cgo with the go command

To use cgo write normal Go code that imports a pseudo-package "C". The Go code can then refer to types such as C.size_t, variables such as C.stdout, or functions such as C.putchar.

If the import of "C" is immediately preceded by a comment, that comment, called the preamble, is used as a header when compiling the C parts of the package. For example:

// #include <stdio.h>
// #include <errno.h>
import "C"

The preamble may contain any C code, including function and variable declarations and definitions. These may then be referred to from Go code as though they were defined in the package "C". All names declared in the preamble may be used, even if they start with a lower-case letter. Exception: static variables in the preamble may not be referenced from Go code; static functions are permitted.

See $GOROOT/misc/cgo/stdio and $GOROOT/misc/cgo/gmp for examples. See "C? Go? Cgo!" for an introduction to using cgo: https://golang.org/doc/articles/c_go_cgo.html.

CFLAGS, CPPFLAGS, CXXFLAGS, FFLAGS and LDFLAGS may be defined with pseudo #cgo directives within these comments to tweak the behavior of the C, C++ or Fortran compiler. Values defined in multiple directives are concatenated together. The directive can include a list of build constraints limiting its effect to systems satisfying one of the constraints (see https://golang.org/pkg/go/build/#hdr-Build_Constraints for details about the constraint syntax). For example:

// #cgo CFLAGS: -DPNG_DEBUG=1
// #cgo amd64 386 CFLAGS: -DX86=1
// #cgo LDFLAGS: -lpng
// #include <png.h>
import "C"

特别是:

To use cgo write normal Go code that imports a pseudo-package "C".

If the import of "C" is immediately preceded by a comment, that comment, called the preamble, is used as a header when compiling the C parts of the package.

CFLAGS may be defined with pseudo #cgo directives within these comments to tweak the behavior of the C compiler.

以你的例子为例:

/*
#cgo CFLAGS: -g -O3 -fno-stack-protector
#include "test.h"
*/
import "C"

输出(未检测到堆栈粉碎):

$ go build -a poc.go && ./poc
Go: BORING
AAAAAAAAAAAAAAA
C: 16 bytes read. Content: AAAAAAAAAAAAAAA
!
fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0xa41414141 pc=0xa41414141]

runtime stack:
runtime.throw(0x4bb802, 0x2a)
    /home/peter/go/src/runtime/panic.go:608 +0x72
runtime.sigpanic()
    /home/peter/go/src/runtime/signal_unix.go:374 +0x2ec

goroutine 1 [syscall]:
runtime.cgocall(0x484e90, 0xc000052f38, 0x0)
    /home/peter/go/src/runtime/cgocall.go:128 +0x5b fp=0xc000052f08 sp=0xc000052ed0 pc=0x403deb
main._Cfunc_hackme()
    _cgo_gotypes.go:41 +0x41 fp=0xc000052f38 sp=0xc000052f08 pc=0x484c51
main.regular()
    /home/peter/gopath/src/poc/poc.go:25 +0x62 fp=0xc000052f88 sp=0xc000052f38 pc=0x484d52
main.main()
    /home/peter/gopath/src/poc/poc.go:19 +0x65 fp=0xc000052f98 sp=0xc000052f88 pc=0x484cd5
runtime.main()
    /home/peter/go/src/runtime/proc.go:201 +0x1ec fp=0xc000052fe0 sp=0xc000052f98 pc=0x42928c
runtime.goexit()
    /home/peter/go/src/runtime/asm_amd64.s:1340 +0x1 fp=0xc000052fe8 sp=0xc000052fe0 pc=0x450cd1
$

poc.go:

package main

import "os"
import "fmt"

/*
#cgo CFLAGS: -g -O3 -fno-stack-protector
#include "test.h"
*/
import "C"

func main() {
    if (len(os.Args) >= 2){
    argsWithoutProg := os.Args[1:]
        if (argsWithoutProg[0] == "admin") {
            secret();
        }
    } else {
        regular()
    }
}

func regular() {
    fmt.Println("Go: BORING")
    C.hackme()
}

func secret() {
    fmt.Println("Go: SECRET FUNC")
}

test.h:

#include <stdint.h>
#include <stdio.h>

void hackme();

// this function is vulnerable and is used as an entrypoint to the go part
void hackme() {
    char buf[3];
    int r;
    r = read(0, buf, 300);
    printf("C: %d bytes read. Content: %s!\n", r, buf);
    return;
}

没有-fno-stack-protector:

/*
#cgo CFLAGS: -g -O3
#include "test.h"
*/
import "C"

输出(检测到堆栈粉碎):

$ go build -a poc.go && ./poc
Go: BORING
AAAAAAAAAAAAAAA
C: 16 bytes read. Content: AAAAAAAAAAAAAAA
!
*** stack smashing detected ***: <unknown> terminated
SIGABRT: abort
PC=0x7f1c5323ee97 m=0 sigcode=18446744073709551610
$

关于c - 为 go 编译的程序禁用堆栈保护,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52651692/

相关文章:

c - 我想从 Rust 语言调用 C 库 "mysql.h"

security - 带有充气城堡的 scala 中的 AES-256 加密工作流程 : salt and IV usage and transfer/storage

web-services - Symfony2 通过网络服务对用户进行身份验证

heroku - 非本地包中的本地导入

c - c中单引号中两个字符的用法

c - 关于将 char 数组复制到 char 指针的基本 C 问题

c - 如何正确释放 malloc 的结构?

.net - 如何保护.NET应用程序中的API key

go - io.Copy写入: broken pipe for big file

java - 在 Eureka Server 中,发现和注册服务/应用程序不是在 Spring 中开发的