自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

當(dāng)git遇上ssh——CVE-2017-1000117漏洞淺析

安全 應(yīng)用安全
Git是一個開源的分布式版本控制系統(tǒng),主要用于項目管理。而SSH是一種應(yīng)用層的安全通信協(xié)議,最常用的就是為通信雙方在在不安全網(wǎng)絡(luò)上提供安全的遠(yuǎn)程登錄。當(dāng)他們二者相遇會發(fā)生什么有趣的事呢?這里以CVE-2017-1000117漏洞為例,簡要剖析該漏洞的成因及防護方法。

Git是一個開源的分布式版本控制系統(tǒng),主要用于項目管理。

而SSH是一種應(yīng)用層的安全通信協(xié)議,最常用的就是為通信雙方在在不安全網(wǎng)絡(luò)上提供安全的遠(yuǎn)程登錄。

當(dāng)他們二者相遇會發(fā)生什么有趣的事呢?這里以CVE-2017-1000117漏洞為例,簡要剖析該漏洞的成因及防護方法。

Git

漏洞相關(guān)信息:

版本控制軟件爆出遠(yuǎn)程命令執(zhí)行漏洞 涉及Git、SVN、Mercurial、CVS版本控制

簡述:幾個流行的版本控制系統(tǒng)受到可能嚴(yán)重的遠(yuǎn)程命令執(zhí)行漏洞的影響。受影響產(chǎn)品的開發(fā)人員本周發(fā)布了更新補丁來修補安全漏洞。該缺陷影響版本控制軟件, 如 Git (CVE-2017-1000117)、Apache Subversion (CVE-2017-9800)、Mercurial (CVE-2017-1000116) 和 CVS。由于CVS 系統(tǒng)上次更新已經(jīng)是9年前的事情了, 因此沒有為它分配 CVE 標(biāo)識符。

背景知識

ssh客戶端登錄時,有一個ProxyCommand選項,該選項的指定鏈接服務(wù)器時執(zhí)行的命令。

  1. ProxyCommand 
  2.  
  3.    Specifies the command to use to connect to the server.  The 
  4.  
  5.    command string extends to the end of the line, and is executed 
  6.  
  7.    with the user’s shell.  In the command string, any occurrence 
  8.  
  9.    of ‘%h’ will be substituted by the host name to connect,‘%p’ 
  10.  
  11.    by the port, and ‘%r’ by the remote user name. 

該選項常用的場景是通過代理服務(wù)器與目標(biāo)機器相連,因此被稱作ProxyCommand,如下圖。

本地的機器(Local)無法直接與目標(biāo)機器(Target)相連,必須通過一個代理機器(Proxy)才能和目標(biāo)機器建立連接。此場景多見于企業(yè)或有較強訪問控制的需求的地方。

因此在這種情況下,ssh客戶端可以采用ProxyCommand選項,通過下面命令最終和目標(biāo)機器建立連接。

  1. ssh -o ProxyCommand=’ssh user@proxy nc %h 22′ user@Target 

加上ProxyCommand選項后。ssh客戶端會先用當(dāng)前用戶的shell執(zhí)行ProxyCommand中的內(nèi)容。

例如下面的命令,在Linux桌面環(huán)境中執(zhí)行,就會彈出gedit文本編輯器。

  1. ssh -oProxyCommand=gedit user@Target 

即便最后的user@hostname不合法,也不會影響ProxyCommand中先執(zhí)行的命令,照樣可以彈出gedit。

好了介紹完了ProxyCommand,可以理解為這個選項如處理不當(dāng),是可以進行命令注入的!

CVE-2017-1000117漏洞

CVE-2017-1000117這個漏洞就是沒有正確處理ssh鏈接的請求,導(dǎo)致受害人通過Git版本控制系統(tǒng),訪問惡意鏈接時,存在安全隱患,一旦黑客攻擊成功,可在受害人機器上執(zhí)行任意命令。

git clone是Git版本控制系統(tǒng)中常用的將遠(yuǎn)程倉庫克隆到本地的命令。當(dāng)使用git clone訪問下面的惡意ssh鏈接時,會在本地執(zhí)行命令,彈出gedit。

  1. git clone ssh://-oProxyCommand=”gedit /tmp/xxx” 

下面我們來詳細(xì)看一看其中的過程,當(dāng)git遇上ssh后,最終是如何觸發(fā)這個漏洞執(zhí)行的。

 

git客戶端在執(zhí)行上面的命令后,通過一系列的參數(shù)解析后,進入git_connect函數(shù),向git的服務(wù)端建立連接。

  1. struct child_process *git_connect(int fd[2], const char *url, 
  2. const char *prog, int flags) 
  3.  
  4.  
  5. char *hostandport, *path; 
  6.  
  7. struct child_process *conn = &no_fork; 
  8.  
  9. enum protocol protocol; 
  10.  
  11. struct strbuf cmd = STRBUF_INIT
  12.  
  13.   
  14.  
  15. /* Without this we cannot rely on waitpid() to tell 
  16.  
  17. * what happened to our children. 
  18.  
  19. */ 
  20.  
  21. signal(SIGCHLD, SIG_DFL); 
  22.  
  23.   
  24.  
  25. protocol = parse_connect_url(url, &hostandport, &path); 
  26.  
  27. if ((flags & CONNECT_DIAG_URL) && (protocol != PROTO_SSH)) { 
  28.  
  29. printf(“Diag: url=%s\n”, url ? url : “NULL”); 
  30.  
  31. printf(“Diag: protocol=%s\n”, prot_name(protocol)); 
  32.  
  33. printf(“Diag: hostandport=%s\n”, hostandport ? hostandport : “NULL”); 
  34.  
  35. printf(“Diag: path=%s\n”, path ? path : “NULL”); 
  36.  
  37. conn = NULL
  38.  
  39. } else if (protocol == PROTO_GIT) { 
  40.  
  41. ….. 
  42.  
  43. } else { 
  44.  
  45. conn = xmalloc(sizeof(*conn)); 
  46.  
  47. child_process_init(conn); 
  48.  
  49.   
  50.  
  51. strbuf_addstr(&cmd, prog); 
  52.  
  53. strbuf_addch(&cmd, ‘ ‘); 
  54.  
  55. sq_quote_buf(&cmd, path); 
  56.  
  57.   
  58.  
  59. /* remove repo-local variables from the environment */ 
  60.  
  61. conn->env = local_repo_env
  62.  
  63. conn->use_shell = 1
  64.  
  65. conn->in = conn->out = -1; 
  66.  
  67. if (protocol == PROTO_SSH) { 
  68.  
  69. const char *ssh; 
  70.  
  71. int putty = 0tortoiseplink = 0
  72.  
  73. char *ssh_host = hostandport
  74.  
  75. const char *port = NULL
  76.  
  77. transport_check_allowed(“ssh”); 
  78.  
  79. get_host_and_port(&ssh_host, &port); 
  80.  
  81.   
  82.  
  83. if (!port) 
  84.  
  85. port = get_port(ssh_host); 
  86.  
  87.   
  88.  
  89. ssh = getenv(“GIT_SSH_COMMAND”); 
  90.  
  91. if (!ssh) { 
  92.  
  93. const char *base; 
  94.  
  95. char *ssh_dup; 
  96.  
  97. /* 
  98.  
  99. * GIT_SSH is the no-shell version of 
  100.  
  101. * GIT_SSH_COMMAND (and must remain so for 
  102.  
  103. * historical compatibility). 
  104.  
  105. */ 
  106.  
  107. conn->use_shell = 0
  108.  
  109.   
  110.  
  111. ssh = getenv(“GIT_SSH”); 
  112.  
  113. if (!ssh) 
  114.  
  115. ssh = “ssh”; 
  116.  
  117.   
  118.  
  119. ssh_dup = xstrdup(ssh); 
  120.  
  121. base = basename(ssh_dup); 
  122.  
  123.   
  124.  
  125. free(ssh_dup); 
  126.  
  127.  
  128.   
  129.  
  130. argv_array_push(&conn->args, ssh); 
  131.  
  132.   
  133.  
  134. if (port) { 
  135.  
  136. /* P is for PuTTY, p is for OpenSSH */ 
  137.  
  138. argv_array_push(&conn->args, putty ? “-P” : “-p”); 
  139.  
  140. argv_array_push(&conn->args, port); 
  141.  
  142.  
  143. argv_array_push(&conn->args, ssh_host); 
  144.  
  145. } else { 
  146.  
  147. transport_check_allowed(“file”); 
  148.  
  149.  
  150. argv_array_push(&conn->args, cmd.buf); 
  151.  
  152.   
  153.  
  154. if (start_command(conn)) 
  155.  
  156. die(“unable to fork”); 
  157.  
  158.   
  159.  
  160. ….. 
  161.  
  162.  
  163.   
  164.  

git_connect函數(shù)的第二個參數(shù)url,即為傳入的ssh鏈接,在此例中為 “ssh://-oProxyCommand=gedit /tmp/xxx”。

在git_connect函數(shù)中通過parse_connect_url函數(shù)將待連接的url解析出來,返回url的主機名、相對路徑及url采用的協(xié)議。

 

https://github.com/git/git/blob/master/connect.c#L620

  1. /* 
  2.  
  3. * Extract protocol and relevant parts from the specified connection URL. 
  4.  
  5. * The caller must free() the returned strings. 
  6.  
  7. */ 
  8.  
  9. static enum protocol parse_connect_url(const char *url_orig, char **ret_host,  char **ret_path) 

對于正常的ssh鏈接,如 ssh://user@host.xzy/path/to/repo.git/,經(jīng)parse_connect_url解析后,其返回的ret_host和ret_path的值應(yīng)該為 user@host.xzy 和 /path/to/repo.git/ 。

但由于沒有對ssh做正確過濾及識別,對于惡意的ssh鏈接,返回的ret_host和ret_path的值則是 -oProxyCommand=gedit 和 /tmp/xxx ,誤將 -oProxyCommand=gedit 作為了主機名ret_host。

在后續(xù)處理中,git_connect得到本地ssh的路徑,將上面獲取的ssh host和path填充到struct child_process *conn中,再通過start_command調(diào)用本地ssh執(zhí)行。

在start_command函數(shù)中,最終調(diào)用exec系列函數(shù)執(zhí)行ssh,由于錯誤的把 -oProxyCommand=gedit 作為遠(yuǎn)程待連接的host,最終引發(fā)了命令執(zhí)行。

但像上面ssh://-oProxyCommand=”gedit /tmp/xxx”的鏈接比較暴露,直接在鏈接中就出現(xiàn)命令。比較隱蔽的方法是,在正常倉庫的目錄下建立一個子模塊submodule,而將惡意的ssh鏈接藏在.gitmodule文件中。

修復(fù)防護方法

看完上面漏洞發(fā)生的成因,其實可以發(fā)現(xiàn)這個過程就是git處理ssh這類智能協(xié)議的傳輸過程:ssh遠(yuǎn)程登錄git服務(wù)器后,通過執(zhí)行g(shù)it-upload-pack處理下載的數(shù)據(jù),這種處理方式較http啞協(xié)議傳輸更高效。

但是在這過程中,對一些惡意的ssh鏈接,沒有正確識別,在解析時誤將 -oProxyCommand 這類參數(shù)當(dāng)做了遠(yuǎn)程主機名host,從而產(chǎn)生了漏洞。

在新版本中,我們看到增加了對host和path的識別過濾。

對包含疑似命令的host和path及時進行了阻止,阻斷了漏洞的發(fā)生。

 

建議用戶及時排查,更新系統(tǒng)存在漏洞的Git版本,在日常通過Git進行項目管理時,仔細(xì)檢查項目中是否存在一些惡意ssh鏈接來預(yù)防安全問題。

原文鏈接:http://blog.nsfocus.net/git-ssh-cve-2017-1000117/

【本文是51CTO專欄作者“綠盟科技博客”的原創(chuàng)稿件,轉(zhuǎn)載請通過51CTO聯(lián)系原作者獲取授權(quán)】

戳這里,看該作者更多好文

責(zé)任編輯:趙寧寧 來源: 51CTO專欄
相關(guān)推薦

2017-05-25 22:20:05

2013-05-22 09:33:09

交互設(shè)計設(shè)計時間

2016-10-21 15:57:39

Rust編輯語言Fedora

2022-02-24 16:15:16

OpenHarmon鴻蒙OpenEuler

2017-06-12 15:50:16

2017-06-28 11:34:55

銳捷 醫(yī)療 物聯(lián)網(wǎng)

2015-01-07 15:49:21

大數(shù)據(jù)SSD

2017-08-18 14:47:31

DDD微服務(wù)架構(gòu)

2017-05-08 07:07:50

2017-05-27 10:22:37

2017-05-16 14:38:25

2013-11-08 09:15:32

大數(shù)據(jù)平板電腦

2009-03-21 16:43:29

SOA虛擬化IT

2011-03-16 14:51:35

2016-10-21 09:45:20

RustFedoraJava

2017-09-11 13:55:30

前端JavaScript物聯(lián)網(wǎng)

2022-06-27 13:56:10

設(shè)計模式緩存分布式系統(tǒng)

2013-08-22 11:08:27

大數(shù)據(jù)商業(yè)只能Hadoop

2017-07-12 11:15:25

2020-03-05 16:35:06

人臉識別口罩人工智能
點贊
收藏

51CTO技術(shù)棧公眾號