summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ychat/src/chat/user.cpp15
-rw-r--r--ychat/src/reqp.cpp10
-rw-r--r--ychat/src/sock/sock.cpp10
-rw-r--r--ychat/src/tool/tool.cpp31
-rw-r--r--ychat/src/tool/tool.h1
5 files changed, 67 insertions, 0 deletions
diff --git a/ychat/src/chat/user.cpp b/ychat/src/chat/user.cpp
index 1308cb0..5a35371 100644
--- a/ychat/src/chat/user.cpp
+++ b/ychat/src/chat/user.cpp
@@ -391,6 +391,21 @@ user::command( string &s_command )
string s_mod( wrap::CONF->get_elem("httpd.modules.commandsdir") + "yc_" );
string s_command2 = s_command.substr(0, pos2-1);
+
+ // Security: s_command2 is attacker-controlled (the first token of a chat
+ // message starting with '/') and is concatenated into the command-module
+ // .so path then dlopen()'d. Reject non-alphanumeric names so ".."/"/" can't
+ // traverse out of the commands dir and load an arbitrary shared object.
+ if ( ! tool::is_alpha_numeric(s_command2) )
+ {
+ wrap::system_message("Chat: blocked command-name traversal: " + s_command2);
+ string s_msg = "<font color=\"" + wrap::CONF->get_elem("chat.html.errorcolor") + "\""
+ + wrap::CONF->get_elem( "chat.msgs.err.findingcommand" )
+ + "</font>\n";
+ msg_post( &s_msg );
+ return;
+ }
+
s_mod.append( s_command2 ).append( ".so" );
dynmod *mod = wrap::MODL->get_module( s_mod, get_name() );
diff --git a/ychat/src/reqp.cpp b/ychat/src/reqp.cpp
index b68bed7..907161d 100644
--- a/ychat/src/reqp.cpp
+++ b/ychat/src/reqp.cpp
@@ -171,6 +171,16 @@ reqp::parse(context *p_context)
void
reqp::run_html_mod( string s_event, map<string,string> &map_params, user* p_user )
{
+ // Security: s_event is attacker-controlled (a query param) and is
+ // concatenated into the html-module .so path then dlopen()'d. Reject
+ // non-alphanumeric names so ".."/"/" can't traverse out of the modules dir
+ // and load an arbitrary shared object (RCE).
+ if ( ! tool::is_alpha_numeric(s_event) )
+ {
+ wrap::system_message("Reqp: blocked module-name traversal: " + s_event);
+ return;
+ }
+
container *c = new container;
c->elem[0] = (void*) wrap::WRAP;
diff --git a/ychat/src/sock/sock.cpp b/ychat/src/sock/sock.cpp
index 327b5ef..5fbcc93 100644
--- a/ychat/src/sock/sock.cpp
+++ b/ychat/src/sock/sock.cpp
@@ -474,6 +474,16 @@ sock::handle_client_read(int i_fd, short event, void *p_arg)
if (s_request.empty())
s_request = wrap::CONF->get_elem("httpd.startsite");
+ // Path-traversal guard (security): reject any request whose decoded path
+ // contains a "."/".." component — it would escape httpd.templatedir when
+ // html.cpp opens (templatedir + request). The raw-URL "/.." strip above
+ // is insufficient because it runs before url_decode (attacker uses %2e%2f).
+ if ( tool::path_has_traversal(s_request) )
+ {
+ wrap::system_message("Sock: blocked path traversal: " + s_request);
+ s_request = wrap::CONF->get_elem("httpd.html.notfound");
+ }
+
map_params["request"] = s_request;
{
diff --git a/ychat/src/tool/tool.cpp b/ychat/src/tool/tool.cpp
index 6ef0217..fc9bf5c 100644
--- a/ychat/src/tool/tool.cpp
+++ b/ychat/src/tool/tool.cpp
@@ -286,6 +286,37 @@ tool::url_decode( string s_url )
return s_dest;
}
+// Returns true if the URL-decoded request path contains a "." or ".."
+// path component (i.e. would escape the template directory when
+// concatenated to httpd.templatedir and opened). The check must run on the
+// DECODED path: the earlier raw-URL "/.." strip in sock.cpp misses
+// %-encoded dots (e.g. %2e%2f) which decode to ".." afterwards.
+bool
+tool::path_has_traversal( const string &s_request )
+{
+ // Reject embedded NULs outright: url_decode turns %00 into '\0', and a
+ // std::string can hold it while ifstream/c_str() truncate at it — a
+ // divergence that is never legitimate in a request path.
+ if ( s_request.find('\0') != string::npos )
+ return true;
+
+ size_t i_start = 0;
+ size_t i_len = s_request.size();
+
+ for ( size_t i = 0; i <= i_len; ++i )
+ {
+ if ( i == i_len || s_request[i] == '/' )
+ {
+ string s_seg = s_request.substr( i_start, i - i_start );
+ if ( s_seg == ".." || s_seg == "." )
+ return true;
+ i_start = i + 1;
+ }
+ }
+
+ return false;
+}
+
int
tool::htoi(string &s_str)
{
diff --git a/ychat/src/tool/tool.h b/ychat/src/tool/tool.h
index c1ad616..a9fbb80 100644
--- a/ychat/src/tool/tool.h
+++ b/ychat/src/tool/tool.h
@@ -51,6 +51,7 @@ public:
static string shell_command( string s_command, method m_method );
static string ychat_version();
static string url_decode(string s_url);
+ static bool path_has_traversal(const string &s_request);
static int htoi(string &s_str);
};