setgid/setuid在编译的Golang代码1.19上没有效果。

huangapple go评论80阅读模式
英文:

setgid/setuid has no effect on compiled golang code 1.19

问题

以下是翻译的内容:

➜ go version      
go version go1.19.6 linux/amd64

➜ uname -a
Linux dmitry-desktop 6.1.18-200.fc37.x86_64 #1 SMP PREEMPT_DYNAMIC Sat Mar 11 16:09:14 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

我无法使用可执行文件的 setuid/setguid 位运行编译的 Golang 应用程序。
我已经在可执行文件 main 上设置了 +s 权限,所有者是 test 用户。我尝试从 dmitry 用户调用该文件,期望文件会使用 test 的 uid,但实际上并没有发生。

[test@dmitry-desktop setguid]$ whoami
test
[test@dmitry-desktop setguid]$ id
uid=1001(test) gid=1002(test) groups=1002(test) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[test@dmitry-desktop setguid]$ ./main
[test@dmitry-desktop setguid]$ ls -la
total 1356
drwxrwxr-x.  2 test test     100 Mar 26 14:07 .
drwxrwxrwt. 48 root root    1780 Mar 26 14:07 ..
-rwsr-sr-x.  1 test test 1.9M Mar 26 14:16 main
-rw-r--r--.  1 test test     225 Mar 26 13:58 main.go
-rw-r--r--.  1 test test       9 Mar 26 14:07 test_file

[test@dmitry-desktop setguid]$ go build main.go 
[test@dmitry-desktop setguid]$ chmod u+s main
[test@dmitry-desktop setguid]$ chmod g+s main
[test@dmitry-desktop setguid]$ ls -la main
-rwsr-sr-x. 1 test test 1943252 Mar 26 14:18 main

[test@dmitry-desktop setguid]$ ./main 
Real UID: 1001
Effective UID: 1001
Real UID: 1001
Effective UID: 1001

现在我使用不同的用户运行相同的 main 文件

➜ whoami
dmitry

✗  /tmp/setguid/main     
Real UID: 1000
Effective UID: 1000
Real UID: 1000
Effective UID: 1000
panic: open /tmp/setguid/test_file: permission denied

goroutine 1 [running]:
main.check(...)
	/tmp/setguid/main.go:14
main.main()
	/tmp/setguid/main.go:32 +0xe5

main.go

package main

import (
    "os"
    "syscall"
    "log"
    "fmt"
    "time"
    
)

func check(e error) {
    if e != nil {
        panic(e)
    }
}

func main() {

    printdelay()

    errgid := syscall.Setuid(syscall.Getuid())
    if errgid != nil {
        log.Fatal(errgid)
        os.Exit(1)
    }

    printdelay()

    d1 := []byte("hello\ngo\n")
    err := os.WriteFile("/tmp/setguid/test_file", d1, 0644)
    check(err)
}

func printdelay() {
    fmt.Printf("Real UID: %d\n", syscall.Getuid())
    fmt.Printf("Effective UID: %d\n", syscall.Geteuid())
    time.Sleep(7 * time.Second)
}

然后我尝试了以下操作:

sudo /sbin/setcap cap_setuid=ep main
chown root:root main
chmod +s main
ls -la main
-rwsr-sr-x. 1 root root 1943124 Mar 26 14:28 main

然后我修改了我的 go 文件

// errgid := syscall.Setuid(syscall.Getuid())
   errgid := syscall.Setuid(1001)

并尝试调用它:

✗  id
uid=1000(dmitry) gid=1000(dmitry) groups=1000(dmitry),10(wheel),969(plugdev),971(wireshark),975(docker) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c102

➜ ./main        
Real UID: 1000
Effective UID: 1000
2023/03/26 14:33:04 operation not permitted

我错过了什么?

英文:
➜ go version      
go version go1.19.6 linux/amd64

➜ uname -a
Linux dmitry-desktop 6.1.18-200.fc37.x86_64 #1 SMP PREEMPT_DYNAMIC Sat Mar 11 16:09:14 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

I am unable to run compiled golang app using setuid/setguid bits of the executable file.
I have set +s permission on the executable main file, owned by test user. I'm trying to invoke that file from dmitry user expecting the file would use test uid, but it's not happening.

[test@dmitry-desktop setguid]$ whoami
test
[test@dmitry-desktop setguid]$ id
uid=1001(test) gid=1002(test) groups=1002(test) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[test@dmitry-desktop setguid]$ ./main
[test@dmitry-desktop setguid]$ ls -la
total 1356
drwxrwxr-x.  2 test test     100 Mar 26 14:07 .
drwxrwxrwt. 48 root root    1780 Mar 26 14:07 ..
-rwsr-sr-x.  1 test test 1.9M Mar 26 14:16 main
-rw-r--r--.  1 test test     225 Mar 26 13:58 main.go
-rw-r--r--.  1 test test       9 Mar 26 14:07 test_file

[test@dmitry-desktop setguid]$ go build main.go 
[test@dmitry-desktop setguid]$ chmod u+s main
[test@dmitry-desktop setguid]$ chmod g+s main
[test@dmitry-desktop setguid]$ ls -la main
-rwsr-sr-x. 1 test test 1943252 Mar 26 14:18 main

[test@dmitry-desktop setguid]$ ./main 
Real UID: 1001
Effective UID: 1001
Real UID: 1001
Effective UID: 1001

now I run the same main from a different user

➜ whoami
dmitry

✗  /tmp/setguid/main     
Real UID: 1000
Effective UID: 1000
Real UID: 1000
Effective UID: 1000
panic: open /tmp/setguid/test_file: permission denied

goroutine 1 [running]:
main.check(...)
	/tmp/setguid/main.go:14
main.main()
	/tmp/setguid/main.go:32 +0xe5

main.go

package main

import (
    "os"
    "syscall"
    "log"
    "fmt"
    "time"
    
)

func check(e error) {
    if e != nil {
        panic(e)
    }
}

func main() {

    printdelay()

    errgid := syscall.Setuid(syscall.Getuid())
    if errgid != nil {
        log.Fatal(errgid)
        os.Exit(1)
    }

    printdelay()

    d1 := []byte("hello\ngo\n")
    err := os.WriteFile("/tmp/setguid/test_file", d1, 0644)
    check(err)
}

func printdelay() {
    fmt.Printf("Real UID: %d\n", syscall.Getuid())
    fmt.Printf("Effective UID: %d\n", syscall.Geteuid())
    time.Sleep(7 * time.Second)
}

then I tried the following:

sudo /sbin/setcap cap_setuid=ep main
chown root:root main
chmod +s main
ls -la main
-rwsr-sr-x. 1 root root 1943124 Mar 26 14:28 main

then I modify my go file to

// errgid := syscall.Setuid(syscall.Getuid())
   errgid := syscall.Setuid(1001)

and trying to invoke it:

✗  id
uid=1000(dmitry) gid=1000(dmitry) groups=1000(dmitry),10(wheel),969(plugdev),971(wireshark),975(docker) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c102

➜ ./main        
Real UID: 1000
Effective UID: 1000
2023/03/26 14:33:04 operation not permitted

what am I missing?

答案1

得分: 1

您没有提到在修改源代码后是否重新构建了 main。我认为您已经重新构建了。请注意,在重新构建后,main 的所有者和文件能力可能会发生变化。我还认为您在重新构建后运行了 setcapchown 命令。请编辑问题以列出真实的步骤。

所以我认为这里的问题是 chown 命令会改变文件的能力。您应该在 chown 之后运行 setcap。请参考下面的命令和输出:

$ getcap main  # 首先,没有文件能力
$ sudo setcap cap_setuid=ep main
$ getcap main  # 现在添加了文件能力 "cap_setuid=ep"
main cap_setuid=ep
$ sudo chown root:root main
$ getcap main  # <== "chown" 后没有文件能力
$ ./main
Real UID: 1000
Effective UID: 1000
2023/03/27 16:43:58 operation not permitted
$ sudo setcap cap_setuid=ep main
$ getcap main  # 恢复文件能力
main cap_setuid=ep
$ ./main
Real UID: 1000
Effective UID: 1000
Real UID: 1001
Effective UID: 1001
英文:

> ### then I tried the following:
>
>
&gt; sudo /sbin/setcap cap_setuid=ep main
&gt; chown root:root main
&gt; chmod +s main
&gt; ls -la main
&gt; -rwsr-sr-x. 1 root root 1943124 Mar 26 14:28 main
&gt;

>
> then I modify my go file to
>
>
&gt; // errgid := syscall.Setuid(syscall.Getuid())
&gt; errgid := syscall.Setuid(1001)
&gt;

>
> and trying to invoke it:

You do not mention whether you have rebuilt main after modifying the source code. I believe you have. Please note that the owner and file capabilities of main could be changed after the rebuild. I also believe that you have run the setcap and chown commands after the rebuild. Please edit the question to list the real steps.

So I think the issue here is that the command chown will change the file capabilities. You should run setcap after chown. See the commands and the output below:

$ getcap main  # at first, no file capabilities
$ sudo setcap cap_setuid=ep main
$ getcap main  # now the file capability &quot;cap_setuid=ep&quot; is added
main cap_setuid=ep
$ sudo chown root:root main
$ getcap main  # &lt;== no file capabilities after &quot;chown&quot;
$ ./main
Real UID: 1000
Effective UID: 1000
2023/03/27 16:43:58 operation not permitted
$ sudo setcap cap_setuid=ep main
$ getcap main  # bring back the file capability
main cap_setuid=ep
$ ./main
Real UID: 1000
Effective UID: 1000
Real UID: 1001
Effective UID: 1001

答案2

得分: 0

首先,在尝试任何操作之前,你必须确保存储main二进制文件的位置位于支持以特权运行的文件系统上。假设你想将其存储在/tmp/目录中,那么哪些挂载选项适用于该目录?

$ findmnt -v -T /tmp
TARGET SOURCE FSTYPE OPTIONS
/tmp   tmpfs  tmpfs  rw,nosuid,nodev,seclabel,size=32756364k,nr_inodes=1048576,in

这里的nosuid选项意味着即使你可以在该目录下更改文件的特权位(setuid或capabilities),内核在运行程序时也不会遵守这些设置。根据你问题中的细节,我认为这很可能是你遇到的问题。

此外,对于一个程序来说,设置了setuid-root会完全覆盖文件的capabilities。因此,你对二进制文件添加特权的尝试是多余的。它唯一能获得的特权来自setuid-root部分。

如果你找到一个可以写入的目录,而且该目录没有挂载nosuid选项,你可以使用它。如果一切都失败了:sudo mkdir /hack ; sudo chmod go+w /hack ; findmnt -v -T /hack将提供一个稍后可以清理的目录。

在这个目录中,你可以复制你的二进制文件,然后选择以下配置之一:

$ cd /hack
$ sudo /sbin/setcap cap_setuid=ep main
$ /sbin/getcap main
main cap_setuid=ep

或者执行以下操作:

$ cd /hack
$ sudo chown root.root main
$ sudo chmod +s main
$ ls -l main
-rwsr-sr-x. 1 root root 1943124 Mar 26 14:28 main
英文:

First, before you try anything, you have to be sure the place you are storing your main binary is on a filesystem that supports it running with privilege. Let's say, you want to store it in /tmp/, what mount options cover that directory?

$ findmnt -v -T /tmp
TARGET SOURCE FSTYPE OPTIONS
/tmp   tmpfs  tmpfs  rw,nosuid,nodev,seclabel,size=32756364k,nr_inodes=1048576,in

The option nosuid here means that even though you can change the privilege bits on the file (setuid or capabilities) under that directory, they will not be honored by the kernel when the program is run. Based on the details in your question, I think this is likely to be the problem you are experiencing.

Further, setuid-root on a program completely overrides file capabilities. So your attempts to add privilege to your binary are redundant. The only privilege it will get is from the setuid-root part.

If you find a directory that you can write to that is mounted without the nosuid option, you can use that. If all else fails: sudo mkdir /hack ; sudo chmod go+w /hack ; findmnt -v -T /hack will provide something you can clean up later.

In this directory, you can copy your binary, then pick one of the following to configure it:

$ cd /hack
$ sudo /sbin/setcap cap_setuid=ep main
$ /sbin/getcap main
main cap_setuid=ep

Or do this:

$ cd /hack
$ sudo chown root.root main
$ sudo chmod +s main
$ ls -l main
-rwsr-sr-x. 1 root root 1943124 Mar 26 14:28 main

huangapple
  • 本文由 发表于 2023年3月27日 03:35:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/75850102.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定