OpenWrt系统安全改进<五> --- Web 访问权限分级

2023-11-06

摘要

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

--- 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。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenWrt系统安全改进<五> --- Web 访问权限分级 的相关文章

  • openwrt reboot流程

    openwrt 系统中 当执行了 reboot 命令 系统将会发生什么事情呢 如何进行重启的呢 下面来一起看一下 reboot 应用层操作 首先 reboot 是由busybox 它是一个集成了常用Linux命令和工具的软件 提供的一个Li
  • Openwrt编译报错 TCP Fast Open is not available for client mode 的解决办法

    报错信息 configure error TCP Fast Open is not available for client mode please rerun without enable tfo client gmake 3 Makef
  • openwrt开启dnsmasq-full替换默认dnsmasq

    因为要用到dnsmasq的ipset功能 所以需要安装dnsmasq full 方法如下 1 进入openwrt目录 配置 make meconfig 在base system里面 2 取消原来的dnsmasq 选中dnsmasq full
  • 启明智显分享

    提示 作为Espressif 乐鑫科技 大中华区合作伙伴及sigmastar 厦门星宸 VAD合作伙伴 启明智显不仅用心整理了你在开发过程中可能会遇到的问题以及快速上手的简明教程供开发小伙伴参考 同时也用心整理了乐鑫及星宸科技的新产品 新方
  • 在K2P路由器,非官方openwrt固件,安装软件遇到的坑!

    手上有一台斐讯K2P A2版本的路由器 一直空闲在宿舍 最近发现这个路由器被破解了 可以刷上不死breed 还有很多大神做的固件 因此我想用它刷上openwrt系统后 安装某软件 从而直接在路由器上完成学校的宽带验证登陆 接下来我就介绍我在
  • OpenWRT移植EC200A驱动,并实现wifi和lan的上网,及wan和4g的负载均衡(五)

    网卡驱动方式 转载 拨号PPP NDIS RNDIS CDC ECM NCM QMI WWAN GOBINET RMNET MBIM概念介绍 https blog csdn net qlexcel article details 11715
  • luci 开发中一些小总结

    一 只保存不应用 当修改或者增加一项配置后 如果不是点击 保存 应用 按钮 而是点击 保存 按钮 这些配置不会保存各个到配置文件中 而是暂时保存到如下临时目录下 tmp uci 例如 当修改了网络配置 没有应用时 会生成一个 tmp uci
  • openwrt luci使用本地软件源更新软件包,更新package.sig签名

    官方的源在国外 一般访问速度比较慢 本地源可以快速解决这个问题 有时自己编译的软件升级发布版本使用本地源 能够更好的维护与安装 为了保证兼容性 尽量使用同一个源提供的SDK打包的源软件 把编译出来的ipk文件上传到本地服务器 在索引中添加新
  • OpenWrt系统配置UCI

    UCI简介 UCI Unified Configuration Interface 是 Openwrt 中的统一配置接口 官方文档参考 每一个程序的配置文件都保存在 etc config 目录 可以通过文本编辑器 uci 一个可执行程序 以
  • 703n无法进入路由管理界面reset无效重刷方法

    现在没法接网线获取不到地址 winscp也登不了 请问除了ttl线外不拆机能重刷吗 安全模式恢复 具体方法如下 网线连接电脑和703n 设置电脑ip地址为192 168 1 2 掩码默认 网关192 168 1 1 电脑 gt 开始 gt
  • openwrt x86 版安装纪实

    1 下载源码 已有编译环境 直接在ubuntu 中 git openwrt 源码 https dev openwrt org wiki GetSource git clone b chaos calmer git github com op
  • 【openwrt】【编译问题】openwrt编译问题

    undefined reference to pthread once 在某次openwrt编译过程中出现了undefined reference to pthread once错误 具体报错信息如下 openwrt staging dir
  • Ubuntu16.04下交叉编译适配openwrt(CC版本)的swoole扩展库(swoole-1.10.3)

    Ubuntu16 04下交叉编译适配openwrt CC版本 的swoole扩展库 swoole 1 10 3 文章目录 Ubuntu16 04下交叉编译适配openwrt CC版本 的swoole扩展库 swoole 1 10 3 一 简
  • 通俗易懂权限管理模块设计-Java

    最近一直在做CMS系统 发现一些内容其实都是重复出现的 例如权限管理模块 权限管理模块就是为了管理用户是否有权利访问某个权限 如果不能则拒绝访问 其实Java中已经有很成熟的权限管理框架 例如 Shiro Spring Security等
  • 在openwrt使用C语言增加ubus接口(包含C uci操作)

    在openwrt使用C语言增加ubus接口 包含C uci操作 文章目录 在openwrt使用C语言增加ubus接口 包含C uci操作 创建自己的软件包 软件包结构 编写代码和启动脚本 重点 案例大致分析 实现过程 ubus demo i
  • linux下安装awk

    sudo apt get install gawk 注意名称
  • OpenWrt添加软件包(一)

    本文参考https wiki openwrt org zh cn doc devel packages http blog csdn net teddy99999 article details 17537545 OpenWrt是一个比较完
  • UCI提供给shell和lua使用的配置接口

    转自 http m blog csdn net article details id 47989493 1 uci提供给shell使用的配置借口有两套 1 config get用来读取一个config值 命令格式如下 config getv
  • [转载]解决PPPOE宽带拨号经常掉线的一种方法(适合刷了第三方固件的无线路由)

    文章作者 姜南 Slyar 文章来源 Slyar Home www slyar com 转载请注明 谢谢合作 最近在进行下载或看视频等大量占用网络带宽的行为时 宽带PPPOE连接非常不稳定 经常自动掉线 严重影响我的下载进程和看视频的乐趣
  • 安装“opkg”?

    我正在尝试将软件包安装到我的 OpenWrt SDK 中 为此 您必须通过键入以下内容来使用 OPKG 包管理器 opkg update opkg install

随机推荐