Samba遠程崩潰或代碼執行漏洞(CVE-2015-0240)簡要分析

1.搭建samba環境

注意:在Linux系統上使用源碼編譯來安裝samba必須要將系統自帶的全部關於samba的軟件均刪除,可用如下命令查看已安裝的samba軟件:

[bb@localhost bin]$ rpm -qa | grep samba
samba-common-3.6.23-14.el6_6.x86_64
samba-winbind-3.6.23-14.el6_6.x86_64
samba-winbind-clients-3.6.23-14.el6_6.x86_64
samba-client-3.6.23-14.el6_6.x86_64

然後直接全部刪除:

[bb@localhost bin]$ rpm -qa | grep samba | xargs sudo rpm -e --nodeps

刪除完成之後從https://download.samba.org/pub/samba/stable/samba-3.6.23.tar.gz下載源碼,解壓後進入source3目錄,先執行./configure進行配置,然後對Makefile文件稍作更改,在編譯選項中加入-g以便gdb對其進行調試。隨後就是make編譯,make install安裝,默認安裝路徑是/usr/local/samba,安裝後目錄如下:

[bb@localhost samba]$ ls
bin  include  lib  private  sbin  share  swat  var

首先進入lib目錄,將源碼中example目錄下的smb.conf.dufault文件複製到當前目錄並改名爲smb.conf;然後執行以下命令:

[bb@localhost bin]$ sudo vim /etc/ld.so.conf

在打開的文件中添加一行

/usr/local/samba/lib

退出並執行ldconfig更新動態鏈接庫緩存。然後就是到/usr/local/samba/bin目錄下執行:

[bb@localhost bin]$ sudo ./smbpasswd -a bb
New SMB password:
Retype new SMB password:
Added user bb.

然後需要關閉防火牆:

[bb@localhost ~]$ sudo service iptables stop
[sudo] password for bb: 
iptables: Flushing firewall rules:                         [  OK  ]
iptables: Setting chains to policy ACCEPT: filter          [  OK  ]
iptables: Unloading modules:                               [  OK  ]

最後則是到sbin目錄下啓動smbd和nmbd程序,完成後可以看到進程如下:

[bb@localhost sbin]$ pgrep smbd
6359
6360
[bb@localhost sbin]$ pgrep nmbd
6365

然後我在Windows上登陸便會提示輸入用戶名和密碼,正確之後便能訪問bb用戶的目錄文件:
這裏寫圖片描述

2.源碼分析過程

首先是在redhat的博客https://securityblog.redhat.com/2015/02/23/samba-vulnerability-cve-2015-0240/上看到了漏洞的代碼是在_netr_ServerPasswordSet函數中,如下圖所示:

這裏寫圖片描述

其中第一方框處事creds的聲明的地方,這裏並未對其進行初始化,第二處將creds的地址作爲參數,想必是對其進行初始化,第三處則是當第二處的函數netr_creds_server_step_check返回錯誤也就是驗證creds失敗則會將creds指向的內存釋放,但是釋放之前並未對creds指針進行有效性檢查。那什麼條件會使得netr_creds_server_step_check函數運行失敗呢?

下面是netr_creds_server_step_check的代碼:

這裏寫圖片描述

顯然schannel_check_creds_state函數用來初始化creds結構指針的,繼續看這個函數:

這裏寫圖片描述

帶有方框的兩部分都是受客戶端的控制並可能導致驗證失敗的地方,第一處只要客戶端的機器沒有在服務器上驗證通過過就會觸發(可以是一個新的計算機名或是僞造一個計算機名),第二處只要隨意僞造一個憑證即可觸發。現在需要驗證這兩種情況的可能性。

3.驗證POC

在github上https://gist.github.com/worawit/33cc5534cb555a0b710b看到了一個poc。

3.1

首先驗證第一個原因,也就是未經過驗證的計算機導致崩潰。運行samba服務端,使用gdb attach上去然後在_netr_ServerPasswordSet函數處下斷點:

(gdb) c
Continuing.

Breakpoint 1, _netr_ServerPasswordSet (p=0x7f1ceeb92d10, r=0x7f1ceeb96520)
    at rpc_server/netlogon/srv_netlog_nt.c:1205
1205    {

一直運行到根據主機名獲取相應憑證的函數,可以看到這裏的計算機名就是客戶端的ip地址192.168.1.132:

(gdb) s
schannel_fetch_session_key_tdb (tdb_sc=0x7fa334355f30, mem_ctx=0x7fa334355e40,
    computer_name=0x7fa33436d890 "192.168.1.132", pcreds=0x7fff538e2ba8)
    at ../libcli/auth/schannel_state_tdb.c:128

隨後構造一個字符串:

(gdb) n
144             keystr = talloc_asprintf(mem_ctx, "%s/%s",
(gdb) p keystr
$15 = 0x7fa334360650 "SECRETS/SCHANNEL/192.168.1.132"

然後根據這個字符串從tdb中獲取相應的憑證:

(gdb) n
151             value = tdb_fetch_bystring(tdb_sc->tdb, keystr);

繼續跟蹤可以看到其計算hash值的算法:

/* This is based on the hash algorithm from gdbm */
unsigned int tdb_old_hash(TDB_DATA *key)
{
    uint32_t value; /* Used to compute the hash value.  */
    uint32_t   i;   /* Used to cycle through random values. */

    /* Set the initial value from the key size. */
    for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++)
        value = (value + (key->dptr[i] << (i*5 % 24)));

    return (1103515243 * value + 12345);
}

查看運行返回的值已經是NULL了,隨後返回失敗的結果,指向creds的指針並沒有初始化:

(gdb) n
152             if (!value.dptr) {
(gdb) p value
$16 = {dptr = 0x0, dsize = <value optimized out>}

最後則是在釋放指針的時候崩潰:

(gdb) n
1224                    TALLOC_FREE(creds);
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x00007fa331e572f0 in talloc_parent_chunk (ptr=<value optimized out>) at ../lib/talloc/talloc.c:407
407             while (tc->prev) tc=tc->prev;

3.2

接下去是使用驗證過的計算機但將其憑證修改爲其他值,這就需要先驗證通過,http://www.freebuf.com/vuls/59898.htmlhttps://technet.microsoft.com/zh-tw/exchange/cc237127中都表明需要使用netlogon服務都必須先通過NetrServerAuthenticate驗證。代碼如下所示:

這裏寫圖片描述

但是經過多次嘗試和改變,服務器端一直都是密碼錯誤,不知爲何:

這裏寫圖片描述

所以第二種方法就暫時無法驗證。

4.修復方法

知道了原因修復起來就簡單多了,直接在creds聲明的時候初始化爲NULL,然後在釋放前判斷其是否爲NULL即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章