写在前面
这篇文章是关于作者在学习PortSwigger的API Test类型漏洞时的记录和学习笔记
使用到的工具为Burp Suite Pro
漏洞简介
什么是api
API全称为Application Interface,是应用程序对外提供功能的接口,现在主要有三种api风格,分别是JSON风格的api,RESTful风格的api以及Graphic风格的api
JSON风格
请求获取用户信息
POST /api/getUser HTTP/1.1
Host: example.com
Content-Type: application/json
{
"userId": 1
}
RESTful风格
请求获取用户信息
GET /api/users/1 HTTP/1.1
Host: example.com
请求修改用户信息
POST /api/users HTTP/1.1
Host: example.com
Content-Type: application/json
{
"name": "Jane Doe",
"email": "[email protected]"
}
Graphic风格
请求获取用户信息
POST /graphql HTTP/1.1
Host: example.com
Content-Type: application/json
{
"query": "{ user(id: 1) { id, name, email } }"
}
API测试是什么
API测试这种漏洞主要包含了对开放api期望运行逻辑的破坏以及对未开放的api的检测和调用,导致的危害可能有敏感信息泄露,应用行为被改变等
这篇文章主要讨论JSON和RESTful APIs
当你在测试一个api的时候,关注下面这些点:
-
api接收并处理的数据,包括必需的和可选的
-
api接受的请求类型,包括请求方法和media formats
-
速率限制和认证机制
和api交互
使用不同的请求方法
HTTP1.0定义了三种请求方法: GET、POST、HEAD
-
GET
方法请求一个指定资源的表示形式,使用GET
的请求应该只被用于获取数据。 -
HEAD
方法请求一个与GET
请求的响应相同的响应,但没有响应体。 -
POST
方法用于将实体提交到指定的资源,通常导致在服务器上的状态变化或副作用。
HTTP1.1新增了六种请求方法:OPTIONS、PUT、DELETE、TRACE 、CONNECT、PATCH -
OPTIONS
方法用于描述目标资源的通信选项。 -
PUT
方法用有效载荷请求替换目标资源的所有当前表示。 -
DELETE
方法删除指定的资源。 -
TRACE
方法沿着到目标资源的路径执行一个消息环回测试。 -
CONNECT
方法建立一个到由目标资源标识的服务器的隧道。 -
PATCH
方法用于对资源应用部分修改。
使用不同的Content-Type
以下是最常使用的10种Content-Typeapplication/json
-
用途:用于 JSON 格式的数据传输,常用于 RESTful API。
text/html
-
用途:用于 HTML 格式的数据传输,常用于 Web 页面响应。
application/x-www-form-urlencoded
-
用途:用于 HTML 表单提交的编码方式,将表单数据编码为键值对。
multipart/form-data
-
用途:用于文件上传表单的编码方式,允许同时上传文件和其他数据。
text/plain
-
用途:用于纯文本数据传输,没有特殊的格式化要求。
application/xml
-
用途:用于 XML 格式的数据传输。
application/javascript
-
用途:用于传输 JavaScript 代码。
application/octet-stream
-
用途:用于传输二进制数据,不指定特定的文件格式,通常用于文件下载。
image/jpeg
-
用途:用于传输 JPEG 格式的图像文件。
image/png
-
用途:用于传输 PNG 格式的图像文件。
Labs
lab1
lab地址:Exploiting an API endpoint using documentation
这个lab是最基础的,通关条件是删除用户carlos的账户
登陆网站,尝试发现的所有功能,然后观察burpsuite的HTTP History,发现一个方法为PATCH的请求,api端点为/api/user/wiener
,直接尝试修改http请求方法为delete,对用户carlos进行请求
lab2
lab地址:Exploiting server-side parameter pollution in a query string
这一个lab关注的点是请求字符串中的参数污染,通关条件是登陆administrator的账户,删除carlos账户
惯例先进行所有的操作,观察burpsuite的http history
将/fogot-password的post请求发送到repeater研究
将请求发送到intruder模块对field参数的值进行爆破
爆破显示正确的结果
将field的值设置为email发送原post请求,发现响应和没有设置field一样,再去http history查看有没有其他可能的值
发现GET /static/js/forgotPassword.js
,js文件内容如下
let forgotPwdReady = (callback) => {
if (document.readyState !== "loading") callback();
else document.addEventListener("DOMContentLoaded", callback);
}
function urlencodeFormData(fd){
let s = '';
function encode(s){ return encodeURIComponent(s).replace(/%20/g,'+'); }
for(let pair of fd.entries()){
if(typeof pair[1]=='string'){
s += (s?'&':'') + encode(pair[0])+'='+encode(pair[1]);
}
}
return s;
}
const validateInputsAndCreateMsg = () => {
try {
const forgotPasswordError = document.getElementById("forgot-password-error");
forgotPasswordError.textContent = "";
const forgotPasswordForm = document.getElementById("forgot-password-form");
const usernameInput = document.getElementsByName("username").item(0);
if (usernameInput && !usernameInput.checkValidity()) {
usernameInput.reportValidity();
return;
}
const formData = new FormData(forgotPasswordForm);
const config = {
method: "POST",
headers: {
"Content-Type": "x-www-form-urlencoded",
},
body: urlencodeFormData(formData)
};
fetch(window.location.pathname, config)
.then(response => response.json())
.then(jsonResponse => {
if (!jsonResponse.hasOwnProperty("result"))
{
forgotPasswordError.textContent = "Invalid username";
}
else
{
forgotPasswordError.textContent = `Please check your email: "${jsonResponse.result}"`;
forgotPasswordForm.className = "";
forgotPasswordForm.style.display = "none";
}
})
.catch(err => {
forgotPasswordError.textContent = "Invalid username";
});
} catch (error) {
console.error("Unexpected Error:", error);
}
}
const displayMsg = (e) => {
e.preventDefault();
validateInputsAndCreateMsg(e);
};
forgotPwdReady(() => {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const resetToken = urlParams.get('reset-token');
if (resetToken)
{
window.location.href = `/forgot-password?reset_token=${resetToken}`;
}
else
{
const forgotPasswordBtn = document.getElementById("forgot-password-btn");
forgotPasswordBtn.addEventListener("click", displayMsg);
}
});
最关键的一段代码是:
forgotPwdReady(() => {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const resetToken = urlParams.get('reset-token');
if (resetToken)
{
window.location.href = `/forgot-password?reset_token=${resetToken}`;
}
else
{
const forgotPasswordBtn = document.getElementById("forgot-password-btn");
forgotPasswordBtn.addEventListener("click", displayMsg);
}
});
代码中涉及一个参数reset_token
,尝试将field这只为reset_token
,发现响应变化了
根据/forgot-password?reset_token=${resetToken}
,重新构建get请求
然后就是设置新密码,删除carlos账户
lab3
lab地址:Finding and exploiting an unused API endpoint
这个lab关注的点是发现和测试未使用的api端点,通关条件是购买一件商品
进去先尝试所有功能,发现无法充值,余额为0,我的思路是将商品价格修改或绕过付款流程
观察brupsuite的http history,发现:GET /api/products/1/price HTTP/2
,发送到repeater研究
先修改http方法为OPTION,发现允许get和patch方法
构建patch方法的请求
构造指定格式的数据,数据是猜测的,但是比较好猜
之后就可以零元购,通关了
lab4
lab地址:Exploiting a mass assignment vulnerability
这个lab关注批量赋值漏洞,通关条件是购买一件商品,还是之前的思路
按惯例先尝试所有功能,然后查看burpsuite的http history
发现两个有意思的请求:POST /api/checkout HTTP/2
和GET /api/checkout HTTP/2
点击付款按钮时会先发送POST请求,数据为购买的商品的列表,包括商品id和数量
{"chosen_products":[{"product_id":"1","quantity":1}]}
GET请求则会返回该次交易的相关信息,如下图:
第一个尝试还是先修改商品的价格,发现没有成功
然后修改代表折扣的字段,发送请求后就直接成功购买了
lab5
lab地址:Exploiting server-side parameter pollution in a REST URL
这个lab和lab2的思路是一样的,关注的重点在改变服务端请求的行为,但是多了许多防御措施,需要更多技巧结合,通关条件和lab2一样
先使用lab2用过的测试技巧,测试后推测服务端请求可能把username内容放在url的路径部分
构造username为:./administrator
读取配置文件,发现url路径:/api/api/internal/v1/users/{username}/field/{field}
将username参数改为administrator/field/x%23
,试图重写field
同lab2一样,查看GET /static/js/forgotPassword.js
构造username为:administrator/field/passwordResetToken%23
通过路径遍历进行指定版本
构造get请求发送
然后修改密码,删除carlos账户,通关
如何防御API导致的漏洞
首先,最好从开始设计系统时就考虑安全因素
其次,最好遵守下列准则
-
如果不想你的api被公开地访问,保管好你的文档
-
确保你的文档足够全面,允许合法测试人员收集全面的攻击面
-
设置允许接受的http方法
-
验证收到的请求或响应是期望的格式
-
使用普遍的报错信息以避免泄露有价值的信息
-
对所有版本的api设置防御措施,而不仅仅是当前主要版本
-
将用户可以修改的属性列入白名单,用户不能修改的敏感属性列入黑名单
4A评测 - 免责申明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。
不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。
侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)