Skip to content

Commit

Permalink
added api versioning
Browse files Browse the repository at this point in the history
  • Loading branch information
digininja committed Oct 11, 2024
1 parent 979265e commit 9097c0f
Show file tree
Hide file tree
Showing 7 changed files with 228 additions and 88 deletions.
1 change: 1 addition & 0 deletions dvwa/includes/dvwaPage.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ function dvwaHtmlEcho( $pPage ) {
}
$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'open_redirect', 'name' => 'Open HTTP Redirect', 'url' => 'vulnerabilities/open_redirect/' );
$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'encryption', 'name' => 'Cryptography', 'url' => 'vulnerabilities/cryptography/' );
$menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'api', 'name' => 'API', 'url' => 'vulnerabilities/api/' );
}

$menuBlocks[ 'meta' ] = array();
Expand Down
30 changes: 20 additions & 10 deletions vulnerabilities/api/public/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,42 +20,52 @@
$local_uri = array();
foreach ($uri as $pos => $dir) {
if ($dir == "user" || $dir == "health") {
$local_uri = array_slice ($uri, $pos);
$local_uri = array_slice ($uri, $pos - 1);
break;
}
}

// all of our endpoints start with /dvwaapi
// all of our endpoints start with /api/v[0-9]
// everything else results in a 404 Not Found

if (count($local_uri) == 0) {
if (count($local_uri) < 2) {
header("HTTP/1.1 404 Not Found");
exit();
}

$requestMethod = $_SERVER["REQUEST_METHOD"];

switch ($local_uri[0]) {
$version = $local_uri[0];

if (preg_match ("/v([0-9]*)/", $version, $matches)) {
$version = intval ($matches[1]);
} else {
header("HTTP/1.1 404 Not Found");
exit();
}
$controller = $local_uri[1];

switch ($controller) {
case "user":
// the user id is, of course, optional and must be a number:
$userId = null;
if (isset($local_uri[1])) {
$userId = (int) $local_uri[1];
if (isset($local_uri[2])) {
$userId = (int) $local_uri[2];
}

// pass the request method and user ID to the UserController and process the HTTP request:
$controller = new UserController($requestMethod, $userId);
$controller = new UserController($requestMethod, $version, $userId);
$controller->processRequest();
break;
case "health":
if (!isset($local_uri[1])) {
if (!isset($local_uri[2])) {
$gc = new GenericController("notFound");
$gc->processRequest();
break;
}

$command = $local_uri[1];
$controller = new HealthController($requestMethod, $command);
$command = $local_uri[2];
$controller = new HealthController($requestMethod, $version, $command);
$controller->processRequest();
break;
default:
Expand Down
107 changes: 45 additions & 62 deletions vulnerabilities/api/source/low.php
Original file line number Diff line number Diff line change
@@ -1,31 +1,17 @@
<?php
$errors = "";
$success = "";
$messages = "";

if ($_SERVER['REQUEST_METHOD'] == "POST") {
try {
if (array_key_exists ('message', $_POST)) {
$message = $_POST['message'];
if (array_key_exists ('direction', $_POST) && $_POST['direction'] == "decode") {
$encoded = xor_this (base64_decode ($message), $key);
$encode_radio_selected = " ";
$decode_radio_selected = " checked='checked' ";
} else {
$encoded = base64_encode(xor_this ($message, $key));
}
}
if (array_key_exists ('password', $_POST)) {
$password = $_POST['password'];
$decoded = xor_this (base64_decode ($password), $key);
if ($password == "Olifant") {
$success = "Welcome back user";
} else {
$errors = "Login Failed";
}
}
} catch(Exception $e) {
$errors = $e->getMessage();
}
}

$html = "
<p>
Versioning is important in APIs, running multiple versions of an API can allow for backward compatibility and can allow new services to be added without affecting existing users. The downside to keeping old versions alive though is when those older versions contain vulnerabilities.
</p>
";

$html = "
<script>
function update_username(user_json) {
Expand Down Expand Up @@ -54,8 +40,8 @@ function update_username(user_json) {
}
}
function get_user() {
const url = '/vulnerabilities/api/user/3';
function get_users() {
const url = '/vulnerabilities/api/v2/user/';
fetch(url, {
method: 'GET',
Expand All @@ -67,59 +53,56 @@ function get_user() {
return response.json();
})
.then(data => {
update_username (data);
// data.forEach(loadTableData);
loadTableData(data);
})
.catch(error => {
console.error('There was a problem with your fetch operation:', error);
});
}
function update_name() {
const url = '/vulnerabilities/api/user/2';
const name = document.getElementById ('name').value;
const data = JSON.stringify({name: name});
fetch(url, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: data
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
update_username(data);
})
.catch(error => {
console.error('There was a problem with your fetch operation:', error);
});
}
function loadTableData(items) {
const table = document.getElementById('testBody');
items.forEach( item => {
let row = table.insertRow();
let date = row.insertCell(0);
date.innerHTML = item.id;
let name = row.insertCell(1);
name.innerHTML = item.name;
let level = row.insertCell(2);
if (item.level == 0) {
level_name = 'admin';
} else {
level_name = 'user';
}
level.innerHTML = level_name;
});
}
</script>
";

$html .= "
<table id='myTable' class=''>
<thead>
<tr>
<th>id</th>
<th>name</th>
<th>level</th>
</tr>
</thead>
<tbody id='testBody'></tbody>
</table>
<p>
Look at the call used to update your name and exploit it to elevate your user to level 0, admin.
</p>
<div class='success' style='display:none' id='message'>Well done, you elevated your user to admin.</div>
<p id='user_info'></p>
<form method='post' action=\"" . $_SERVER['PHP_SELF'] . "\">
<p>
<label for='name'>Name</label>
<input type='text' value='' name='name' id='name'>
</p>
<p>
<input type=\"button\" value=\"Submit\" onclick='update_name();'>
</p>
</form>
<script>
get_user();
get_users();
</script>
";

Expand Down
127 changes: 127 additions & 0 deletions vulnerabilities/api/source/medium.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
<?php

if ($_SERVER['REQUEST_METHOD'] == "POST") {
try {
if (array_key_exists ('message', $_POST)) {
$message = $_POST['message'];
if (array_key_exists ('direction', $_POST) && $_POST['direction'] == "decode") {
$encoded = xor_this (base64_decode ($message), $key);
$encode_radio_selected = " ";
$decode_radio_selected = " checked='checked' ";
} else {
$encoded = base64_encode(xor_this ($message, $key));
}
}
if (array_key_exists ('password', $_POST)) {
$password = $_POST['password'];
$decoded = xor_this (base64_decode ($password), $key);
if ($password == "Olifant") {
$success = "Welcome back user";
} else {
$errors = "Login Failed";
}
}
} catch(Exception $e) {
$errors = $e->getMessage();
}
}

$html = "
<script>
function update_username(user_json) {
console.log(user_json);
var user_info = document.getElementById ('user_info');
var name_input = document.getElementById ('name');
if (user_json.name == '') {
user_info.innerHTML = 'User details: unknown user';
name_input.value = 'unknown';
} else {
if (user_json.level == 0) {
level = 'admin';
} else {
level = 'user';
}
user_info.innerHTML = 'User details: ' + user_json.name + ' (' + level + ')';
name_input.value = user_json.name;
}
const message_line = document.getElementById ('message');
if (user_json.id == 2 && user_json.level == 0) {
message_line.style.display = 'block';
} else {
message_line.style.display = 'none';
}
}
function get_user() {
const url = '/vulnerabilities/api/v2/user/2';
fetch(url, {
method: 'GET',
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
update_username (data);
})
.catch(error => {
console.error('There was a problem with your fetch operation:', error);
});
}
function update_name() {
const url = '/vulnerabilities/api/v2/user/2';
const name = document.getElementById ('name').value;
const data = JSON.stringify({name: name});
fetch(url, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: data
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
update_username(data);
})
.catch(error => {
console.error('There was a problem with your fetch operation:', error);
});
}
</script>
";

$html .= "
<p>
Look at the call used to update your name and exploit it to elevate your user to level 0, admin.
</p>
<div class='success' style='display:none' id='message'>Well done, you elevated your user to admin.</div>
<p id='user_info'></p>
<form method='post' action=\"" . $_SERVER['PHP_SELF'] . "\">
<p>
<label for='name'>Name</label>
<input type='text' value='' name='name' id='name'>
</p>
<p>
<input type=\"button\" value=\"Submit\" onclick='update_name();'>
</p>
</form>
<script>
get_user();
</script>
";

?>
2 changes: 1 addition & 1 deletion vulnerabilities/api/src/HealthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class HealthController
private $command = null;
private $requestMethod = "GET";

public function __construct($requestMethod, $command) {
public function __construct($requestMethod, $version, $command) {
$this->requestMethod = $requestMethod;
$this->command = $command;
}
Expand Down
31 changes: 24 additions & 7 deletions vulnerabilities/api/src/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,38 @@ final class User
#[OAT\Property(type: 'integer', example: 1)]
public int $level;

function __construct ($id, $name, $level) {
public string $password;

function __construct ($id, $name, $level, $password) {
if (is_null ($id)) {
$id = mt_rand(50,100);
}
$this->id = $id;
$this->name = $name;
$this->level = $level;
$this->password = $password;
}

public function toArray() {
$a = array (
"id" => $this->id,
"name" => $this->name,
"level" => $this->level,
);
public function toArray($version) {
switch ($version) {
case 1:
$a = array (
"id" => $this->id,
"name" => $this->name,
"level" => $this->level,
"password" => $this->password,
);
break;
default:
case 2:
$a = array (
"id" => $this->id,
"name" => $this->name,
"level" => $this->level,
);
break;
}

return $a;
}
}
Expand Down
Loading

0 comments on commit 9097c0f

Please sign in to comment.