CTF-快速反弹 POST 请求

CTF-Web中一类题的小结

Posted by BlackDn on March 11, 2020

“原本无意穿堂风,偏偏孤倨引山洪。”

快速反弹 POST 请求

前言

好久没写东西了…一放假整个人就懒了 XD
我知道很久没写,但没想到竟然有两个月了…
在做 CTF 的时候遇到了这类题:获取有效期很短的 key 值,需要将经过处理后的 key 值快速 POST 给服务器。
往往这时候需要写脚本进行处理上传。因为有效期往往在一秒左右,在这一秒内手动处理再 POST 实在不是人类所为。
同时,python 提供了第三方库 Requests,更够很好的处理此类大部分问题。因为是第三方库记得先安装。

Requests 常用基本方法

发送请求后,我们可以理解为得到一个响应对象
这个对象有很多属性,每个属性都是这个响应的一些数据
比如响应的请求头(*.request.headers)、响应头(*.headers)、响应内容(*.text)等

GET 请求

# get()发送GET请求,参数为url字符串
r = requests.get('https://...')

GET 请求参数作为查询字符串附加在 URL 末尾,可以通过 requests.get() 方法中的 params 参数完成,注意是 dict 类型

# 构建URL:https://github.com/?username=ciphersaw&id=1
args = {'username': 'ciphersaw', 'id': 1}
r = requests.get('https://github.com/', params = args)

这样构建出来的 r 的 url 的值(r.url)就为“https://github.com/?username=ciphersaw&id=1”

POST 请求

# post()发送post请求,参数为url字符串
r = requests.post('https://...')

和 GET 类似,借助 requests.post() 方法中的 data 参数完成,也是 dict 类型

# 构建URL:https://github.com/?username=ciphersaw&id=1
args = {'username': 'ciphersaw', 'id': 1}
r = requests.post('https://github.com/', data = args)

查看请求头

利用上述方法进行请求后,请求的响应会存储在 r 中,我们可以利用其查看请求头

# 查看请求的请求头
r.request.headers
# 查看请求头某一属性
r.request.headers['Accept-Encoding']

查看响应头

响应头直接用 headers 即可,不需要添加 request

# 查看响应头
r.headers
# 查看响应头的某一属性
r.headers['Status']

查看响应内容

相应内容存储在 text 中

# 查看响应内容
r.text

如果想传递自定义 Cookie 到服务器,可以使用 cookies 参数,也是 dict 类型

mycookie = {'userid': '123456'}
r = requests.post('https://github.com/', cookies = mycookie)

然后查看 r.request.headers 可以发现其中的 Cookie 已经是我们设定的

会话对象 Session()

Session 是存储在服务器上的相关用户信息,用于在有效期内保持客户端与服务器之间的状态

# 创建Session()
s = requests.Session()

同一个 Session 发出的所有请求都保持着相同的 Cookie,因此可以利用 Session 进行请求的发送

r = s.get('https://...')
r = s.post('https://...')

例题:BugKu-秋名山老司机

题目要求在 2s 内计算老司机的车速,实际上是要我们 2s 内 post 上一个式子最后的值,数据挺大的,几亿几亿的加减乘法。因此手动算完再 post 是不实际的。
于是就选择编写脚本运算后 post 传值

解题思路

大致分为三步骤:发出请求、处理数据、再次请求并返回数据
由于数据是随机生成的计算题,我们采用正则表达式获取
将结果 post 上后打印返回的文本,猜想其中应该会有 flag

然而实际还要注意一点,第二次请求的时候会刷新,导致产生新的计算题,因此一开始需要利用 Session 记录。第二次请求利用 Session 进行 post 请求。

代码解析

import requests    # 第三方库
import re    # 内库,正则表达式用

url = 'http://120.24.86.145:8002/qiumingshan/'    # 题目的url
s = requests.Session()    # 记录Session
source = s.get(url)    # 第一次请求, 返回的结果在source中

# re库中的方法。source.text中储存返回的文本,在其中检索计算式。
# group()提取分组,group()同group(0),表示匹配的全部内容
expression = re.search(r'(\d+[+\-*])+(\d+)', source.text).group()

result = eval(expression)    # 利用eval()将提取出的字符串进行计算得到结果,存储在result中
post = {'value': result}    # 构造post的数据,变量名为value,值为result
print(s.post(url, data = post).text)    # 利用Session进行第二次请求,并带上post数据。将返回的响应内容打印,查看flag

要注意的是,脚本并非每次执行都能成功得到 flag
可能由于请求响应延迟、网络链接、生成的计算式过长等原因导致时间太长而不满组题目要求,多试几次就好

其他

PyCharm 中导入第三方库

虽然在本地装入了第三方库,但我在 PyCharm 中不能直接引用,需要将其导入编译器。
在 Settings -> Project -> Project Interpreter 中,点击“+”,搜索想要的第三方库并且导入就好了。

参考

详解 CTF Web 中的快速反弹 POST 请求