OpenWrt系統安全改進 --- Web 訪問權限分級

摘要

OpenWrt系統安全改進<四>中介紹的只是在UI層面對用戶進行訪問控制,對於深層次非法操作並不能起到保護效果。本節介紹針對不同的用戶登錄請求,使用不同用戶啓動luci進程,從而實現不同用戶進行操作級別的訪問控制。

機制分析

web頁面操作涉及到uhttpd和luci兩個模塊,uhttpd處理http報文,將cgi請求轉給luci處理。從代碼實現就可以看出這兩個模塊目前只是針對單用戶:

1 uhttpd在初始化時,由root用戶啓動,在調用cgi請求時,使用execl調用luci

2 luci的cache內容只保留一份。

在本實踐中,創建admin(歸爲root用戶組)和user兩個用戶,當uhttpd接收到登陸請求包,判斷用戶是否發生變化,如果是就清除luci的cache(否則luci會執行出錯),使用su啓動luci進程。

準備工作

創建用戶和用戶組,相關的腳本(可執行文件)針對不同用戶組分配不同的權限。

(注意:busybox中的ash和sh需要能夠被所有用戶可以執行,我採用了兩份busybox,ash/sh link到所有用戶可執行的busybox,其他link到只有同組用戶可執行的busybox)

使能busybox的su

使能web ui的多用戶登陸

具體操作可以參見OpenWrt系統安全改進<一>

實現不同用戶身份執行luci

  1. --- a/uhttpd.c 
  2. +++ b/uhttpd.c 
  3. @@ -243,6 +243,64 @@ 
  4.         return bound; 
  5.  
  6. +#ifndef MULTI_USER 
  7. +extern void MU_dbg(char *info); 
  8. +void MU_dbg(char *info) 
  9. +{ 
  10. +    #if
  11. +    int fd = open("/debug",O_RDWR|O_APPEND); 
  12. +    char buf[128] = {0}; 
  13. +    int len = strlen(info); 
  14. +    if (fd<0) { 
  15. +        fd = open("/debug",O_CREAT|O_RDWR); 
  16. +    } 
  17. +    memcpy(buf,info,len); 
  18. +    buf[len] = '\n'
  19. +    write(fd,buf,len+1); 
  20. +    close(fd); 
  21. +    #endif 
  22. +} 
  23. +static char CUR_USER[32] = {0}; 
  24. +extern void get_cur_user(char *user); 
  25. +void get_cur_user(char *user) { 
  26. +    if ( strlen(CUR_USER)==0 ) { 
  27. +        MU_dbg("CUR_USER empty"); 
  28. +        strcpy(user,"admin"); 
  29. +    } else
  30. +        memcpy(user,CUR_USER,strlen(CUR_USER)); 
  31. +    } 
  32. +} 
  33. +static void MU_get_user(const struct client *cl, char *user) { 
  34. +    char *usrhead = cl->httpbuf.ptr; 
  35. +    char *pwdhead = strfind(usrhead,strlen(usrhead),"&password=",strlen("&password=")); 
  36. +    usrhead += strlen("username="); 
  37. +    memcpy( user, usrhead, pwdhead-usrhead ); 
  38. +    MU_dbg(user); 
  39. +} 
  40. +static void MU_clear_luci_cache() { 
  41. +    int ret = 0; 
  42. +    ret = system("echo clear cache > /tmp/luci_action"); 
  43. +    ret = system("rm -Rf /tmp/luci-*"); 
  44. +    if ( ret == -1 ) { 
  45. +        system("echo fail >> /debug"); 
  46. +    } else if ( ret==0 ) { 
  47. +        system("echo ignore >> /debug"); 
  48. +    } else
  49. +        system("echo finish >> /debug"); 
  50. +    } 
  51. +} 
  52. +#endif 
  53. static struct http_request * uh_http_header_parse(struct client *cl, 
  54.                                                                                  char *buffer, int buflen) 
  55. @@ -281,7 +339,21 @@ 
  56.                 if (method && !strcmp(method, "GET")) 
  57.                         req->method = UH_HTTP_MSG_GET; 
  58.                 else if (method && !strcmp(method, "POST")) 
  59. -                       req->method = UH_HTTP_MSG_POST; 
  60. +               #ifndef MULTI_USER 
  61. +        { 
  62. +            char user[32] = {0}; 
  63. +            MU_get_user(cl,user); 
  64. +            if( strncmp(user,CUR_USER,4)!=0 ) { 
  65. +                MU_clear_luci_cache(); 
  66. +            } 
  67. +            memcpy(CUR_USER,user,32); 
  68. +            req->method = UH_HTTP_MSG_POST; 
  69. +        } 
  70. +        #else 
  71. +            req->method = UH_HTTP_MSG_POST; 
  72. +        #endif 
  73.                 else if (method && !strcmp(method, "HEAD")) 
  74.                         req->method = UH_HTTP_MSG_HEAD; 
  75.                 else 
  76. --- a/uhttpd-cgi.c 
  77. +++ b/uhttpd-cgi.c 
  78. @@ -486,12 +486,32 @@ 
  79.                         if (chdir(pi->root)) 
  80.                                 perror("chdir()"); 
  81.  
  82. +            #ifndef MULTI_USER 
  83. +            { 
  84. +                extern void get_cur_user(char *user); 
  85. +                extern void MU_dbg(char *info); 
  86. +                char user[32] = {0}; 
  87. +                char info[32] = {0}; 
  88. +                get_cur_user(user); 
  89. +                sprintf(info,"exec via %s",user); 
  90. +                MU_dbg(info); 
  91. +                if (ip!=NULL) { 
  92. +                    execl("/bin/su","su",user,"-c",ip->path,pi->phys,NULL); 
  93. +                } else
  94. +                    execl("/bin/su","su",user,"-c",pi->phys,NULL); 
  95. +                } 
  96. +            } 
  97. +            #else 
  98.                         if (ip != NULL) 
  99. -                               execl(ip->path, ip->path, pi->phys, NULL); 
  100. -                       else 
  101. +                               execl(ip->path, ip->path, pi->phys, NULL); 
  102. +            else 
  103.                                 execl(pi->phys, pi->phys, NULL); 
  104. -                       /* in case it fails ... */ 
  105. +            #endif 
  106. +            /* in case it fails ... */ 
  107.                         printf("Status: 500 Internal Server Error\r\n\r\n" 
  108.                                    "Unable to launch the requested CGI program:\n" 
  109.                                    "  %s: %s\n", ip ? ip->path : pi->phys, strerror(errno)); 
--- a/uhttpd.c
+++ b/uhttpd.c
@@ -243,6 +243,64 @@
        return bound;
 }

+#ifndef MULTI_USER
+extern void MU_dbg(char *info);
+void MU_dbg(char *info)
+{
+    #if 0
+    int fd = open("/debug",O_RDWR|O_APPEND);
+    char buf[128] = {0};
+    int len = strlen(info);
+
+    if (fd<0) {
+        fd = open("/debug",O_CREAT|O_RDWR);
+    }
+
+    memcpy(buf,info,len);
+    buf[len] = '\n';
+
+    write(fd,buf,len+1);
+    close(fd);
+    #endif
+}
+
+static char CUR_USER[32] = {0};
+
+extern void get_cur_user(char *user);
+void get_cur_user(char *user) {
+    if ( strlen(CUR_USER)==0 ) {
+        MU_dbg("CUR_USER empty");
+        strcpy(user,"admin");
+    } else {
+        memcpy(user,CUR_USER,strlen(CUR_USER));
+    }
+}
+
+static void MU_get_user(const struct client *cl, char *user) {
+    char *usrhead = cl->httpbuf.ptr;
+    char *pwdhead = strfind(usrhead,strlen(usrhead),"&password=",strlen("&password="));
+
+    usrhead += strlen("username=");
+    memcpy( user, usrhead, pwdhead-usrhead );
+
+    MU_dbg(user);
+}
+
+static void MU_clear_luci_cache() {
+    int ret = 0;
+
+    ret = system("echo clear cache > /tmp/luci_action");
+    ret = system("rm -Rf /tmp/luci-*");
+    if ( ret == -1 ) {
+        system("echo fail >> /debug");
+    } else if ( ret==0 ) {
+        system("echo ignore >> /debug");
+    } else {
+        system("echo finish >> /debug");
+    }
+}
+#endif
+
 static struct http_request * uh_http_header_parse(struct client *cl,
                                                                                 char *buffer, int buflen)
 {
@@ -281,7 +339,21 @@
                if (method && !strcmp(method, "GET"))
                        req->method = UH_HTTP_MSG_GET;
                else if (method && !strcmp(method, "POST"))
-                       req->method = UH_HTTP_MSG_POST;
+               #ifndef MULTI_USER
+        {
+            char user[32] = {0};
+
+            MU_get_user(cl,user);
+            if( strncmp(user,CUR_USER,4)!=0 ) {
+                MU_clear_luci_cache();
+            }
+            memcpy(CUR_USER,user,32);
+
+            req->method = UH_HTTP_MSG_POST;
+        }
+        #else
+            req->method = UH_HTTP_MSG_POST;
+        #endif
                else if (method && !strcmp(method, "HEAD"))
                        req->method = UH_HTTP_MSG_HEAD;
                else
--- a/uhttpd-cgi.c
+++ b/uhttpd-cgi.c
@@ -486,12 +486,32 @@
                        if (chdir(pi->root))
                                perror("chdir()");

+            #ifndef MULTI_USER
+            {
+                extern void get_cur_user(char *user);
+                extern void MU_dbg(char *info);
+
+                char user[32] = {0};
+                char info[32] = {0};
+
+                get_cur_user(user);
+
+                sprintf(info,"exec via %s",user);
+                MU_dbg(info);
+
+                if (ip!=NULL) {
+                    execl("/bin/su","su",user,"-c",ip->path,pi->phys,NULL);
+                } else {
+                    execl("/bin/su","su",user,"-c",pi->phys,NULL);
+                }
+            }
+            #else
                        if (ip != NULL)
-                               execl(ip->path, ip->path, pi->phys, NULL);
-                       else
+                               execl(ip->path, ip->path, pi->phys, NULL);
+            else
                                execl(pi->phys, pi->phys, NULL);
-
-                       /* in case it fails ... */
+            #endif
+            /* in case it fails ... */
                        printf("Status: 500 Internal Server Error\r\n\r\n"
                                   "Unable to launch the requested CGI program:\n"
                                   "  %s: %s\n", ip ? ip->path : pi->phys, strerror(errno));

實現admin執行UCI修改

完成上步操作後,使用不同用戶登錄可以根據用戶執行LuCI,但是admin和user都只能查詢UCI相關的一些配置,而我期望的admin能夠修改配置。

經過一些嘗試,發現僅僅爲admin賦予uci的執行權限和相關配置文件的寫權限扔不能執行UCI修改操作(uci set/commit)。

我希望修改的配置是通過UCI Map來進行修改的,修改usr/lib/lua/luci/cbi.lua文件的Map.set和Map.parse,使用su權限來執行uci set 和 commit。

後續工作

目前實現雖然支持了多用戶的操作權限控制,但是對於用戶切換時訪問效率低,後續可以修改luci,針對每個用戶創建一份cache。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章