base 影响版本 1.8.2 - 1.8.31p2
1.9.0 - 1.9.5p1
漏洞类型 因拷贝user_args的结束判断条件可绕过,导致的堆溢出
利用方法 溢出修改service_user中的name字段 在nss_load_library加载对应的"libnss_",ni->name,".so"
时,劫持至自编译的so文件弹rootshell
源码和调试 sudo 1.8.21p2漏洞函数源码 path: plugins/sudoers/sudoers.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 846 847 for (size = 0 , av = NewArgv + 1 ; *av; av++)848 size += strlen (*av) + 1 ;849 if (size == 0 || (user_args = malloc (size)) == NULL ) {850 sudo_warnx(U_("%s: %s" ), __func__, U_("unable to allocate memory" ));851 debug_return_int(-1 );852 }853 if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {854 859 for (to = user_args, av = NewArgv + 1 ; (from = *av); av++) {860 while (*from) {861 if (from[0 ] == '\\' && !isspace ((unsigned char )from[1 ]))862 from++;863 *to++ = *from++;864 }865 *to++ = ' ' ;866 }867 *--to = '\0' ;868 } else {
修复后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 for (size = 0 , av = NewArgv + 1 ; *av; av++)size += strlen (*av) + 1 ; if (size == 0 || (user_args = malloc (size)) == NULL ) {sudo_warnx(U_("%s: %s" ), __func__, U_("unable to allocate memory" )); debug_return_int(-1 ); } if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL) && ISSET(sudo_mode, MODE_RUN)) { for (to = user_args, av = NewArgv + 1 ; (from = *av); av++) { while (*from) { if (from[0 ] == '\\' && from[1 ] != '\0' && !isspace ((unsigned char )from[1 ])) { from++; } if (size - (to - user_args) < 1 ) { sudo_warnx(U_("internal error, %s overflow" ), __func__); debug_return_int(NOT_FOUND_ERROR); } *to++ = *from++; } if (size - (to - user_args) < 1 ) { sudo_warnx(U_("internal error, %s overflow" ), __func__); debug_return_int(NOT_FOUND_ERROR); } *to++ = ' ' ; } *--to = '\0' ; } else {
利用调试点 源码位置:nss/nsswitch.c
static int nss_load_library(service_user *ni)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 static int nss_load_library (service_user *ni) { if (ni->library == NULL ) { static name_database default_table; ni->library = nss_new_service (service_table ?: &default_table, ni->name); if (ni->library == NULL ) return -1 ; } if (ni->library->lib_handle == NULL ) { size_t shlen = (7 + strlen (ni->name) + 3 + strlen (__nss_shlib_revision) + 1 ); int saved_errno = errno; char shlib_name[shlen]; __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name, "libnss_" ), ni->name), ".so" ), __nss_shlib_revision); ni->library->lib_handle = __libc_dlopen (shlib_name);