今日Golang发布一个安全版本(Go 1.15.7 和Go 1.14.14),解决了涉及在不受信任目录中进行PATH查找的问题CVE-2021-3115,相关的问题会导致执行go get命令时远程执行。关于该问题Golang官方博客进行了介绍,我们来学习下。

go命令和远程执行

golang语言的go命令设计目标是用来执行大量的操作,包括go build,go doc,go get,go install,以及go list,他们可以从互联网上下载但是不会运行任意代码。但是还有几个命令,比如go run,go test以及go generate可以直接运行任意代码,包括可复制的版本和安全性。因此,当go get可以被诱骗执行任意代码时,这是一个安全漏洞。

如果go get不能运行任意代码,那么其调用的所有程序,例如编译器和版本控制系统,也都在安全范围内。例如,过去曾经遇到过这样的问题,即在版本控制系统中巧妙地使用晦涩的编译器功能或远程执行漏洞,导致Go中的远程执行。

Go命令和PATH路径

所有操作系统都有一个可执行路径PATH的概念(在类Unix系统上是用$PATH定义,Windows上为%PATH%)。它是一些可执行文件保存目录的列表。在shell提示符下输入命令时,shell依次在列出的每个目录中查找具有该名称的可执行文件,然后运行找到的第一个命令,如果编译列表找不到该名称,就会报错 "找不到命令"。

-bash: XXX: command not found

Bourne shell手册说明中:

shell参数$PATH定义包含命令的目录的搜索路径。每个备用目录名称都用冒号(:)分隔。预设路径为:/bin:/usr/bin。如果命令名称中包含/,则不使用搜索路径。否则,将在PATH中的各个目录中搜索可执行文件。

默认值:当前目录(.)在/bin和之前列出/usr/bin。MS-DOS和Windows中是硬编码了这个行为:在windows下会首先自动搜索当前目录(.),然后再搜索%PATH%列出的目录。

PATH设置的系统目录之前先搜索当前目录,这样如果cd进入目录并运行ls,则可能会从当前目录中执行恶意副本,而不是系统程序。而且,如果可以欺骗系统管理员以ls身份登录时,其他用户主目录root中运行,那么也可以运行所需的任何代码。由于这个问题和其他类似的问题,基本上所有现代*nix发行版都将默认PATH设置中排除当前目录(即.)。但是,在Windows中,默认是首先搜索当前目录(.)。例如,当输入go version命令时,默认配置的*nix上,shell都从PATH中的系统目录运行go可执行文件。但是,在Windows上键入输入该命令时,cmd.exe会首先检查当前目录(.),如果存在.go.exe(或.go.bat等等),cmd.exe就会先运行这个可执行文件(.go.exe),而不是PATH中路径设定的系统go编译器。

对于Golang,PATH搜索由exec.LookPath自动处理exec.Command。为了很好地适应主机系统,Goland的exec.LookPath在*nix上和Windows各自通过调用底层的系统的规则来实现。下面的命令:

out, err := exec.Command("go", "version").CombinedOutput()

行为与在操作系统shell中直接执行go version命令是一样的。

在Windows上,如果当前目录存在.go.exe,就会优先运行。

漏洞解析

当go get下载并构建一个包含包 import "C",它会运行cgo程序来处理golang中的有关C代码。cgo命令在包含软件包源的目录中运行。一旦cgo已经产生其转到输出文件,go命令会调用所生成的文件转交给主机C编译器(gcc或clang编译器)来构建引入到包中的C源码。

为了调用C编译器,go命令需要通过系统PATH来查找。但是如果在程序包源目录中运行C编译器时,它将从go调用命令的原始目录中查找:

cmd := exec.Command("gcc", "file.c")

cmd.Dir = "badpkg"

cmd.Run()

因此,即使Windows系统上存在badpkggcc.exe,也找不到它。exec.Command进行PATH搜寻时候不包括badpkg目录。

go命令使用类似的代码来调用cgo,但是不会有路径查找,因为cgo总是来自于GOROOT:

cmd := exec.Command(GOROOT+"/pkg/tool/"+GOOS_GOARCH+"/cgo", "file.go")

cmd.Dir = "badpkg"

cmd.Run()

这第一段代码看起来更加安全,没有运行存在的问题的cgo.exe可能。

但是,实际上cgo本身还需要在它创建的某些临时文件上调用宿主的C编译器,这样,它还要执行以下代码:

cmd := exec.Command("gcc", "tmpfile.c")

cmd.Run()

由于cgo运行时,当前目录就是badpkg,而不是go运行命令的目录,因此如果badpkggcc.exe存在,就会被调用执行,而不会再去PATH中查找系统的gcc。

因此,攻击者可以创建一个使用cgo并包含的恶意程序gcc.exe的打包,当用户通过go get以下载并build的时候,Windows用户会就会优先于系统路径中的gcc先执行这个恶意的gcc.exe,从而导致的远程执行漏洞。

*nix系统由于从根本上就不包括当前目录,所以不会受到影响。并且由于golang模块解包时不会对其写入的文件设置执行位,所以默认是无法执行的。

但是,如果系统设置时候,手动PATH中增加"."路径,并且使用GOPATH模式的用户也会受到影响。

漏洞修复

上面说了,可能的风险就是下载并执行恶意的gcc.exe。那么如何解决呢?

一个可能的解决方法:由于cgo在不受信任的源目录中而不是在go调用命令的目录中C编译器,这会导致问题。那么解决我们通过更改go命令,将cgo完整路径传递给主机C编译器,让cgo无需在不受信任的目录中进行PATH查找。

由于问题出在PATH查找时候的查找当前路径(.),无论在Windows上自动发生还是由于在*nix系统上显式的设置当前路径(.)的PATH。用户可能希望在当前目录中查找以找到在控制台或shell程序窗口中键入的命令,但是一般不会希望查找键入的命令的子命令。那么解决方法就是更改cgo 的PATH查找过程中不包括当前目录(.)。

golang的新版本中对这两方面都予以了修复。go命令会把完整的主机C编译器路径传递给cgo。最重要的是,go和cgo转到命令现在使用的一个变种os/exec,如果将以前使用的当前目录(.)的可执行文件,会报错误。这些go程序包go/build命令和其他工具go/import使用相同的策略。出于谨慎考虑,还对诸如goimports和gopls命令以及golang.org/x/tools/go/analysis和golang.org/x/tools/go/packages库进行了类似的修复,这些库将命令作为子进程调用。

更新到新的Go版本后,可以gopls使用以下方法更新到最新版本:

GO111MODULE=on

go get golang.org/x/tools/gopls@v0.6.4

使用以下方法更新到最新版的goimports工具或其他工具:

GO111MODULE=on

go get golang.org/x/tools/cmd/goimports@v0.1.0

在golang.org/x/tools/go/packages通过在以下过程中添加对依赖关系的显式升级来更新依赖于的程序:

GO111MODULE=on

go get golang.org/cmd/thecmd golang.org/x/tools@v0.1.0

对于使用的程序,go/build 就可以使用更新的Go版本重新编译它们。

同样,仅当是Windows用户或*nix用户且PATH中手动设置了.并且在不信任的源目录中运行这些程序(可能包含恶意程序)时,才需要更新这些程序。

如果代码中使用了exec.LookPath或exec.Command,则需要关注在不受信任内容的目录中运行程序。可以使用os/execas替换:

import "os/exec"

import exec "golang.org/x/sys/execabs"

并重新编译。

设置go path_Go命令的PATH安全性相关推荐

  1. linux设置用户的执行权限,Linux下ACL权限控制以及用sudo设置用户对命令的执行权限...

    ACL权限分配 1.setfacl命令设置文件权限 setfacl -m u:user1:rw root.txt setfacl -m u:user2:rwx root.txt 2.getfacl命令 ...

  2. MySQL导入sql脚本中文乱码设置和常用命令

    MySQL导入sql脚本中文乱码设置和常用命令 1. use database_name;  2. set names utf8; (或其他需要的编码)  3. source example.sql ...

  3. windows 设置mvn 本地命令

    windows 设置mvn 本地命令 编辑系统环境变量: 新建 名称:MAVEN_HOME 变量:盘符到maven主目录下 例如:E:\apache-maven-3.0.4 编辑 名称:path 新建 ...

  4. Linux设置界面或命令行启动

    设置界面或命令行启动 以root的身份登陆,然后执行: #cd /etc #vi inittab 更改"id:5:initdefault:"语句即可. 其中5表示默认图形启动界面 ...

  5. Linux下ACL权限控制以及用sudo设置用户对命令的执行权限

    ACL权限分配 1.setfacl命令设置文件权限 setfacl -m u:user1:rw root.txt setfacl -m u:user2:rwx root.txt 2.getfacl命令 ...

  6. QNX设置开机启动命令来修改IP地址

    2019独角兽企业重金招聘Python工程师标准>>> 在控制台使用命令行修改QNX系统IP地址: # ifconfig en0 192.168.0.156 查询IP地址: # if ...

  7. 常用DOS命令和Path环境变量的配置

    常用DOS命令和Path环境变量的配置 1 常用DOS命令 1.1 打开命令提示符窗口 1.2 常用DOS命令 2 Path环境变量的配置 2.1 为什么要配置Path环境变量 2.2 配置流程 2. ...

  8. 设置 Linux 别名命令 alias 永久生效的方法

    直入主题,编辑.bashrc文件,该文件主要用于保存一些个性化的设置,如命令别名.路径等: vim .bashrc 执行上述命令后,如下图所示: 如上图所示,我们可以在User specific al ...

  9. Cadence Allegro如何设置stroke快捷命令

    **Cadence Allegro如何设置stroke快捷命令** 在运用Cadence Allegro设计PCB过程中我们需要不断的提高设计效率,只能不断的摸索各方面的技巧,设置ENV快捷键文集和设 ...

最新文章

  1. 自适应_自适应信号分解综述
  2. 趋势修改服务器地址,趋势客户端修改连接服务器
  3. 蓝桥杯来了?最后节点了,这不得共享一波资源?
  4. 世道变了!这个AI竞赛不再要刷榜成绩,直接看商业落地计划书
  5. Qt QDialog将窗体变为顶层窗体(activateWindow(); 和 raise() )
  6. 利用 Arthas 精准定位 Java 应用 CPU 负载过高问题
  7. mysql解压版下载安装教程_mysql 解压版安装配置方法教程
  8. 新晋“网红”Cat1 是什么
  9. 第15章 音乐可视化(《Python趣味创意编程》教学视频)
  10. 极限3秒钟,闪存能作什么?
  11. JavaScript面向对象之Object类型
  12. lol最新聊天服务器断开,lol聊天服务器断开 英雄联盟聊天服务器连不上解决办法...
  13. 怎么用电脑录音,在电脑上录制音频的方法
  14. 1999年秋浙江省计算机等级考试二级c 编程题,2004年秋浙江省计算机等级考试二级C 编程题(2) (C++代码)...
  15. Linux cat命令
  16. MODBUS-RTU协议主机和从机代码STM32 包含2个程序代码,主机和从机
  17. 谷歌FLAN-T5作者亲讲:5400亿参数,1800个任务,如何实现大语言模型“自我改进”...
  18. xmanager5链接linux配置,使用Xmanager连接CentOS 5.5
  19. 文字图片行内垂直居中对齐方法
  20. AIDA64如何设置小屏监控 AIDA64监控CPU功耗

热门文章

  1. EntLib 3.1学习笔记(2) : Data Access Application Block
  2. 将阿拉伯数字转换成中文大写的好算法
  3. CCF201512-1 数位之和
  4. PAT乙级(1012 数字分类)
  5. flyway版本号_Spring Boot 集成 Flyway 实现数据库版本控制
  6. python导入类属性不存在_为什么我会得到一个错误:我的类中不存在该属性?
  7. 定积分华里士公式推广_数学分析第九章《定积分》备考指南
  8. MogDB数据库高可用及负载均衡JDBC参数测试
  9. 一位Oracle老司机的openGauss初体验
  10. 直播预告丨云时代的数据库客户端——CloudQuery最佳实践