CVE-2020-8597 pppd stack buffer overflow in eap_response
2020-03-24 10:50:01 Author: xz.aliyun.com(查看原文) 阅读量:505 收藏

0x0 背景

pppd是一个通过串行接口连接的点对点协议(PPP)

github地址 :https://github.com/paulusmack/ppp

在ppp 2.4.2 - 2.4.8版本有一个栈溢出漏洞,我试着分析了整个过程

0x1复现整个过程

准备两台ubuntu的虚拟机(我用的virtualbox),设置启用串口功能。分别在两台虚拟机上git clone一份ppp,并回滚到有漏洞版本,编译安装。例如

git clone https://github.com/paulusmack/ppp.git
cd ppp
git checkout ppp-2.4.8
./configure
make
make install

开启服务端的md5认证(MD5-Challenge)

打开文件/etc/ppp/chap-secrets添加下面内容

admin   *       password        *

服务端启动pppd程序

pppd /dev/ttyS0 9600 auth local lock defaultroute debug nodetach 172.16.1.1:172.16.1.2 ms-dns 8.8.8.8 require-eap

客户端启动pppd程序

pppd noauth local lock defaultroute debug nodetach /dev/ttyS0 9600 user aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbb password notpassword

下图我们发现程序没有崩溃,服务端打印出的username只有255个字节,我们输入的username255+5个字节,可惜这不是服务端对接收的内容进行的验证,这是在客户端限制了用户输入的用户名长度

0x2 漏洞分析

pppd进行MD5-Challenge的时候,通过eap_chap_response把密码hash、用户名和用户名长度一起发送到了服务端,用户名保存在一个256大小的栈变量中。

所以在我们上边的测试中,其实只发送了255长度的username到服务端。

6     typenum = id;
   5     MD5_Update(&mdContext, &typenum, 1);
   4     MD5_Update(&mdContext, (u_char *)secret, secret_len);
   3     BZERO(secret, sizeof (secret));
   2     MD5_Update(&mdContext, inp, vallen);
   1     MD5_Final(hash, &mdContext);
1454     ** eap_chap_response(esp, id, hash, esp->es_client.ea_name,
   1         esp->es_client.ea_namelen);
   2     break;
787    eap_authwithpeer(unit, user);
20 void
  19 eap_authwithpeer(unit, localname)
  18 int unit;
  17 char *localname;
  16 {
  15   eap_state *esp = &eap_states[unit];
  14
  13   /* Save the peer name we're given */
  12   esp->es_client.ea_name = localname;
  11   esp->es_client.ea_namelen = strlen(localname);
  10
   9   esp->es_client.ea_state = eapListen;
   8
   7   /*
   6    * Start a timer so that if the other end just goes
   5    * silent, we don't sit here waiting forever.
   4    */
   3   if (esp->es_client.ea_timeout > 0)
   2     TIMEOUT(eap_client_timeout, (void *)esp,
   1         esp->es_client.ea_timeout);
257  }
extern char user[MAXNAMELEN];/* Our name for authenticating ourselves */
extern char passwd[MAXSECRETLEN]; /* Password for PAP or CHAP */
#define MAXNAMELEN  256 /* max length of hostname or name for auth */

服务端接收的时候,vallen是已经处理的长度,len是接收的总长度,sizeof (rhostname)是username最大的长度和客户端一样256的数组,所以if判断手误了?

最后MD5-Challenge没处理好长度验证。当发送大于256长度的字符串时,发生益处。

if (vallen >= len + sizeof (rhostname)) {
          dbglog("EAP: trimming really long peer name down");
          BCOPY(inp + vallen, rhostname, sizeof (rhostname) - 1;
          rhostname[sizeof (rhostname) - 1] = '\0';
        } else {
          BCOPY(inp + vallen, rhostname, len - vallen);
          rhostname[len - vallen] = '\0';
        }

0x3 其他

想要触发服务端崩溃,可以像参考链接中的博主一样,直接修改eap_chap_response中的username送的内容。也可以像另一位博主一样,wireshark抓包,修改数据包中username内容,在写脚本发包到服务端,

0x4一半翻译一半补充的参考链接

https://gist.github.com/nstarke/551433bcc72ff95588e168a0bb666124


文章来源: http://xz.aliyun.com/t/7407
如有侵权请联系:admin#unsafe.sh