Reputation: 143
I want to disable the stack protection for my Go program. I'm trying to simulate a vulnerable C library and want to pivot into the Go code from there. However, I can't seem to find the right flags to disable the stack smashing detection.
Here is my go code:
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")
}
and here is my c library code:
// #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;
}
I compile with go build -a poc.go
.
As you can see, I already added some CFLAGS instructions at the beginning of my C library, but they don't seem to help. Previously I tried adding them via the -gcflags
switch in my compilation command, but that was fruitless as well. Everytime I try to attack my program with a 300*A string, it is being detected:
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
[...]
Checking the file with GDB also tells me the option is still active.. Could you please point me to some hints as to what I'm doing wrong or what flags I should use to disable this feature?
Thanks so much!
Upvotes: 1
Views: 1659
Reputation: 166815
Start with the Go cgo command documentation.
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"
In particular:
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.
For your example:
/*
#cgo CFLAGS: -g -O3 -fno-stack-protector
#include "test.h"
*/
import "C"
Output (no stack smashing detected):
$ 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;
}
Without -fno-stack-protector
:
/*
#cgo CFLAGS: -g -O3
#include "test.h"
*/
import "C"
Output (stack smashing detected):
$ 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
$
Upvotes: 2