API测试(一):PortSwigger靶场笔记

写在前面

这篇文章是关于作者在学习PortSwigger的API Test类型漏洞时的记录和学习笔记 使用到的工具为Burp Suite Pro

漏洞简介

什么是api

API全称为Application Interface,是应用程序对外提供功能的接口,现在主要有三种api风格,分别是JSON风格的api,RESTful风格的api以及Graphic风格的api

JSON风格

请求获取用户信息

1POST /api/getUser HTTP/1.1 2Host: example.com 3Content-Type: application/json 4 5{ 6 "userId": 1 7}

RESTful风格

请求获取用户信息

1GET /api/users/1 HTTP/1.1 2Host: example.com

请求修改用户信息

1POST /api/users HTTP/1.1 2Host: example.com 3Content-Type: application/json 4 5{ 6 "name": "Jane Doe", 7 "email": "jane.doe@example.com" 8}

Graphic风格

请求获取用户信息

1POST /graphql HTTP/1.1 2Host: example.com 3Content-Type: application/json 4 5{ 6 "query": "{ user(id: 1) { id, name, email } }" 7}

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-Type application/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进行请求 l1-s1.png l1-s2.png

lab2

lab地址:Exploiting server-side parameter pollution in a query string 这一个lab关注的点是请求字符串中的参数污染,通关条件是登陆administrator的账户,删除carlos账户 惯例先进行所有的操作,观察burpsuite的http history 将/fogot-password的post请求发送到repeater研究 l2-s1.png l2-s2.png l2-s3.png 将请求发送到intruder模块对field参数的值进行爆破 l2-s4.png 爆破显示正确的结果 l2-s5.png 将field的值设置为email发送原post请求,发现响应和没有设置field一样,再去http history查看有没有其他可能的值 发现GET /static/js/forgotPassword.js,js文件内容如下

1let forgotPwdReady = (callback) => { 2 if (document.readyState !== "loading") callback(); 3 else document.addEventListener("DOMContentLoaded", callback); 4} 5 6function urlencodeFormData(fd){ 7 let s = ''; 8 function encode(s){ return encodeURIComponent(s).replace(/%20/g,'+'); } 9 for(let pair of fd.entries()){ 10 if(typeof pair[1]=='string'){ 11 s += (s?'&':'') + encode(pair[0])+'='+encode(pair[1]); 12 } 13 } 14 return s; 15} 16 17const validateInputsAndCreateMsg = () => { 18 try { 19 const forgotPasswordError = document.getElementById("forgot-password-error"); 20 forgotPasswordError.textContent = ""; 21 const forgotPasswordForm = document.getElementById("forgot-password-form"); 22 const usernameInput = document.getElementsByName("username").item(0); 23 if (usernameInput && !usernameInput.checkValidity()) { 24 usernameInput.reportValidity(); 25 return; 26 } 27 const formData = new FormData(forgotPasswordForm); 28 const config = { 29 method: "POST", 30 headers: { 31 "Content-Type": "x-www-form-urlencoded", 32 }, 33 body: urlencodeFormData(formData) 34 }; 35 fetch(window.location.pathname, config) 36 .then(response => response.json()) 37 .then(jsonResponse => { 38 if (!jsonResponse.hasOwnProperty("result")) 39 { 40 forgotPasswordError.textContent = "Invalid username"; 41 } 42 else 43 { 44 forgotPasswordError.textContent = `Please check your email: "${jsonResponse.result}"`; 45 forgotPasswordForm.className = ""; 46 forgotPasswordForm.style.display = "none"; 47 } 48 }) 49 .catch(err => { 50 forgotPasswordError.textContent = "Invalid username"; 51 }); 52 } catch (error) { 53 console.error("Unexpected Error:", error); 54 } 55} 56 57const displayMsg = (e) => { 58 e.preventDefault(); 59 validateInputsAndCreateMsg(e); 60}; 61 62forgotPwdReady(() => { 63 const queryString = window.location.search; 64 const urlParams = new URLSearchParams(queryString); 65 const resetToken = urlParams.get('reset-token'); 66 if (resetToken) 67 { 68 window.location.href = `/forgot-password?reset_token=${resetToken}`; 69 } 70 else 71 { 72 const forgotPasswordBtn = document.getElementById("forgot-password-btn"); 73 forgotPasswordBtn.addEventListener("click", displayMsg); 74 } 75});

最关键的一段代码是:

1forgotPwdReady(() => { 2 const queryString = window.location.search; 3 const urlParams = new URLSearchParams(queryString); 4 const resetToken = urlParams.get('reset-token'); 5 if (resetToken) 6 { 7 window.location.href = `/forgot-password?reset_token=${resetToken}`; 8 } 9 else 10 { 11 const forgotPasswordBtn = document.getElementById("forgot-password-btn"); 12 forgotPasswordBtn.addEventListener("click", displayMsg); 13 } 14});

代码中涉及一个参数reset_token,尝试将field这只为reset_token,发现响应变化了 l2-s6.png 根据/forgot-password?reset_token=${resetToken},重新构建get请求 l2-s7.png 然后就是设置新密码,删除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方法 l3-s1.png 构建patch方法的请求 l3-s2.png 构造指定格式的数据,数据是猜测的,但是比较好猜 l3-s3.png 之后就可以零元购,通关了

lab4

lab地址:Exploiting a mass assignment vulnerability 这个lab关注批量赋值漏洞,通关条件是购买一件商品,还是之前的思路 按惯例先尝试所有功能,然后查看burpsuite的http history 发现两个有意思的请求:POST /api/checkout HTTP/2GET /api/checkout HTTP/2 点击付款按钮时会先发送POST请求,数据为购买的商品的列表,包括商品id和数量

{"chosen_products":[{"product_id":"1","quantity":1}]}

GET请求则会返回该次交易的相关信息,如下图: l4-s1.png 第一个尝试还是先修改商品的价格,发现没有成功 l4-s2.png 然后修改代表折扣的字段,发送请求后就直接成功购买了 l4-s3.png

lab5

lab地址:Exploiting server-side parameter pollution in a REST URL 这个lab和lab2的思路是一样的,关注的重点在改变服务端请求的行为,但是多了许多防御措施,需要更多技巧结合,通关条件和lab2一样 先使用lab2用过的测试技巧,测试后推测服务端请求可能把username内容放在url的路径部分 l5-e1.png l5-e2.png l5-e3.png 构造username为:./administrator l5-s1.png l5-s2.png 读取配置文件,发现url路径:/api/api/internal/v1/users/{username}/field/{field} l5-s3.png 将username参数改为administrator/field/x%23,试图重写field l5-s4.png 同lab2一样,查看GET /static/js/forgotPassword.js l5-i1.png 构造username为:administrator/field/passwordResetToken%23 l5-s5.png 通过路径遍历进行指定版本 l5-s6.png 构造get请求发送 l5-s8.png 然后修改密码,删除carlos账户,通关

如何防御API导致的漏洞

首先,最好从开始设计系统时就考虑安全因素 其次,最好遵守下列准则

  • 如果不想你的api被公开地访问,保管好你的文档
  • 确保你的文档足够全面,允许合法测试人员收集全面的攻击面
  • 设置允许接受的http方法
  • 验证收到的请求或响应是期望的格式
  • 使用普遍的报错信息以避免泄露有价值的信息
  • 对所有版本的api设置防御措施,而不仅仅是当前主要版本
  • 将用户可以修改的属性列入白名单,用户不能修改的敏感属性列入黑名单
点赞
收藏

评论区

加载中...

相关推荐

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

PPDB:今晚老齐直播

【今晚老齐直播】今晚(本周三晚)20:0021:00小白开始“用”飞桨(https://www.oschina.net/action/visit/ad?id1185)由PPDE(飞桨(https://www.oschina.net/action/visit/ad?id1185)开发者专家计划)成员老齐,为深度学习小白指点迷津。

Python网络爬虫与信息提取

title:Python网络爬虫与信息提取date:2020121001:00:23tags:Pythoncategories:学习笔记写在前面不知道写啥其实说实话TOC网络爬虫之规则安装requests库cmd命令行打开输入pip3installrequests,等待即可简单测试,爬一下bkjwpythonimportrequ

AJAX学习

作者声明:本博客中所写的文章,都是博主自学过程的笔记,参考了很多的学习资料,学习资料和笔记会注明出处,所有的内容都以交流学习为主。有不正确的地方,欢迎批评指正。本节课学习视频来自于:https://www.bilibili.com/video/av21373626(https://www.oschina.net/action/GoToLi

Redis哈希(Hash)

个人学习笔记Hash是一个string类型的field和value的映射表,hash适合存储对象。插入HashHMSETzxqname"redistutorial"description"redisbasiccommandsforcaching"likes20visitors23000获取Hash