CVE-2019-18634
复现下sudo的一个cve
搭建环境
ubuntu 16.04 vmware 虚拟机
下载sudo-1.8.25源码并编译
1 | wget https://www.sudo.ws/dist/sudo-1.8.25.tar.gz |
编译好的程序会在build目录下的bin目录里
漏洞分析
要复现漏洞的话,要先开启sudo的pwfeedback 选项,这个选项就是sudo要求输入密码的时候,输进去的密码会有*显示,算是一种反馈吧:
1 | ruan@ubuntu ~/cve/cve-2019-18634/build/bin ./sudo ls |
开启的方法是在/etc/sudoers 文件中添加一行Defaults pwfeedback
poc
该poc 适用 sudo 1.8.25p1 以下的版本 :
1 | perl -e 'print(("A" x 100 . "\x{00}") x 50)' | sudo -S id |
程序奔溃:
1 | ✘ ruan@ubuntu ~/cve/cve-2019-18634/build/bin perl -e 'print(("A" x 100 . "\x{00}") x 50)' | ./sudo -S id |
调试
参考安全客文章里的调试代码:
1 | import sys,os |
./poc的话就是perl -e 'print(("A" x 100 . "\x{00}") x 50)' > ./poc生成的
我们在第一个pause()的时候用gdb attach上去,sudo gdb attach pid,然后跑起来,gdb会断在程序奔溃处:

出问题的是tgetpass.c文件里的getln函数
漏洞代码分析
getln函数源码:
1 | static char * |
出问题的就是在:
1 | if (feedback) { //我们开启了pwfeedback选项,所以会进入这里 |
sudo_term_kill的值可以调试得知:
1 | pwndbg> p sudo_term_kill |
因为我们是通过管道传进来的字符串,但是管道是单向的,所以write(fd, "\b \b", 3)会返回-1,于是直接break出while (cp > buf)的循环,又对left进行了赋值,但是此时的cp并没有回到buf的头部,所以造成了溢出
在查看下buf是哪里的变量,从奔溃的栈布局可以知道是tgetpass函数调用了getln,源码里对应:
1 | if (timeout > 0) |
在向上看看,能找到对buf的定义:
1 | char * |
1 |
buf是static变量,说明它是存放在数据区的:
1 | pwndbg> p buf |
用ida打开我们编译的sudo程序,查看下buf变量下面都有些啥全局的变量:

这个好像用不同版本的gcc编译会有一些差别
可以看到的是,buf底下有user_details结构体,还有一个tgetpass_flags,先来看下这个tgetpass_flags
tgetpass函数里有一段:
1 | /* If using a helper program to get the password, run it instead. */ |
如果设置了TGP_ASKPASS的flag,那程序就会fork出一个子进程去执行那个helper program
而sudo_askpass函数里就用到了user_details这个结构:
1 | child = sudo_debug_fork(); |
子进程的权限通过user_details.uid和user_details.gid来设置,这两个值我们是可以通过这个漏洞改写掉的,也就是说我们可以通过这里用root权限来运行程序
思路
sudo有3次机会给我们输入密码
设置环境变量
SUDO_ASKPASS指定外部程序第一次用溢出把
user_details覆盖掉,顺便把tgetpass_flags也给覆盖为TGP_ASKPASS,启用askpass功能第二次输入密码的时候就会去执行外部的程序
踩坑
一开始我是从stdin给sudo输入数据,第一次溢出是可以的,第二次就不知道为什么不行,一只卡在read那里,无论输入什么都没有反应,而且从stdin输入数据的时候,sudo_term_kill一直为\x00,这样是没办法一次写入多个\x00只能写一个\x00字节进去。
后来还是选择从伪终端里输入数据,这样的话:
1 | pwndbg> p/x sudo_term_kill |
我们就可以一次写入多个\x00了
还有一个坑就是,我指定了SUDO_ASKPASS为shell脚本,但是执行的时候老是说找不到文件,后来换成程序就可以了。。。
最终:
1 | ruan@ubuntu ~/cve/cve-2019-18634/build/bin python debug.py DEBUG |

test程序是一个反弹shell的程序
exp:
1 | import sys,os |