使用 WSDL 文件对 SOAP Web 服务运行 Acunetix 扫描查找漏洞
API和Web服务似乎不如websites和Web应用程序受欢迎,但事实并非如此。早在2018年,API就已占全球网络流量的83%。大多数复杂的应用程序都基于微服务,而微服务基本上是使用API相互通信的Web应用程序。Web服务和API容易遭受与Web应用程序相同的漏洞。因此,为了确保它们的安全,您需要知道如何扫描它们。
在本文中,我们将向您展示如何使用WSDL文件对SOAP Web服务运行Acunetix扫描。您将学习如何执行以下操作:
- 构建一个简单的Web服务
- 扫描Web服务
- 识别漏洞
- 缓解和/或解决漏洞
- 重新扫描Web服务以确认解决方案
阶段1:构建简单的Web服务
在本部分中,您将学习如何执行以下操作:
- 在Web服务器上创建数据库以存储数据
- 构建一个/var/www/hello/config.php文件以存储连接到数据库的参数
- 为服务的基本支持功能构建一个/var/www/hello/functions.php文件
- 为该Web服务将提供的API函数构建/var/www/hello/hello_server.php文件;在此示例中,我们将提供一个名为doGetUserName的 API函数。
- 构建一个/var/www/hello/hello_client.php文件,该文件将向用户显示一个输入表单,并使用Web服务检索请求的信息。
- 构建一个/var/www/hello/hello.wsdl以描述Web服务
注意:在实际情况中,上面列表的最后一步通常是第一步。在某些开发环境中,开发人员首先使用可视化工具来创建Web服务的结构,然后生成基本结构以及WSDL文件。在我们的示例中,我们正在手动执行此操作,因此这是最后一步。
步骤1.在Web服务器上创建数据库
从MariaDB或MySQL根提示符下运行以下命令:
MariaDB [(none)]> create user 'hellouser'@'localhost' identified by 'hellouserpass';
MariaDB [(none)]> create database hellodb;
MariaDB [hellodb]> GRANT ALL PRIVILEGES ON hellodb.* TO 'hellouser'@'localhost';
MariaDB [(none)]> use hellodb;
MariaDB [hellodb]> CREATE TABLE `users` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(30) DEFAULT NULL, `email` varchar(30) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `UNIQUE_email` (`email`) );
MariaDB [hellodb]> INSERT INTO users (name, email) VALUES ('John Doe', 'john@example.com');
MariaDB [hellodb]> INSERT INTO users (name, email) VALUES ('Jane Doe', 'jane@example.com');
步骤2.构建您的配置文件
使用nano创建一个/var/www/hello/config.php文件,如下所示:
<?php
$db_host = 'localhost';
$db_name = 'hellodb';
$db_user = 'hellouser';
$db_pass = 'hellouserpass';
步骤3.构建您的功能文件
使用nano创建一个/var/www/hello/functions.php文件,如下所示:
<?php
include 'config.php';
function function_response($response_string) : int {
$response_value = intval(substr($response_string,0,3));
return $response_value;
}
function function_payload($response_string) : string {
$response_value = substr($response_string,4);
return $response_value;
}
function user_get_name($useremail) : string {
global $db_host, $db_user, $db_pass, $db_name;
try{
$db_conn = new PDO('mysql:host='.$db_host.';dbname='.$db_name, $db_user, $db_pass);
$db_qry = "SELECT count(name) FROM users WHERE email = '" . $useremail ."'";
$db_act = $db_conn->prepare($db_qry);
$db_act->execute();
$db_rows = $db_act->fetchColumn();
if ($db_rows>0) {
$retval="";
$db_qry = "SELECT name FROM users WHERE email = '" . $useremail . "'";
$db_act = $db_conn->prepare($db_qry);
$db_act->execute();
$rows = $db_act->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as $row) {
if ($retval=="") {
$retval = $row['name'];
} else {
$retval = $retval . ", " . $row['name'];
}
}
$db_conn = null;
return "200 " . $retval;
} else {
$db_conn = null;
return "404 Not Found";
}
}
catch(PDOException $e) {
error_log('PDOException - ' . $e->getMessage(),0);
$db_conn->close();
return "500 Database Unavailable";
}
}
步骤4.构建您的Web服务服务器文件
使用nano创建一个/var/www/hello/hello_server.php文件,如下所示:
<?php
include 'config.php';
require_once 'functions.php';
if(!extension_loaded("soap")){
dl("php_soap.dll");
}
ini_set("soap.wsdl_cache_enabled","0");
$server = new SoapServer("hello.wsdl");
function doGetUserName($emailaddr){
return function_payload(user_get_name($emailaddr));
}
$server->addFunction("doGetUserName");
$server->handle();
?>
步骤5.构建Web应用程序用户界面
使用nano创建一个/var/www/hello/hello_client.php文件,如下所示:
<?php
include 'config.php';
require_once 'functions.php';
$emailaddr = $_POST["useremail"];
if (!empty($emailaddr)) {
try{
$sClient = new SoapClient('https://siptesting.net/hello/hello.wsdl');
$response = $sClient->doGetUserName($emailaddr);
echo "<h1>This is the Full Name of the user registered with email address: ".$emailaddr.":</h1><br>";
echo $response;
} catch(SoapFault $e){
var_dump($e);
}
} else {
echo "<form action=\"/hello/hello_client.php\" method=\"post\">";
echo "Enter User Email to search for: <input type=\"text\" name=\"useremail\"><br>";
echo "<input type=\"submit\">";
echo "</form>";
echo "<br><br><a href=\"/\">Home Page</a>";
}
?>
步骤6.创建您的Web服务定义文件
使用nano创建一个/var/www/hello/hello.wsdl文件,如下所示:
<?xml version="1.0"?>
<definitions name="HelloWorld" targetNamespace='urn:HelloWorld' xmlns:tns="urn:HelloWorld" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:Hello">
<xsd:element name="getUserName" type="xsd:string" />
<xsd:element name="getUserNameResponse" type="xsd:string" />
</xsd:schema>
</types>
<message name="doGetUserName">
<part name="emailAddress" type="tns:getUserName" />
</message>
<message name="doGetUserNameResponse">
<part name="return" type="tns:getUserNameResponse" />
</message>
<portType name="HelloPort">
<operation name="doGetUserName">
<input message="tns:doGetUserName" />
<output message="tns:doGetUserNameResponse" />
</operation>
</portType>
<binding name="HelloBinding" type="tns:HelloPort">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="doGetUserName">
<soap:operation soapAction="urn:GetUserNameAction" />
<input>
<soap:body use="encoded" namespace="urn:Hello" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</input>
<output>
<soap:body use="encoded" namespace="urn:Hello" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</output>
</operation>
</binding>
<service name="HelloService">
<port name="HelloPort" binding="tns:HelloBinding">
<soap:address location="https://siptesting.net/hello/hello_server.php" />
</port>
</service>
</definitions>
阶段2.扫描您的Web服务
在此示例中,我们的Web服务定义在siptesting.net/hello/hello.wsdl。要使用Acunetix扫描Web服务,请执行以下操作:
- 使用URL siptesting.net/hello/hello.wsdl 创建一个新目标
- 将PHP AcuSensor部署到您的Web服务
- 对您的Web服务启动全面扫描,然后等待其完成
阶段3.确定Web服务中的漏洞
检查目标漏洞列表
我们将集中讨论此练习的跨站点脚本和SQL注入漏洞。
项目1.跨站点脚本编写
- Acunetix显示了攻击详细信息–输入字段中填充了潜在的恶意脚本。
- Acunetix在“HTTP响应”部分中突出显示了漏洞利用脚本代码。这意味着没有正确验证插入到输入字段中的数据。
项目2. SQL注入
- Acunetix会显示攻击详细信息-输入字段中填充了可能会诱使数据库显示不希望显示的数据的潜在恶意数据,从而使恶意黑客可以提出其他请求以可能检索大量数据。
- Acunetix在HTTP响应部分中突出显示了漏洞利用数据-它能够检索多个用户的名称。意味着没有正确验证插入到输入字段中的数据。
阶段4.解决漏洞
项目1.跨站点脚本编写
此漏洞的根本原因在于hello_client.php文件中的以下行:
echo "<h1>This is the Full Name of the user registered with email address: ".$emailaddr.":</h1><br>";
该$ EMAILADDR包含用户输入区的未经验证的内容,这些内容将被发送回浏览器,这意味着浏览器可以被强制执行脚本代码。我们需要先清理此变量的内容,然后再将其发送到浏览器,并按如下方式调整代码:
echo "<h1>This is the Full Name of the user registered with email address: ".htmlspecialchars($emailaddr).":</h1><br>";
项目2. SQL注入
快速浏览hello_server.php文件可以发现根本原因。使用字符串连接构建查询:
$db_qry = "SELECT count(name) FROM users WHERE email = '" . $useremail ."'";
$db_act = $db_conn->prepare($db_qry);
$db_act->execute();
$db_qry = "SELECT name FROM users WHERE email = '" . $useremail . "'";
$db_act = $db_conn->prepare($db_qry);
$db_act->execute();
在$ EMAILADDR变量被简单地连接到查询字符串,没有任何验证。我们需要通过参数化查询字符串来调整代码,以确保传递的所有参数均正确地转义并用引号封装,从而阻止进一步的利用。新的代码片段如下所示:
$db_qry = "SELECT count(name) FROM users WHERE email = :useremail";
$db_act = $db_conn->prepare($db_qry);
$db_act->bindParam(':useremail', $useremail);
$db_act->execute();
$db_qry = "SELECT name FROM users WHERE email = :useremail";
$db_act = $db_conn->prepare($db_qry);
$db_act->bindParam(':useremail', $useremail);
$db_act->execute();
注意:有关更多信息,请阅读有关防止PHP中的SQL注入的文章。
阶段5.重新扫描以确认解决方案
我们可以转到扫描漏洞列表,然后选择我们已调整的漏洞。
现在,单击“重新测试”按钮-这将创建一个新的扫描,以再次测试所选的漏洞。结果表明,我们已经成功解决了这些漏洞。
