溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何理解Linux X.25套接字棧越界讀寫漏洞

發(fā)布時(shí)間:2021-10-23 17:49:25 來源:億速云 閱讀:143 作者:iii 欄目:編程語言

本篇內(nèi)容介紹了“如何理解Linux X.25套接字棧越界讀寫漏洞”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

25簡介

25協(xié)議簡介

X.25接口協(xié)議于1976年首次提出,它是在加拿大DATAPAC公用分組網(wǎng)相關(guān)標(biāo)準(zhǔn)的基礎(chǔ)上制定的,在1980年、1984年、1988年和1993年又進(jìn)行了多次修改,是目前使用最廣泛的分組交換協(xié)議。X.25協(xié)議是數(shù)據(jù)終端設(shè)備(DTE)和數(shù)據(jù)電路終接設(shè)備(DCE)之間的接口協(xié)議,該協(xié)議的制定實(shí)現(xiàn)了接口協(xié)議的標(biāo)準(zhǔn)化,使得各種DTE能夠自由連接到各種分組交換網(wǎng)上。作為用戶設(shè)備和網(wǎng)絡(luò)之間的接口協(xié)議,X.25協(xié)議主要定義了數(shù)據(jù)傳輸通路的建立、保持和釋放過程所需遵循的標(biāo)準(zhǔn),數(shù)據(jù)傳輸過程中進(jìn)行差錯(cuò)控制和流量控制的機(jī)制以及提供的基本業(yè)務(wù)和可選業(yè)務(wù)等。

如何理解Linux X.25套接字棧越界讀寫漏洞

X.25協(xié)議采用分層的體系結(jié)構(gòu),自下而上分為三層:物理層、數(shù)據(jù)鏈路層和分組層,分別對(duì)應(yīng)于OSI參考模型的下三層。各層在功能上相互獨(dú)立,每一層接受下一層提供的服務(wù),同時(shí)也為上一層提供服務(wù),相鄰層之間通過原語進(jìn)行通信。在接口的對(duì)等層之間通過對(duì)等層之間的通信協(xié)議進(jìn)行信息交換的協(xié)商、控制和信息的傳輸。

如何理解Linux X.25套接字棧越界讀寫漏洞

Linux X.25套接字簡介

1996/12/18,Linux 內(nèi)核發(fā)布了 2.1.16版,第一次引入了對(duì)X.25協(xié)議的支持,定義了 AF_NFC 地址族:

#define AF_X25  9 /* Reserved for X.25 project  */

X25 sockets 為 X.25 數(shù)據(jù)包層協(xié)議(packet layer protocol)提供接口。 應(yīng)用程序可以使用標(biāo)準(zhǔn)的 ITU X.25 建議 (X.25 DTE-DCE 模式)在公共 X.25 數(shù)據(jù)網(wǎng)中進(jìn)行通訊。AF_X25 socket 地址族用 struct sockaddr_x25 代表 ITU-T X.121 規(guī)范中定義的網(wǎng)絡(luò)地址。

struct x25_address {

char x25_addr[16];

};




struct sockaddr_x25 {

sa_family_t   sx25_family;  /* 必須是 AF_X25 */

x25_address   sx25_addr;    /* X.121 地址 */

};

sx25_addr 包含一個(gè)空零結(jié)尾的字符串 x25_addr[] 。 sx25_addr.x25_addr[] 由最多 15  個(gè)  ASCII字符(不包括結(jié)束的 0)構(gòu)成 X.121 地址。 只能使用數(shù)字 `0' 到 `9' 。

X.25套接字僅支持 SOCK_SEQPACKET 類型,在建立X.25套接字時(shí), socket()調(diào)用的參數(shù)如下

x25_socket = socket(PF_X25, SOCK_SEQPACKET, 0);

Linux內(nèi)核中對(duì)應(yīng)的 struct proto 和 struct proto_ops:

static struct proto x25_proto = {

.name    = "X25",

.owner   = THIS_MODULE,

.obj_size = sizeof(struct x25_sock),

};




static const struct proto_ops x25_proto_ops = {

.family =  AF_X25,

.owner =   THIS_MODULE,

.release = x25_release,

.bind =    x25_bind,

.connect = x25_connect,

.socketpair =  sock_no_socketpair,

.accept =  x25_accept,

.getname = x25_getname,

.poll =    datagram_poll,

.ioctl =   x25_ioctl,

#ifdef CONFIG_COMPAT

.compat_ioctl = compat_x25_ioctl,

#endif

.gettstamp =   sock_gettstamp,

.listen =  x25_listen,

.shutdown = sock_no_shutdown,

.setsockopt =  x25_setsockopt,

.getsockopt =  x25_getsockopt,

.sendmsg = x25_sendmsg,

.recvmsg = x25_recvmsg,

.mmap =    sock_no_mmap,

.sendpage = sock_no_sendpage,

};

Linux X.25套接字棧越界讀漏洞

該漏洞位于x25_bind函數(shù)中,以Linux內(nèi)核最新的穩(wěn)定版本5.9.8為例,https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/net/x25/af_x25.c?h=v5.9.8#n677

677 static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)

678 {

679 struct sock *sk = sock->sk;

680 struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;

…………………………………………………………………………

692  len = strlen(addr->sx25_addr.x25_addr);

693  for (i = 0; i < len; i++) {

694   if (!isdigit(addr->sx25_addr.x25_addr[i])) {

695    rc = -EINVAL;

696    goto out;

697   }

698  }

…………………………………………………………………………

x25_bind有3個(gè)參數(shù),第二個(gè)參數(shù)uaddr是應(yīng)用層傳遞過來的套接字地址

在680行,uaddr轉(zhuǎn)成了X.25套接字地址指針

在692行,調(diào)用strlen函數(shù),獲取addr->sx25_addr.x25_addr的長度

從693行開始的for循環(huán),依次判斷addr->sx25_addr.x25_addr字符串里面是不是全部是數(shù)字。按照ITU-T X.121 規(guī)范,套接字地址只能使用數(shù)字 `0' 到 `9' 數(shù)字表示,不能用其他字符。

再來看一下sockaddr_x25 結(jié)構(gòu)體定義:

struct x25_address {

char x25_addr[16];

};




struct sockaddr_x25 {

sa_family_t   sx25_family;  /* 必須是 AF_X25 */

x25_address   sx25_addr;    /* X.121 地址 */

};

X.121 地址對(duì)應(yīng)的結(jié)構(gòu)體struct x25_address,其實(shí)是一個(gè)ascii字符串?dāng)?shù)組,大小是16。

X.121 地址最多15個(gè)ascii字符,而struct x25_address里面的x25_addr字符串?dāng)?shù)組大小是16,所以最后面是用來存儲(chǔ)字符串末尾的空字符的。

x25_bind函數(shù)的漏洞在于:調(diào)用strlen函數(shù)之前,沒有判斷struct x25_address里面的x25_addr字符串是不是以空字符結(jié)尾的。如果末尾不是空字符,那么strlen函數(shù)獲得的長度將會(huì)大于16,在接下來的for循環(huán)中,將會(huì)越界讀取addr正常范圍之后的數(shù)據(jù)。

Linux X.25套接字棧越界寫漏洞

該漏洞由多個(gè)X.25套接字相關(guān)漏洞組合而成,仍然以Linux內(nèi)核最新的穩(wěn)定版本5.9.8為例,從x25_connect函數(shù)開始,源代碼見:https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/net/x25/af_x25.c?h=v5.9.8#n744

744 static int x25_connect(struct socket *sock, struct sockaddr *uaddr,

745         int addr_len, int flags)

746 {

747 struct sock *sk = sock->sk;

748 struct x25_sock *x25 = x25_sk(sk);

749 struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;

…………………………………………………………………………

803 x25->dest_addr = addr->sx25_addr;

…………………………………………………………………………

811 x25_write_internal(sk, X25_CALL_REQUEST);

x25_connect有4個(gè)參數(shù),第二個(gè)參數(shù)uaddr是應(yīng)用層傳遞過來的套接字地址

在749行,uaddr轉(zhuǎn)成了X.25套接字地址指針

在803行,addr->sx25_addr 賦給了x25套接字的dest_addr,用作連接的目標(biāo)地址,

在811行,調(diào)用了x25_write_internal函數(shù)

x25_write_internal函數(shù)源代碼見:https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/net/x25/x25_subr.c?h=v5.9.8#n109

109 void x25_write_internal(struct sock *sk, int frametype)

110 {

111 struct x25_sock *x25 = x25_sk(sk);

…………………………………………………………………………

115 unsigned char  addresses[1 + X25_ADDR_LEN];

…………………………………………………………………………

179 switch (frametype) {

180

181  case X25_CALL_REQUEST:

182   dptr    = skb_put(skb, 1);

183   *dptr++ = X25_CALL_REQUEST;

184   len     = x25_addr_aton(addresses, &x25->dest_addr,

185      &x25->source_addr);

…………………………………………………………………………

111行,sk套接字轉(zhuǎn)成x25套接字指針

115行,在棧上聲明了一個(gè)字符串?dāng)?shù)組addresses,長度是1 + X25_ADDR_LEN,也就是17

傳遞過來的x25_write_internal函數(shù)第二個(gè)參數(shù)frametype是X25_CALL_REQUEST,由此在第181行開始處理

184行,調(diào)用x25_addr_aton函數(shù),傳遞了在棧上聲明的字符串?dāng)?shù)組addresses,x25套接字的dest_addr和source_addr,

dest_addr是在x25_connect函數(shù)中賦值的

source_addr是在x25_bind函數(shù)中賦值的

繼續(xù)看x25_addr_aton源代碼:https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/net/x25/af_x25.c?h=v5.9.8#n154

154 int x25_addr_aton(unsigned char *p, struct x25_address *called_addr,

155    struct x25_address *calling_addr)

156 {

157 unsigned int called_len, calling_len;

158 char *called, *calling;

159 int i;

160

161 called  = called_addr->x25_addr;

162 calling = calling_addr->x25_addr;

163

164 called_len  = strlen(called);

165 calling_len = strlen(calling);

166

167 *p++ = (calling_len << 4) | (called_len << 0);

168

169 for (i = 0; i < (called_len + calling_len); i++) {

170  if (i < called_len) {

171   if (i % 2 != 0) {

172    *p |= (*called++ - '0') << 0;

173    p++;

174   } else {

175    *p = 0x00;

176    *p |= (*called++ - '0') << 4;

177   }

178  } else {

179   if (i % 2 != 0) {

180    *p |= (*calling++ - '0') << 0;

181    p++;

182   } else {

183    *p = 0x00;

184    *p |= (*calling++ - '0') << 4;

185   }

186  }

187 }

188

189 return 1 + (called_len + calling_len + 1) / 2;

190 }

x25_addr_aton函數(shù)有三個(gè)參數(shù):

unsigned char *p:在棧上聲明的字符串?dāng)?shù)組addresses

struct x25_address *called_addr:x25_connect函數(shù)中賦值的目標(biāo)地址

struct x25_address *calling_addr:x25_bind函數(shù)中賦值的當(dāng)前地址

164、165行,調(diào)用strlen獲取目標(biāo)地址、當(dāng)前地址的長度,

169行開始的for循環(huán),用得到的兩個(gè)地址的長度,不斷地往參數(shù)p指向的內(nèi)存中寫值

和x25_bind函數(shù)一樣,x25_connect在賦值時(shí),也沒有判斷應(yīng)用層傳遞過來的套接字地址是不是以空字符結(jié)尾,在整個(gè)的傳遞過程中,x25_write_internal、x25_addr_aton兩個(gè)函數(shù)也沒有判斷。

由此顯而易見的是,如果x25_bind、x25_connect兩個(gè)函數(shù)賦值的地址不是以空字符結(jié)尾的話,那么x25_addr_aton函數(shù)調(diào)用的兩個(gè)strlen獲取到的長度都將超過16,在169行for循環(huán)寫入addresses時(shí),將造成addresses的溢出,造成嚴(yán)重的棧溢出漏洞。

影響范圍

最初的2.1.16版本的x25_bind函數(shù)(見https://elixir.bootlin.com/linux/2.1.16/source/net/x25/af_x25.c#L697),沒有對(duì)addr做任何判斷,直接賦給了sk套接字,所以上述的越界讀漏洞在最初的版本中并不存在。當(dāng)然,按照ITU-T X.121 規(guī)范,套接字地址只能使用數(shù)字 `0' 到 `9' 數(shù)字表示,不能用其他字符,所以這里的功能其實(shí)是不正常的。

從2.6.34版本開始(2010/05/16發(fā)布),x25_bind函數(shù)中開始加入strlen函數(shù)和for循環(huán),用于判斷addr的有效性,并持續(xù)至現(xiàn)在的最新版本5.9.8.所以上述越界讀漏洞影響linux內(nèi)核版本為:2.6.34~5.9.8

x25_connect、x25_write_internal、x25_addr_aton三個(gè)函數(shù),自從引入以來,對(duì)dest_addr的沒有變化,一直都沒有判斷是否以空字符結(jié)尾,所以上述越界寫漏洞影響linux內(nèi)核版本為:2.1.16~5.9.8,持續(xù)時(shí)間長達(dá)24年。

“如何理解Linux X.25套接字棧越界讀寫漏洞”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI