收起左侧

为FN Connect穿上铠甲(WAF)

1
回复
145
查看
[ 复制链接 ]

3

主题

16

回帖

0

牛值

江湖小虾

写在最前面的注意事项!!!

  1. 下面所提供的方式方法并不一定适用于各种FnOS版本,笔者只在x86的1.1.19版本中进行过测试。
  2. pxy程序进行改造存在一定风险,确定知道自己在干什么再尝试。笔者不为任何损失承担责任。
  3. 虽然标题中称 穿上铠甲,但实际上即便使用 WAF也并不能保证可以抵御所有种类的攻击。笔者写本文只为交流学习,自己使用更安全的环境,并不指望仅靠 WAF可以保证不受 0day攻击
  4. 仅供有一定动手能力的用户尝试,笔者无法保证方法的稳定性,不要在生产环境下使用!!!

1、动机

相信不少 FnOS用户和我一样是把 FnOSNAS作为主力 NAS再用,里面存放了不少并不希望公开的资料。对 NAS的安全性非常敏感,如果 NAS遭受 0day攻击必会带来经济损失。

笔者看到论坛上有不少关于搭建 WAF的文章,且购买设备的时候有获得赠送的 FN Connect,便想在“免费”赠送的 FN Connect上搭建 WAF通过外网"安全"(注意事项3)的访问 NAS,但发现两者并不方便结合在一起。

2、学习

带着问题,笔者尝试来学习一下 FN Connect是如何把端口中转到外网的。
通过分析系统端口和进程,不难发现 pxy是进行中转的主要程序,简单分析一下这个程序,应该基于 frp的实现,采用 frp插件来进行转发。
当然添加了非常多的改动,为了在上面搭建 WAF笔者比较关注两个功能的加入。

一个是通过获取配置自动改变映射端口。
函数 FUN_00786640用来获取端口配置

                             *************************************************************
                             *                           FUNCTION                     
                             *************************************************************
                             undefined  FUN_00786640 ()
             undefined         <UNASSIGNED>   <RETURN>
                             FUN_00786640                                    XREF[2]:     007866e0 (j) , 
                                                                                          FUN_007fdcc0:007fdd00 (c)   
         00786640           CMP        RSP ,qword ptr [R14  + 0x10 ]
         00786644           JBE        LAB_007866d6
         0078664a           PUSH       RBP
         0078664b           MOV        RBP ,RSP
         0078664e           SUB        RSP ,0x48
         00786652           LEA        RAX ,[s_com.trim.network_00d6175f ]   = "com.trim.network"
         00786659           MOV        EBX ,0x10
         0078665e           LEA        RCX ,[s_gw.getting_00d5cd5a ]         = "gw.getting"
         00786665           MOV        EDI ,0xa
         0078666a           XOR        ESI ,ESI
         0078666c           XOR        R8D ,R8D
         0078666f           CALL       FUN_00786700                         undefined FUN_00786700()
         00786674           TEST       RCX ,RCX
         00786677           JZ         LAB_00786687
         00786679           XOR        EAX ,EAX
         0078667b           MOV        RBX ,RCX
         0078667e           MOV        RCX ,RDI
         00786681           ADD        RSP ,0x48
         00786685           POP        RBP
         00786686           RET
                             LAB_00786687                                    XREF[1]:     00786677 (j)   
         00786687           MOV        qword ptr [RSP  + 0x30 ],RAX
         0078668c           MOV        qword ptr [RSP  + 0x38 ],RBX
         00786691           LEA        RAX ,[DAT_00cb58e0 ]                  = 18h
         00786698           CALL       FUN_00417d20                         undefined FUN_00417d20()
         0078669d           MOV        qword ptr [RSP  + 0x40 ],RAX
         007866a2           MOV        RCX ,qword ptr [RSP  + 0x30 ]
         007866a7           MOV        RCX ,qword ptr [RCX  + 0x18 ]
         007866ab           MOV        RAX ,qword ptr [RSP  + 0x38 ]
         007866b0           CALL       RCX
         007866b2           LEA        RDI ,[DAT_00be8320 ]                  = 08h
         007866b9           MOV        RSI ,qword ptr [RSP  + 0x40 ]
         007866be           NOP
         007866c0           CALL       FUN_00515d00                         undefined FUN_00515d00()
         007866c5           MOV        RCX ,RBX
         007866c8           MOV        RBX ,RAX
         007866cb           MOV        RAX ,qword ptr [RSP  + 0x40 ]
         007866d0           ADD        RSP ,0x48
         007866d4           POP        RBP
         007866d5           RET
                             LAB_007866d6                                    XREF[1]:     00786644 (j)   
         007866d6           CALL       FUN_00478720                         undefined FUN_00478720()
         007866db           NOP        dword ptr [RAX  + RAX *0x1 ]
         007866e0           JMP        FUN_00786640

通过函数引用,不难找到函数 FUN_007fdcc0负责自动从配置中更新映射端口

void FUN_007fdcc0(void)

{
  char cVar1;
  long *plVar2;
  undefined *puVar3;
  undefined *puVar4;
  long unaff_RBX;
  undefined8 *in_R11;
  long unaff_R14;
  undefined1 auVar5 [16];
  undefined8 *puStack_60;
  undefined8 uStack_58;
  undefined8 *puStack_50;
  undefined8 uStack_48;
  undefined8 *puStack_40;
  undefined8 uStack_38;
  undefined8 *puStack_30;
  undefined8 uStack_28;
  undefined8 *puStack_20;
  undefined8 uStack_18;
  undefined **ppuStack_10;
  
  while (&puStack_50 <= *(undefined8 ***)(unaff_R14 + 0x10)) {
    FUN_00478720();
  }
  ppuStack_10 = &PTR_FUN_00d98f40;
  plVar2 = (long *)FUN_00786640();
  if (unaff_RBX != 0) {
    (**(code **)(unaff_RBX + 0x18))();
    auVar5 = FUN_0046ff00();
    uStack_18 = auVar5._0_8_;
    puStack_20 = &DAT_00c07900;
    FUN_0059dc60(0x20,&puStack_20,auVar5._8_8_,"get gateway http port error : %s",1,1);
  }
  puVar4 = PTR_s_8000_01403e00;
  if ((0 < *plVar2) &&
     ((puVar3 = (undefined *)FUN_0048afc0(), DAT_01403e08 != 10 ||
      (cVar1 = FUN_004044a0(), puVar4 = PTR_s_8000_01403e00, cVar1 == '\0')))) {
    uStack_38 = FUN_0046ff00();
    puStack_40 = &DAT_00c07900;
    auVar5 = FUN_0046ff00();
    uStack_28 = auVar5._0_8_;
    puStack_30 = &DAT_00c07900;
    FUN_0059dc60(0x2a,&puStack_40,auVar5._8_8_,"update gateway http port from [%s] to [%s]",2,2) ;
    DAT_01403e08 = 10;
    puVar4 = puVar3;
    if (DAT_01449d70 != 0) {
      FUN_0047a620();
      *in_R11 = puVar3;
      in_R11[1] = PTR_s_8000_01403e00;
    }
  }
  PTR_s_8000_01403e00 = puVar4;
  if ((0 < plVar2[1]) &&
     ((puVar4 = (undefined *)FUN_0048afc0(), DAT_01403e18 != 10 ||
      (cVar1 = FUN_004044a0(), cVar1 == '\0')))) {
    uStack_58 = FUN_0046ff00();
    puStack_60 = &DAT_00c07900;
    auVar5 = FUN_0046ff00();
    uStack_48 = auVar5._0_8_;
    puStack_50 = &DAT_00c07900;
    FUN_0059dc60(0x2b,&puStack_60,auVar5._8_8_,"update gateway https port from [%s] to [%s]",2,2 );
    DAT_01403e18 = 10;
    if (DAT_01449d70 != 0) {
      FUN_0047a620();
      *in_R11 = puVar4;
      in_R11[1] = PTR_DAT_01403e10;
    }
    PTR_DAT_01403e10 = puVar4;
    FUN_007fbf80();
  }
  FUN_007879a0();
  return;
}

类似的程序中还有的函数 FUN_007fe000从dbus中获取配置,做了同样的事情。

void FUN_007fe000(void)

{
  char cVar1;
  long in_RAX;
  long lVar2;
  undefined *puVar3;
  undefined *puVar4;
  undefined8 *in_R11;
  long unaff_R14;
  undefined1 auVar5 [16];
  undefined8 *puStack_68;
  undefined8 uStack_60;
  undefined8 *puStack_58;
  undefined8 uStack_50;
  undefined8 *puStack_48;
  undefined8 uStack_40;
  undefined8 *puStack_38;
  undefined8 uStack_30;
  undefined8 *puStack_28;
  undefined8 uStack_20;
  long *plStack_18;
  undefined **ppuStack_10;
  
  while (&uStack_60 <= *(undefined8 **)(unaff_R14 + 0x10)) {
    FUN_00478720();
  }
  ppuStack_10 = &PTR_FUN_00d98f40;
  if (*(long *)(in_RAX + 0x38) != 0) {
    if ((undefined8 *)**(undefined8 **)(in_RAX + 0x30) != &DAT_00c07900) {
      FUN_004140a0();
      FUN_0043b5c0();
      return;
    }
    plStack_18 = (long *)FUN_00417d20();
    FUN_0045a4e0();
    lVar2 = FUN_00515d00(&DAT_00be8320,plStack_18);
    if (lVar2 != 0) {
      (**(code **)(lVar2 + 0x18))();
      auVar5 = FUN_0046ff00();
      uStack_20 = auVar5._0_8_;
      puStack_28 = &DAT_00c07900;
      FUN_0059dc60(0x1a,&puStack_28,auVar5._8_8_,"get dbus signal error : %s",1,1);
    }
    puVar4 = PTR_s_8000_01403e00;
    if ((0 < *plStack_18) &&
       ((puVar3 = (undefined *)FUN_0048afc0(), DAT_01403e08 != 10 ||
        (cVar1 = FUN_004044a0(), puVar4 = PTR_s_8000_01403e00, cVar1 == '\0')))) {
      uStack_40 = FUN_0046ff00();
      puStack_48 = &DAT_00c07900;
      auVar5 = FUN_0046ff00();
      uStack_30 = auVar5._0_8_;
      puStack_38 = &DAT_00c07900;
      FUN_0059dc60(0x34,&puStack_48,auVar5._8_8_,
                   "update gateway http port from dbus from [%s] to [%s]",2,2);
      DAT_01403e08 = 10;
      puVar4 = puVar3;
      if (DAT_01449d70 != 0) {
        FUN_0047a620();
        *in_R11 = puVar3;
        in_R11[1] = PTR_s_8000_01403e00;
      }
    }
    PTR_s_8000_01403e00 = puVar4;
    if ((0 < plStack_18[1]) &&
       ((puVar4 = (undefined *)FUN_0048afc0(), DAT_01403e18 != 10 ||
        (cVar1 = FUN_004044a0(), cVar1 == '\0')))) {
      uStack_60 = FUN_0046ff00();
      puStack_68 = &DAT_00c07900;
      auVar5 = FUN_0046ff00();
      uStack_50 = auVar5._0_8_;
      puStack_58 = &DAT_00c07900;
      FUN_0059dc60(0x35,&puStack_68,auVar5._8_8_,
                   "update gateway https port from dbus from [%s] to [%s]",2,2);
      DAT_01403e18 = 10;
      if (DAT_01449d70 != 0) {
        FUN_0047a620();
        *in_R11 = puVar4;
        in_R11[1] = PTR_DAT_01403e10;
      }
      PTR_DAT_01403e10 = puVar4;
      FUN_007fbf80();
    }
  }
  FUN_007879a0();
  return;
}

二是默认使用的映射端口。

                             PTR_s_8000_01403e00                             XREF[16]:    FUN_007fdcc0:007fdd9d (R) , 
                                                                                          FUN_007fdcc0:007fddc9 (R) , 
                                                                                          FUN_007fdcc0:007fde73 (R) , 
                                                                                          FUN_007fdcc0:007fde7e (W) , 
                                                                                          FUN_007fe000:007fe149 (R) , 
                                                                                          FUN_007fe000:007fe17a (R) , 
                                                                                          FUN_007fe000:007fe221 (R) , 
                                                                                          FUN_007fe000:007fe22c (W) , 
                                                                                          FUN_00a395a0:00a39782 (R) , 
                                                                                          00a3b0cd (R) , 
                                                                                          FUN_00a3bf40:00a3bff2 (R) , 
                                                                                          FUN_00a4b820:00a4b852 (R) , 
                                                                                          FUN_00a4b820:00a4b86a (R) , 
                                                                                          FUN_00a4f2e0:00a4f8e7 (R) , 
                                                                                          FUN_00a4f2e0:00a4fcb8 (R) , 
                                                                                          FUN_00a51680:00a51983 (R)   
         01403e00           addr       s_8000_00d506da                      = "8000"

通过调查引用不难发现,改变端口号全局变量的引用只在上面两个函数中存在。

3、改造

基本思路是停掉自动获取 gateway端口的功能,换掉默认映射的端口,这样就可以让 FN Connect映射我们指定的端口。
那么我们将函数 FUN_007fdcc0FUN_007fe000改为 ret直接返回不做任何操作,并改变地址 01403e00上的端口号就能固定使用一个我们指定的端口号来让中继转发。在这个端口上套上对 FnOS WebUIWAF转发既能达成目的。因为是 pxy是利用插件来做的,服从 frp的方式在应用 WAF时我们采用 http来中转即可。

4、总结

通过改造 pxy我们可以给 FN Connect上套层 WAF一定程度上带来一些"安全感",但本方法并不能保证跨版本依旧可行,且有点费事,还是希望官方能将提供更多配置选项方便用户配置。最后笔者还需强调一下,对于防御 0day攻击通过搭建 WAF带来的安全性依旧有限,请各位根据自身情况谨慎选择。

5、参考连接

收藏
送赞
分享

3

主题

1

回帖

0

牛值

江湖小虾

3 小时前 显示全部楼层
要是官方能提供一下快捷配置转到的端口就好了,现在都不敢开fnconnect😂
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则