Closed ek1ng closed 1 year ago
配置mysql后编译并启动server,可以正常访问。
server
发送如下http请求后,能够导致server堆溢出从而crash。
crash
GET <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< HTTP/1.1 Host: 127.0.0.1:9006 User-Agent: curl/7.68.0 Accept: */*
server会crash,无法正常提供服务。
调用链
触发点在http请求后写入log的位置。
http
void Log::write_log(int level, const char *format, ...) { struct timeval now = {0, 0}; gettimeofday(&now, NULL); time_t t = now.tv_sec; struct tm *sys_tm = localtime(&t); struct tm my_tm = *sys_tm; char s[16] = {0}; switch (level) { case 0: strcpy(s, "[debug]:"); break; case 1: strcpy(s, "[info]:"); break; case 2: strcpy(s, "[warn]:"); break; case 3: strcpy(s, "[erro]:"); break; default: strcpy(s, "[info]:"); break; } //写入一个log,对m_count++, m_split_lines最大行数 m_mutex.lock(); m_count++; if (m_today != my_tm.tm_mday || m_count % m_split_lines == 0) //everyday log { char new_log[256] = {0}; fflush(m_fp); fclose(m_fp); char tail[16] = {0}; snprintf(tail, 16, "%d_%02d_%02d_", my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday); if (m_today != my_tm.tm_mday) { snprintf(new_log, 255, "%s%s%s", dir_name, tail, log_name); m_today = my_tm.tm_mday; m_count = 0; } else { snprintf(new_log, 255, "%s%s%s.%lld", dir_name, tail, log_name, m_count / m_split_lines); } m_fp = fopen(new_log, "a"); } m_mutex.unlock(); va_list valst; va_start(valst, format); string log_str; m_mutex.lock(); //写入的具体时间内容格式 int n = snprintf(m_buf, 48, "%d-%02d-%02d %02d:%02d:%02d.%06ld %s ", my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday, my_tm.tm_hour, my_tm.tm_min, my_tm.tm_sec, now.tv_usec, s); int m = vsnprintf(m_buf + n, m_log_buf_size - 1, format, valst); m_buf[n + m] = '\n'; m_buf[n + m + 1] = '\0'; log_str = m_buf; m_mutex.unlock(); if (m_is_async && !m_log_queue->full()) { m_log_queue->push(log_str); } else { m_mutex.lock(); fputs(log_str.c_str(), m_fp); m_mutex.unlock(); } va_end(valst); }
在log.cpp中int m = vsnprintf(m_buf + n, m_log_buf_size - 1, format, valst); 这里使用的对于m_log_buf_size默认初始化成了2000大小。但是在使用时从m_buf + n开始使用,这时候再向buf写2000个字节大小的内容,就会因此会堆溢出n个字节,导致crash。
log.cpp
int m = vsnprintf(m_buf + n, m_log_buf_size - 1, format, valst);
m_log_buf_size
2000
m_buf + n
在/webserver.cpp中
/webserver.cpp
void WebServer::log_write() { if (0 == m_close_log) { //初始化日志 if (1 == m_log_write) Log::get_instance()->init("./ServerLog", m_close_log, 3000, 800000, 800); else Log::get_instance()->init("./ServerLog", m_close_log, 3000, 800000, 0); } }
将buf调大可以解决问题。
很棒的修复方案!
POC
配置mysql后编译并启动
server
,可以正常访问。发送如下http请求后,能够导致
server
堆溢出从而crash
。server
会crash
,无法正常提供服务。漏洞原理
调用链
触发点在
http
请求后写入log的位置。在
log.cpp
中int m = vsnprintf(m_buf + n, m_log_buf_size - 1, format, valst);
这里使用的对于m_log_buf_size
默认初始化成了2000
大小。但是在使用时从m_buf + n
开始使用,这时候再向buf写2000
个字节大小的内容,就会因此会堆溢出n个字节,导致crash
。修复建议
在
/webserver.cpp
中将buf调大可以解决问题。